fix(frontend): the layer gates cover what the move left outside them, and each page keeps its own logic
Gates the folder move had narrowed or left open: the MenuCheck contract scans the whole app again (it saw only components/); local/layers refuses an import of an entry (main.tsx, the /watch page) from any layer, and reads a backtick import() as the path it is; the /watch contract forbids the shell, the modules and the features by folder (its one path to App had gone stale); chunkGuard's own test gets the vitest focus/skip rules. The root tests' exemption from local/layers is in the gate register, with its three imports. Placement: Plex's chip builder moves into lib beside the feed's, the folder names into features/folders, and three files only one page uses into that page. ui/FilterRail takes its reset from useRail instead of a page id. The channel page reads the feed's view and builds "Show in feed" itself, and the feed's scroll key is the feed's hook, so the shell holds no feed logic. The floating header re-measures when one page's pills replace another's in the same commit (the claim count stayed equal, so only the observer caught it). A Plex view applied and edited now stays across a visit to another page, as the feed's does: pinned by a test. docs/development.md says what a page with a rail adds in lib.
This commit is contained in:
@@ -11,13 +11,7 @@ import { useEntryParams } from "./useEntryParams";
|
||||
import { useAccessRequestsNudge } from "./useAccessRequestsNudge";
|
||||
import { useVerifyEntry } from "../lib/useVerifyEntry";
|
||||
import { useNavigation, useNavigationActions } from "../features/navigation/navigationContext";
|
||||
import {
|
||||
useFeedFilters,
|
||||
useFeedFiltersActions,
|
||||
useFeedView,
|
||||
useFeedViewActions,
|
||||
ChannelPage,
|
||||
} from "../modules/feed";
|
||||
import { useFeedScrollKey, ChannelPage } from "../modules/feed";
|
||||
import { moduleDef, pageTitleKey } from "../features/navigation/moduleRegistry";
|
||||
import { LoadingState } from "../components/ui/QueryState";
|
||||
// Persistent shell — always mounted, so eagerly imported.
|
||||
@@ -51,22 +45,16 @@ const ReleaseNotes = lazy(() => import("./ReleaseNotes"));
|
||||
|
||||
export default function App() {
|
||||
const { t, i18n } = useTranslation();
|
||||
const { page, channelView, ytSearch } = useNavigation();
|
||||
const { page, channelView } = useNavigation();
|
||||
const { setPage } = useNavigationActions();
|
||||
// An emailed verification link is confirmed HERE, above the signed-in/signed-out branch below, so
|
||||
// it works in a browser that already holds a session. It used to be handled inside Welcome, which
|
||||
// that branch never renders when signed in — the token was silently dropped. Signed out, the
|
||||
// outcome goes to the auth card's banners; signed in, to the top-of-app bar.
|
||||
const verifyEntry = useVerifyEntry();
|
||||
// The global feed filters live in FeedFiltersProvider (per-account persistence + the account-load
|
||||
// effect + share-link capture all moved there). App reads them to hand to <Feed> and to the
|
||||
// handlers that mutate the feed view (onShowInFeed, tag-click, the feed scrollKey).
|
||||
const filters = useFeedFilters();
|
||||
const { setFilters } = useFeedFiltersActions();
|
||||
// The feed's view mode (card/row/tile density) lives in FeedViewProvider — server-synced, shared
|
||||
// by the feed page and the channel page. App reads it only to hand to <Feed>/<ChannelPage>.
|
||||
const view = useFeedView();
|
||||
const { setView } = useFeedViewActions();
|
||||
// The feed page restores its scroll by its own key (its filters, the live search); read always,
|
||||
// used only while the feed is the page.
|
||||
const feedScrollKey = useFeedScrollKey();
|
||||
const queryClient = useQueryClient();
|
||||
const [aboutOpen, setAboutOpen] = useState(false);
|
||||
const [notesOpen, setNotesOpen] = useState(false);
|
||||
@@ -119,16 +107,9 @@ export default function App() {
|
||||
// preload failed), and like every loading state it stays invisible for a load that is quick anyway.
|
||||
const pageFallback = <LoadingState className="flex-1 justify-center" />;
|
||||
|
||||
// Scroll restore/reset key for the shared normal-page scroller (see PageScroller): the same
|
||||
// page/feed-filters returns you to where you were (bug 1); a changed feed filter is a new key, so
|
||||
// the fresh result set starts at the top (bug 3). `q` is normalised out so typing in the search
|
||||
// box doesn't reset the scroll on every keystroke; the live-YouTube sub-view gets its own key.
|
||||
const normalScrollKey =
|
||||
page !== "feed"
|
||||
? `page:${page}`
|
||||
: ytSearch != null
|
||||
? `yt:${ytSearch}`
|
||||
: `feed:${JSON.stringify({ ...filters, q: "" })}`;
|
||||
// Scroll restore/reset key for the shared normal-page scroller (see PageScroller): the same page
|
||||
// returns you to where you were; the feed keys it by its filters (useFeedScrollKey).
|
||||
const normalScrollKey = page === "feed" ? feedScrollKey : `page:${page}`;
|
||||
|
||||
// The module registry drives the render from `page` alone — no per-page chrome conditionals. A page
|
||||
// the account can't reach never gets here: the navigation state already moved it to the feed
|
||||
@@ -168,23 +149,6 @@ export default function App() {
|
||||
channelId={channelView.id}
|
||||
initialName={channelView.name}
|
||||
me={me!}
|
||||
view={view}
|
||||
setView={setView}
|
||||
onShowInFeed={() => {
|
||||
// Keep the rest of the feed's filters — the point is "this channel, the way I
|
||||
// normally read": unwatched, my tags, my date window.
|
||||
// ADD to the picked set, don't replace it: channels OR together now, so arriving
|
||||
// from a second channel page should widen the feed, not silently drop the first.
|
||||
// Deduped — clicking it again for a channel already picked is a no-op.
|
||||
setFilters({
|
||||
...filters,
|
||||
channelIds: [...new Set([...filters.channelIds, channelView.id])],
|
||||
});
|
||||
// setPage already leaves an open channel page and pushes a clean history entry.
|
||||
// Calling closeChannel() first ran history.back(), whose popstate landed AFTER this
|
||||
// and restored whatever page the channel had been opened from.
|
||||
setPage("feed");
|
||||
}}
|
||||
/>
|
||||
</Suspense>
|
||||
</PageShell>
|
||||
|
||||
Reference in New Issue
Block a user