v4: the followed feed's two views are pages — "From people" and "From playlists" on a feed's "follow" tab were a state of the page, which a reload, Back or a shared link lost, while a profile's same split is /@name/follow/playlists. They are now /follow and /follow/playlists, and /music/follow/playlists in a category, feedPath taking the view as userPath does (FOLLOW_VIEWS); picking a category keeps it. Their dumps come from GET /api/dumps?follow=users|playlists, signed in, which the feed's word for it names, instead of GET /api/me/feed?from=; an unknown category is a 404 there, as on the rest of the feed, rather than an empty list.
A feed's tab, as a profile's, a search's or the community page's, now takes the place of the current history entry, since it is a view of the same page; picking a category, another page, still adds one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
32
src/App.tsx
32
src/App.tsx
@@ -5,8 +5,9 @@
|
||||
* more segment, and a default view the bare path, with no redirect.
|
||||
*
|
||||
* - `/` is the feed of every dump on the viewer's default tab, and `/hot`,
|
||||
* `/new`, `/journal` and `/follow` its tabs (`Index`). `/?share_url=` opens
|
||||
* the create form on a shared link.
|
||||
* `/new`, `/journal` and `/follow` its tabs (`Index`), `/follow/playlists`
|
||||
* the dumps of the playlists followed. `/?share_url=` opens the create form
|
||||
* on a shared link.
|
||||
* - `/search` and `/search/:searchTab` are the search results (`Search`).
|
||||
* - `/register` and `/login` sign up and sign in (`UserRegister`,
|
||||
* `UserLogin`), signed out only, `/login?next=` coming back to a page.
|
||||
@@ -28,7 +29,7 @@
|
||||
* signed in only), and their playlists at `playlists/:slug`
|
||||
* (`PlaylistDetail`).
|
||||
* - `/:categorySlug` and `/:categorySlug/:feedTab` are a dump category's feed
|
||||
* (`Index`).
|
||||
* (`Index`), with its `/follow/playlists` too.
|
||||
* - Any other path is `NotFound`.
|
||||
*
|
||||
* The pages not marked are open to anyone. Every page is loaded with its
|
||||
@@ -49,7 +50,12 @@ import {
|
||||
|
||||
import { RestrictedGuest } from "./pages/RestrictedGuest.tsx";
|
||||
import { RestrictedLoggedIn } from "./pages/RestrictedLoggedIn.tsx";
|
||||
import { FEED_TABS, type FeedTab } from "../shared/paths.ts";
|
||||
import {
|
||||
FEED_TABS,
|
||||
type FeedTab,
|
||||
FOLLOW_VIEWS,
|
||||
type FollowView,
|
||||
} from "../shared/paths.ts";
|
||||
|
||||
import { AuthProvider } from "./contexts/auth/AuthProvider.tsx";
|
||||
import { PlayerProvider } from "./contexts/player/PlayerProvider.tsx";
|
||||
@@ -132,18 +138,21 @@ const NotFound = lazy(() =>
|
||||
/**
|
||||
* Renders a feed, of every dump or of `categorySlug`'s, on the tab the path's
|
||||
* segment after the scope names, or the viewer's default one on the bare
|
||||
* path. Every feed path renders it at the same place in the tree, and the key
|
||||
* keeps `Index` mounted on a change of tab, which sorts on the client, and
|
||||
* remounts it on a change of category, so that it refetches.
|
||||
* path, and the `follow` tab on the view the next segment names. Every feed
|
||||
* path renders it at the same place in the tree, and the key keeps `Index`
|
||||
* mounted on a change of tab, which sorts on the client, and remounts it on a
|
||||
* change of category, so that it refetches.
|
||||
*/
|
||||
function Feed({ categorySlug }: { categorySlug?: string }) {
|
||||
const { pathname } = useLocation();
|
||||
const segments = pathname.split("/").filter(Boolean);
|
||||
const rest = segments.slice(categorySlug ? 1 : 0);
|
||||
const feedTab = rest[0];
|
||||
const [feedTab, view, ...more] = segments.slice(categorySlug ? 1 : 0);
|
||||
if (
|
||||
rest.length > 1 ||
|
||||
(feedTab && !(FEED_TABS as readonly string[]).includes(feedTab))
|
||||
more.length > 0 ||
|
||||
(feedTab && !(FEED_TABS as readonly string[]).includes(feedTab)) ||
|
||||
(view !== undefined &&
|
||||
(feedTab !== "follow" || view === FOLLOW_VIEWS[0] ||
|
||||
!(FOLLOW_VIEWS as readonly string[]).includes(view)))
|
||||
) {
|
||||
return <NotFound />;
|
||||
}
|
||||
@@ -152,6 +161,7 @@ function Feed({ categorySlug }: { categorySlug?: string }) {
|
||||
key={categorySlug ?? ""}
|
||||
categorySlug={categorySlug}
|
||||
feedTab={feedTab as FeedTab | undefined}
|
||||
followView={view as FollowView | undefined}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user