feat: uniform control height, chrome auto-hide, streaming quality
Every control in the app now shares one height (CONTROL_H), with width still growing to fit its label. The player transport is larger, Back is an icon, and the footer buttons match the prev/next size. Player chrome — transport and edge arrows — fades after 2.6s of inactivity and never hides while paused. The title-bar strip collapses in macOS window fullscreen, where the traffic lights are gone and it was just a blank white bar. Streaming quality is now selectable alongside download quality. A cap is applied by rewriting YouTube's HLS master playlist down to the best variant at or below the chosen height, keeping its audio group. That playlist is served from a small loopback HTTP server: Safari's native HLS is backed by AVFoundation, which cannot read blob: or custom-scheme URLs, so a Blob URL silently fails to play. Settings closes with an icon button and its selects match the shared control height.
This commit is contained in:
+12
-15
@@ -1,4 +1,4 @@
|
||||
import { INPUT, Segmented } from "./ui";
|
||||
import { CONTROL_H, ICON_BTN, INPUT, Segmented } from "./ui";
|
||||
|
||||
export type ViewMode = "list" | "grid";
|
||||
|
||||
@@ -39,7 +39,7 @@ function Toggle({
|
||||
title={title}
|
||||
disabled={disabled}
|
||||
className={
|
||||
"cursor-pointer whitespace-nowrap rounded-lg border px-2.5 py-1.5 text-[11px] " +
|
||||
`inline-flex ${CONTROL_H} cursor-pointer items-center whitespace-nowrap rounded-lg border px-2.5 text-[12px] ` +
|
||||
"font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-40 " +
|
||||
(active
|
||||
? "border-sky-500 bg-sky-500 text-white hover:bg-sky-400"
|
||||
@@ -73,10 +73,9 @@ export default function TopBar({
|
||||
onClick={onShowSidebar}
|
||||
title="Show subscriptions"
|
||||
aria-label="Show subscriptions"
|
||||
className="grid size-[30px] shrink-0 cursor-pointer place-items-center rounded-lg
|
||||
border border-slate-300 text-slate-500 hover:border-sky-500
|
||||
hover:text-sky-600 dark:border-slate-700 dark:text-slate-400
|
||||
dark:hover:border-sky-500 dark:hover:text-sky-400"
|
||||
className={`${ICON_BTN} border border-slate-300 text-slate-500 hover:border-sky-500
|
||||
hover:text-sky-600 dark:border-slate-700 dark:text-slate-400
|
||||
dark:hover:border-sky-500 dark:hover:text-sky-400`}
|
||||
>
|
||||
<svg viewBox="0 0 24 24" className="size-4" fill="none" stroke="currentColor" strokeWidth="1.8">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M4 6h16M4 12h16M4 18h16" />
|
||||
@@ -87,7 +86,7 @@ export default function TopBar({
|
||||
value={search}
|
||||
onChange={(e) => onSearch(e.target.value)}
|
||||
placeholder="Search videos and channels"
|
||||
className={`${INPUT} min-w-72 max-w-sm flex-1 py-1.5`}
|
||||
className={`${INPUT} min-w-72 max-w-sm flex-1`}
|
||||
/>
|
||||
|
||||
<span className="font-mono text-[11px] tabular-nums text-slate-400 dark:text-slate-500">
|
||||
@@ -125,11 +124,11 @@ export default function TopBar({
|
||||
? "Offline mode is forced on — click to go back online"
|
||||
: "Simulate being offline"
|
||||
}
|
||||
className="flex cursor-pointer items-center gap-1.5 whitespace-nowrap rounded-lg border
|
||||
border-slate-300 px-2.5 py-1.5 text-[11px] font-medium text-slate-500
|
||||
hover:border-sky-500 hover:text-sky-600
|
||||
dark:border-slate-700 dark:text-slate-400 dark:hover:border-sky-500
|
||||
dark:hover:text-sky-400"
|
||||
className={`inline-flex ${CONTROL_H} cursor-pointer items-center gap-1.5 whitespace-nowrap
|
||||
rounded-lg border border-slate-300 px-2.5 text-[12px] font-medium text-slate-500
|
||||
hover:border-sky-500 hover:text-sky-600
|
||||
dark:border-slate-700 dark:text-slate-400 dark:hover:border-sky-500
|
||||
dark:hover:text-sky-400`}
|
||||
>
|
||||
<span
|
||||
className={`size-1.5 rounded-full ${online ? "bg-sky-500" : "bg-amber-500"}`}
|
||||
@@ -146,9 +145,7 @@ export default function TopBar({
|
||||
: "Refreshing needs a connection"
|
||||
}
|
||||
aria-label="Refresh"
|
||||
className="grid size-[30px] shrink-0 cursor-pointer place-items-center rounded-lg
|
||||
bg-sky-500 text-white hover:bg-sky-400 disabled:cursor-not-allowed
|
||||
disabled:opacity-40">
|
||||
className={`${ICON_BTN} bg-sky-500 text-white hover:bg-sky-400`}>
|
||||
<svg viewBox="0 0 24 24" className={`size-4 ${refreshing ? "animate-spin" : ""}`}
|
||||
fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round"
|
||||
|
||||
Reference in New Issue
Block a user