feat(ui): liquid-glass design system, settings polish, hints, notif fixes
- Add a theme-aware glass surface system (.glass/.glass-card + ambient backdrop, performance-mode opt-out) and apply it across panels, popovers, toasts, cards, sidebar widgets, channel rows, video cards and login. - SettingsPanel: slide in/out animation, glass styling, wrapping pill tabs (no horizontal scrollbar) with a prominent active state. - Notifications: auto-dismiss can be switched off (stays until closed); the test notification now also triggers the alert sound; resume a suspended AudioContext. - Add an app-wide, toggleable hint/tooltip system (lib/hints + Tooltip) and wire hints across the settings and channel-manager surfaces; persisted per account.
This commit is contained in:
parent
a8822d3935
commit
002579e5e5
13 changed files with 388 additions and 102 deletions
|
|
@ -12,6 +12,7 @@ import {
|
|||
} from "lucide-react";
|
||||
import { api, type ManagedChannel, type Tag } from "../lib/api";
|
||||
import { notify } from "../lib/notifications";
|
||||
import Tooltip from "./Tooltip";
|
||||
|
||||
export default function Channels({
|
||||
onViewChannel,
|
||||
|
|
@ -76,11 +77,23 @@ export default function Channels({
|
|||
{/* Per-user sync status */}
|
||||
{s && (
|
||||
<div className="flex flex-wrap items-center gap-x-5 gap-y-1 text-sm text-muted mb-4">
|
||||
<Stat label="Channels" value={s.channels_total} />
|
||||
<Stat label="Recent synced" value={`${s.channels_recent_synced}/${s.channels_total}`} />
|
||||
<Stat label="Full history" value={`${s.channels_deep_done}/${s.channels_total}`} />
|
||||
<Stat label="My videos" value={s.my_videos.toLocaleString()} />
|
||||
<Stat label="Quota left" value={s.quota_remaining_today.toLocaleString()} />
|
||||
<Stat label="Channels" value={s.channels_total} hint="Channels you're subscribed to." />
|
||||
<Stat
|
||||
label="Recent synced"
|
||||
value={`${s.channels_recent_synced}/${s.channels_total}`}
|
||||
hint="Channels whose recent uploads are in the local DB and show in your feed."
|
||||
/>
|
||||
<Stat
|
||||
label="Full history"
|
||||
value={`${s.channels_deep_done}/${s.channels_total}`}
|
||||
hint="Channels whose entire back-catalog is fetched. The rest backfill gradually."
|
||||
/>
|
||||
<Stat label="My videos" value={s.my_videos.toLocaleString()} hint="Total videos available across your channels." />
|
||||
<Stat
|
||||
label="Quota left"
|
||||
value={s.quota_remaining_today.toLocaleString()}
|
||||
hint="Shared YouTube API budget left today (resets midnight US Pacific)."
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
@ -166,23 +179,35 @@ export default function Channels({
|
|||
);
|
||||
}
|
||||
|
||||
function Stat({ label, value }: { label: string; value: string | number }) {
|
||||
function Stat({
|
||||
label,
|
||||
value,
|
||||
hint,
|
||||
}: {
|
||||
label: string;
|
||||
value: string | number;
|
||||
hint?: string;
|
||||
}) {
|
||||
return (
|
||||
<span>
|
||||
<span className="text-fg font-semibold">{value}</span> {label}
|
||||
</span>
|
||||
<Tooltip hint={hint ?? ""}>
|
||||
<span className={hint ? "cursor-help" : ""}>
|
||||
<span className="text-fg font-semibold">{value}</span> {label}
|
||||
</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
function SyncBadge({ ok, label }: { ok: boolean; label: string }) {
|
||||
function SyncBadge({ ok, label, hint }: { ok: boolean; label: string; hint?: string }) {
|
||||
return (
|
||||
<span
|
||||
className={`text-[10px] px-1.5 py-0.5 rounded-full border ${
|
||||
ok ? "border-accent/40 text-accent" : "border-border text-muted"
|
||||
}`}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
<Tooltip hint={hint ?? ""}>
|
||||
<span
|
||||
className={`text-[10px] px-1.5 py-0.5 rounded-full border ${
|
||||
ok ? "border-accent/40 text-accent" : "border-border text-muted"
|
||||
}`}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -203,7 +228,7 @@ function ChannelRow({
|
|||
}) {
|
||||
return (
|
||||
<div
|
||||
className={`flex items-center gap-3 p-2.5 rounded-xl border border-border bg-card/30 ${
|
||||
className={`glass-card glass-hover flex items-center gap-3 p-2.5 rounded-xl transition ${
|
||||
c.hidden ? "opacity-60" : ""
|
||||
}`}
|
||||
>
|
||||
|
|
@ -232,8 +257,16 @@ function ChannelRow({
|
|||
{c.subscriber_count != null && <span>· {c.subscriber_count.toLocaleString()} subs</span>}
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-1 mt-1">
|
||||
<SyncBadge ok={c.recent_synced} label="recent" />
|
||||
<SyncBadge ok={c.backfill_done} label="full" />
|
||||
<SyncBadge
|
||||
ok={c.recent_synced}
|
||||
label="recent"
|
||||
hint={c.recent_synced ? "Recent uploads synced." : "Recent uploads not fetched yet."}
|
||||
/>
|
||||
<SyncBadge
|
||||
ok={c.backfill_done}
|
||||
label="full"
|
||||
hint={c.backfill_done ? "Full history fetched." : "Only recent videos so far; full history pending."}
|
||||
/>
|
||||
{userTags.map((t) => {
|
||||
const on = c.tag_ids.includes(t.id);
|
||||
return (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue