fix: address reader-UI feedback (shorts, search, tags, login, UX)
- Shorts: confirm via youtube.com/shorts/<id> probe (SOCS cookie bypasses the
consent redirect) instead of a 60s heuristic; concurrent probing, shorts_probed
flag, scheduled refinement (migration 0005)
- Search: match title + channel name only (descriptions caused noisy results)
- Faceted tag filtering: AND across categories (language AND topic narrows),
OR within a category; any/all toggle applies to topics
- Language detection: majority vote over individual titles (fixes misdetections
like multipoleguy -> English; drops bogus Polish/Romanian)
- Login: drop forced consent so returning sign-in is quick (select_account)
- Feed cards: clickable channel name (opens channel), persistent saved badge,
undo toast on hide, Hidden view to restore; tag chips show counts in tooltip
2026-06-11 03:07:49 +02:00
|
|
|
import { useSyncExternalStore } from "react";
|
2026-06-11 19:26:34 +02:00
|
|
|
import {
|
|
|
|
|
AlertCircle,
|
|
|
|
|
AlertTriangle,
|
|
|
|
|
CheckCircle2,
|
|
|
|
|
Info,
|
|
|
|
|
X,
|
|
|
|
|
XCircle,
|
|
|
|
|
} from "lucide-react";
|
|
|
|
|
import {
|
|
|
|
|
dismiss,
|
|
|
|
|
getActiveToasts,
|
|
|
|
|
subscribe,
|
|
|
|
|
type NotifLevel,
|
|
|
|
|
} from "../lib/notifications";
|
|
|
|
|
|
|
|
|
|
export const LEVEL_STYLE: Record<
|
|
|
|
|
NotifLevel,
|
|
|
|
|
{ icon: typeof Info; color: string }
|
|
|
|
|
> = {
|
|
|
|
|
info: { icon: Info, color: "text-accent" },
|
|
|
|
|
success: { icon: CheckCircle2, color: "text-emerald-400" },
|
|
|
|
|
warning: { icon: AlertTriangle, color: "text-amber-400" },
|
|
|
|
|
error: { icon: AlertCircle, color: "text-red-400" },
|
|
|
|
|
fatal: { icon: XCircle, color: "text-red-500" },
|
|
|
|
|
};
|
fix: address reader-UI feedback (shorts, search, tags, login, UX)
- Shorts: confirm via youtube.com/shorts/<id> probe (SOCS cookie bypasses the
consent redirect) instead of a 60s heuristic; concurrent probing, shorts_probed
flag, scheduled refinement (migration 0005)
- Search: match title + channel name only (descriptions caused noisy results)
- Faceted tag filtering: AND across categories (language AND topic narrows),
OR within a category; any/all toggle applies to topics
- Language detection: majority vote over individual titles (fixes misdetections
like multipoleguy -> English; drops bogus Polish/Romanian)
- Login: drop forced consent so returning sign-in is quick (select_account)
- Feed cards: clickable channel name (opens channel), persistent saved badge,
undo toast on hide, Hidden view to restore; tag chips show counts in tooltip
2026-06-11 03:07:49 +02:00
|
|
|
|
|
|
|
|
export default function Toaster() {
|
2026-06-11 19:26:34 +02:00
|
|
|
const toasts = useSyncExternalStore(subscribe, getActiveToasts, getActiveToasts);
|
|
|
|
|
|
fix: address reader-UI feedback (shorts, search, tags, login, UX)
- Shorts: confirm via youtube.com/shorts/<id> probe (SOCS cookie bypasses the
consent redirect) instead of a 60s heuristic; concurrent probing, shorts_probed
flag, scheduled refinement (migration 0005)
- Search: match title + channel name only (descriptions caused noisy results)
- Faceted tag filtering: AND across categories (language AND topic narrows),
OR within a category; any/all toggle applies to topics
- Language detection: majority vote over individual titles (fixes misdetections
like multipoleguy -> English; drops bogus Polish/Romanian)
- Login: drop forced consent so returning sign-in is quick (select_account)
- Feed cards: clickable channel name (opens channel), persistent saved badge,
undo toast on hide, Hidden view to restore; tag chips show counts in tooltip
2026-06-11 03:07:49 +02:00
|
|
|
return (
|
2026-06-11 19:26:34 +02:00
|
|
|
<div className="fixed top-4 right-4 z-50 flex flex-col gap-2 w-80 max-w-[calc(100vw-2rem)]">
|
|
|
|
|
{toasts.map((t) => {
|
|
|
|
|
const { icon: Icon, color } = LEVEL_STYLE[t.level];
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
key={t.id}
|
|
|
|
|
className="bg-surface border border-border rounded-xl shadow-2xl px-3 py-3 flex items-start gap-3 animate-[fadeIn_0.15s_ease]"
|
|
|
|
|
>
|
|
|
|
|
<Icon className={`w-5 h-5 shrink-0 mt-0.5 ${color}`} />
|
|
|
|
|
<div className="min-w-0 flex-1">
|
|
|
|
|
{t.title && <div className="text-sm font-semibold">{t.title}</div>}
|
|
|
|
|
<div className="text-sm break-words">{t.message}</div>
|
|
|
|
|
{t.action && (
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => {
|
|
|
|
|
t.action!.onClick();
|
|
|
|
|
dismiss(t.id);
|
|
|
|
|
}}
|
|
|
|
|
className="mt-1 text-accent text-sm font-semibold hover:underline"
|
|
|
|
|
>
|
|
|
|
|
{t.action.label}
|
|
|
|
|
</button>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
fix: address reader-UI feedback (shorts, search, tags, login, UX)
- Shorts: confirm via youtube.com/shorts/<id> probe (SOCS cookie bypasses the
consent redirect) instead of a 60s heuristic; concurrent probing, shorts_probed
flag, scheduled refinement (migration 0005)
- Search: match title + channel name only (descriptions caused noisy results)
- Faceted tag filtering: AND across categories (language AND topic narrows),
OR within a category; any/all toggle applies to topics
- Language detection: majority vote over individual titles (fixes misdetections
like multipoleguy -> English; drops bogus Polish/Romanian)
- Login: drop forced consent so returning sign-in is quick (select_account)
- Feed cards: clickable channel name (opens channel), persistent saved badge,
undo toast on hide, Hidden view to restore; tag chips show counts in tooltip
2026-06-11 03:07:49 +02:00
|
|
|
<button
|
2026-06-11 19:26:34 +02:00
|
|
|
onClick={() => dismiss(t.id)}
|
|
|
|
|
className="shrink-0 text-muted hover:text-fg"
|
|
|
|
|
title="Dismiss"
|
fix: address reader-UI feedback (shorts, search, tags, login, UX)
- Shorts: confirm via youtube.com/shorts/<id> probe (SOCS cookie bypasses the
consent redirect) instead of a 60s heuristic; concurrent probing, shorts_probed
flag, scheduled refinement (migration 0005)
- Search: match title + channel name only (descriptions caused noisy results)
- Faceted tag filtering: AND across categories (language AND topic narrows),
OR within a category; any/all toggle applies to topics
- Language detection: majority vote over individual titles (fixes misdetections
like multipoleguy -> English; drops bogus Polish/Romanian)
- Login: drop forced consent so returning sign-in is quick (select_account)
- Feed cards: clickable channel name (opens channel), persistent saved badge,
undo toast on hide, Hidden view to restore; tag chips show counts in tooltip
2026-06-11 03:07:49 +02:00
|
|
|
>
|
2026-06-11 19:26:34 +02:00
|
|
|
<X className="w-4 h-4" />
|
fix: address reader-UI feedback (shorts, search, tags, login, UX)
- Shorts: confirm via youtube.com/shorts/<id> probe (SOCS cookie bypasses the
consent redirect) instead of a 60s heuristic; concurrent probing, shorts_probed
flag, scheduled refinement (migration 0005)
- Search: match title + channel name only (descriptions caused noisy results)
- Faceted tag filtering: AND across categories (language AND topic narrows),
OR within a category; any/all toggle applies to topics
- Language detection: majority vote over individual titles (fixes misdetections
like multipoleguy -> English; drops bogus Polish/Romanian)
- Login: drop forced consent so returning sign-in is quick (select_account)
- Feed cards: clickable channel name (opens channel), persistent saved badge,
undo toast on hide, Hidden view to restore; tag chips show counts in tooltip
2026-06-11 03:07:49 +02:00
|
|
|
</button>
|
2026-06-11 19:26:34 +02:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
})}
|
fix: address reader-UI feedback (shorts, search, tags, login, UX)
- Shorts: confirm via youtube.com/shorts/<id> probe (SOCS cookie bypasses the
consent redirect) instead of a 60s heuristic; concurrent probing, shorts_probed
flag, scheduled refinement (migration 0005)
- Search: match title + channel name only (descriptions caused noisy results)
- Faceted tag filtering: AND across categories (language AND topic narrows),
OR within a category; any/all toggle applies to topics
- Language detection: majority vote over individual titles (fixes misdetections
like multipoleguy -> English; drops bogus Polish/Romanian)
- Login: drop forced consent so returning sign-in is quick (select_account)
- Feed cards: clickable channel name (opens channel), persistent saved badge,
undo toast on hide, Hidden view to restore; tag chips show counts in tooltip
2026-06-11 03:07:49 +02:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|