feat(ui): E31 S4a — rail rows are links, the channel page opens on unwatched, users and audit tidied
- Nav rail page rows are real links (/?page=<id>): a middle-click or Ctrl-click opens the page in a new tab; a plain click stays in-app. - A fresh channel page shows the unwatched videos; a picked watch state is a remembered preference (channelShow). - Users: the role, suspend and delete move into the row's one menu (the "…", right-click, Shift+F10); locked ones keep their reason. - Audit log: back-to-back successful runs of one job fold into one row that opens to the earlier ones; a failed run reads in the danger colour. - DESIGN.md decision log: the E31 picks.
This commit is contained in:
@@ -29,6 +29,9 @@ import ChannelAboutContent from "./ChannelAbout";
|
||||
import { PageToolbar } from "./ui/PageShell";
|
||||
import { PageToolbarSlot } from "./ui/pageToolbarSlot";
|
||||
import { useFeedFilters } from "./feedFiltersContext";
|
||||
import { SHOW_IDS } from "./feedFiltersInit";
|
||||
import { usePref } from "../lib/usePref";
|
||||
import { LS } from "../lib/storage";
|
||||
import { useConfirm } from "./confirmContext";
|
||||
import { notify } from "../lib/notifications";
|
||||
import { notifyYouTubeActionError } from "../lib/youtubeErrors";
|
||||
@@ -260,7 +263,13 @@ export default function ChannelPage({
|
||||
|
||||
// Channel-scoped feed: the whole catalog filtered to this channel (scope=all + source=all so
|
||||
// the explored, per-user-private videos show — the backend gates them to this explorer).
|
||||
const [filters, setFilters] = useState<FeedFilters>(() => ({
|
||||
// The watch state is the one filter a channel page remembers (the owner, E31): a fresh page shows
|
||||
// what is still unwatched, and a change sticks — across channels, reloads and devices.
|
||||
const [show, setShow] = usePref<string>("channelShow", "unwatched", {
|
||||
localKey: LS.channelShow,
|
||||
parse: (v) => (typeof v === "string" && SHOW_IDS.includes(v) ? v : "unwatched"),
|
||||
});
|
||||
const [ownFilters, setOwnFilters] = useState<FeedFilters>(() => ({
|
||||
tags: [],
|
||||
tagModes: DEFAULT_TAG_MODES,
|
||||
q: "",
|
||||
@@ -271,9 +280,14 @@ export default function ChannelPage({
|
||||
includeNormal: globalFilters.includeNormal,
|
||||
includeShorts: globalFilters.includeShorts,
|
||||
includeLive: globalFilters.includeLive,
|
||||
show: "all",
|
||||
show: "unwatched",
|
||||
channelIds: [channelId],
|
||||
}));
|
||||
const filters: FeedFilters = { ...ownFilters, show };
|
||||
const setFilters = (next: FeedFilters) => {
|
||||
if (next.show !== show) setShow(next.show);
|
||||
setOwnFilters(next);
|
||||
};
|
||||
|
||||
const name = ch?.title ?? initialName ?? channelId;
|
||||
const ytUrl = channelYouTubeUrl(channelId, ch?.handle);
|
||||
|
||||
Reference in New Issue
Block a user