feat(tags): tag UX overhaul + per-card video reset
- Channel-row tags show only what's attached; a '+' opens a per-channel picker. Clicking a tag filters the feed by it; a 'Your tags' sidebar widget makes that filter visible/clearable. - Tag manager dialog (add/rename/delete; delete only confirms when the tag is in use), reachable from the Channel manager and the feed sidebar; hovering a tag's count lists its channels, each a link that focuses it in the Channel manager (DataTable gains an external filter input). - Video cards get a reset action that clears all watch state (incl. an in-progress position). - api.req() now raises the error dialog on 5xx and 400/409/422 with the server's reason.
This commit is contained in:
parent
14b8eb6084
commit
d33a109ea2
22 changed files with 445 additions and 49 deletions
|
|
@ -66,6 +66,7 @@ export default function DataTable<T>({
|
|||
rowClassName,
|
||||
controlsPosition = "bottom",
|
||||
controlsLeading,
|
||||
externalFilter,
|
||||
}: {
|
||||
rows: T[];
|
||||
columns: Column<T>[];
|
||||
|
|
@ -77,6 +78,9 @@ export default function DataTable<T>({
|
|||
rowClassName?: (row: T) => string;
|
||||
controlsPosition?: "top" | "bottom" | "both";
|
||||
controlsLeading?: ReactNode;
|
||||
// Set a column's filter from outside (e.g. "focus this channel" deep-links here). Applied
|
||||
// whenever its value changes; the user can still clear it from the header afterwards.
|
||||
externalFilter?: { key: string; value: string } | null;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const initial = loadPersist(persistKey);
|
||||
|
|
@ -93,6 +97,13 @@ export default function DataTable<T>({
|
|||
if (persistKey) localStorage.setItem(persistKey, JSON.stringify({ sort, filters, page, size }));
|
||||
}, [persistKey, sort, filters, page, size]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!externalFilter) return;
|
||||
setFilters((f) => ({ ...f, [externalFilter.key]: externalFilter.value }));
|
||||
setPage(0);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [externalFilter?.key, externalFilter?.value]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!openFilter) return;
|
||||
function onDown(e: MouseEvent) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue