feat: custom transport bar, live refresh, collapsible sidebar
Replace WebKit's native video controls with our own. WebKit puts fullscreen, Picture-in-Picture and volume as overlay buttons in the video's top corners with no way to move them; owning the bar is the only way to get every control into one strip along the bottom. Right-click on the player is suppressed — its menu acted on a video the app does not control. One spinner now covers both waits: resolving the stream URL and buffering it. It no longer sticks after a resume-seek, which fires 'waiting' after 'playing'. Also: Open on YouTube and a new Download are real buttons in the player; refresh is a compact icon; Settings is a cog; the subscription sidebar collapses and reappears on a left-edge hover; the feed auto-refreshes every 10 minutes while online, skipped while the player is open; the title-bar strip takes the panel colour, since it sits above panels rather than the page; and downloaded-only, hide-Shorts and the sidebar state are remembered between launches.
This commit is contained in:
@@ -8,10 +8,14 @@ interface Props {
|
||||
onOpenSettings: () => void;
|
||||
totalVideos: number;
|
||||
totalDownloaded: number;
|
||||
onHide: () => void;
|
||||
/** True when revealed by hover over the left edge rather than pinned open. */
|
||||
floating?: boolean;
|
||||
}
|
||||
|
||||
export default function Sidebar({
|
||||
channels, activeChannel, onSelect, onOpenSettings, totalVideos, totalDownloaded,
|
||||
onHide, floating,
|
||||
}: Props) {
|
||||
const row =
|
||||
"flex w-full cursor-pointer items-center justify-between gap-2 rounded-lg px-2 py-1.5 " +
|
||||
@@ -22,9 +26,14 @@ export default function Sidebar({
|
||||
|
||||
return (
|
||||
<aside
|
||||
className="flex max-h-[45vh] w-full shrink-0 flex-col overflow-hidden border-b
|
||||
border-slate-300 bg-white lg:h-full lg:max-h-none lg:w-[280px]
|
||||
lg:border-b-0 lg:border-r dark:border-slate-800 dark:bg-slate-900"
|
||||
className={
|
||||
"flex flex-col overflow-hidden border-slate-300 bg-white dark:border-slate-800 " +
|
||||
"dark:bg-slate-900 " +
|
||||
(floating
|
||||
? "absolute inset-y-0 left-0 z-30 w-[280px] border-r shadow-2xl"
|
||||
: "max-h-[45vh] w-full shrink-0 border-b lg:h-full lg:max-h-none lg:w-[280px] " +
|
||||
"lg:border-b-0 lg:border-r")
|
||||
}
|
||||
>
|
||||
<header
|
||||
className="sticky top-0 z-20 flex items-center justify-between gap-2 border-b
|
||||
@@ -35,9 +44,29 @@ export default function Sidebar({
|
||||
<span aria-hidden className="text-sky-500">✈</span>
|
||||
FlightTube
|
||||
</span>
|
||||
<button onClick={onOpenSettings} className={`${BTN_CHROME} cursor-pointer`}>
|
||||
Settings
|
||||
</button>
|
||||
<div className="flex shrink-0 items-center gap-1">
|
||||
<button
|
||||
onClick={onOpenSettings}
|
||||
title="Settings"
|
||||
aria-label="Settings"
|
||||
className={`${BTN_CHROME} grid size-7 cursor-pointer place-items-center`}
|
||||
>
|
||||
<svg viewBox="0 0 24 24" className="size-4" fill="none" stroke="currentColor" strokeWidth="1.8">
|
||||
<circle cx="12" cy="12" r="3.2" />
|
||||
<path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 11-2.83 2.83l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 11-4 0v-.09A1.65 1.65 0 008 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 11-2.83-2.83l.06-.06A1.65 1.65 0 004.6 15a1.65 1.65 0 00-1.51-1H3a2 2 0 110-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 112.83-2.83l.06.06A1.65 1.65 0 009 4.6a1.65 1.65 0 001-1.51V3a2 2 0 114 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 112.83 2.83l-.06.06A1.65 1.65 0 0019.4 9c.14.34.4.62.73.79.24.13.51.2.78.21H21a2 2 0 110 4h-.09c-.7.01-1.33.43-1.51 1z" />
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
onClick={onHide}
|
||||
title="Hide subscriptions"
|
||||
aria-label="Hide subscriptions"
|
||||
className={`${BTN_CHROME} grid size-7 cursor-pointer place-items-center`}
|
||||
>
|
||||
<svg viewBox="0 0 24 24" className="size-4" fill="none" stroke="currentColor" strokeWidth="1.8">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15 6l-6 6 6 6" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<nav className="min-h-0 flex-1 overflow-y-auto px-2 py-3">
|
||||
|
||||
Reference in New Issue
Block a user