v3: added site-wide categories, added admin category management, various visual fixes
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 2m52s
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 2m52s
This commit is contained in:
46
src/App.tsx
46
src/App.tsx
@@ -1,5 +1,11 @@
|
||||
import { lazy, Suspense } from "react";
|
||||
import { BrowserRouter, Navigate, Route, Routes } from "react-router";
|
||||
import {
|
||||
BrowserRouter,
|
||||
Navigate,
|
||||
Route,
|
||||
Routes,
|
||||
useParams,
|
||||
} from "react-router";
|
||||
|
||||
import { RestrictedGuest } from "./pages/RestrictedGuest.tsx";
|
||||
import { RestrictedLoggedIn } from "./pages/RestrictedLoggedIn.tsx";
|
||||
@@ -10,6 +16,7 @@ import { AuthProvider } from "./contexts/AuthProvider.tsx";
|
||||
import { PlayerProvider } from "./contexts/PlayerProvider.tsx";
|
||||
import { WSProvider } from "./contexts/WSProvider.tsx";
|
||||
import { FollowProvider } from "./contexts/FollowProvider.tsx";
|
||||
import { CategoriesProvider } from "./contexts/CategoriesProvider.tsx";
|
||||
import { ThemeProvider } from "./contexts/ThemeProvider.tsx";
|
||||
import { GlobalPlayer } from "./components/GlobalPlayer.tsx";
|
||||
import { DumpFab } from "./components/DumpFab.tsx";
|
||||
@@ -69,12 +76,29 @@ const NotFound = lazy(() =>
|
||||
import("./pages/NotFound.tsx").then((m) => ({ default: m.NotFound }))
|
||||
);
|
||||
|
||||
function IndexRedirect() {
|
||||
// Default feed tab for the current viewer ("followed" needs a session).
|
||||
function useResolvedDefaultTab() {
|
||||
const { user } = useAuth();
|
||||
const [preferredTab] = useDefaultFeedTab();
|
||||
// "followed" requires a session, so fall back to "hot" for guests.
|
||||
const tab = preferredTab === "followed" && !user ? "hot" : preferredTab;
|
||||
return <Navigate to={`/~/${tab}`} replace />;
|
||||
return preferredTab === "followed" && !user ? "hot" : preferredTab;
|
||||
}
|
||||
|
||||
function IndexRedirect() {
|
||||
return <Navigate to={`/~/${useResolvedDefaultTab()}`} replace />;
|
||||
}
|
||||
|
||||
// Bare `/<slug>` lands on that category's default feed tab.
|
||||
function CategoryRedirect() {
|
||||
const { categorySlug } = useParams();
|
||||
return <Navigate to={`/${categorySlug}/${useResolvedDefaultTab()}`} replace />;
|
||||
}
|
||||
|
||||
// Both `/~/:feedTab` (all) and `/:categorySlug/:feedTab` render the same feed.
|
||||
// Keying by scope remounts the feed when switching categories so it refetches,
|
||||
// while switching tabs within a scope keeps it mounted (client-side re-sort).
|
||||
function ScopedIndex() {
|
||||
const { categorySlug } = useParams();
|
||||
return <Index key={categorySlug ?? "~"} categorySlug={categorySlug} />;
|
||||
}
|
||||
|
||||
function AppRoutes() {
|
||||
@@ -83,7 +107,7 @@ function AppRoutes() {
|
||||
<Suspense>
|
||||
<Routes>
|
||||
<Route path="/" element={<IndexRedirect />} />
|
||||
<Route path="/~/:feedTab" element={<Index />} />
|
||||
<Route path="/~/:feedTab" element={<ScopedIndex />} />
|
||||
<Route path="/dumps/:selectedDump" element={<Dump />} />
|
||||
<Route
|
||||
path="/dumps/:selectedDump/edit"
|
||||
@@ -132,6 +156,8 @@ function AppRoutes() {
|
||||
</RestrictedLoggedIn>
|
||||
}
|
||||
/>
|
||||
<Route path="/:categorySlug/:feedTab" element={<ScopedIndex />} />
|
||||
<Route path="/:categorySlug" element={<CategoryRedirect />} />
|
||||
<Route path="*" element={<NotFound />} />
|
||||
</Routes>
|
||||
</Suspense>
|
||||
@@ -147,9 +173,11 @@ function App() {
|
||||
<PlayerProvider>
|
||||
<WSProvider>
|
||||
<FollowProvider>
|
||||
<BrowserRouter>
|
||||
<AppRoutes />
|
||||
</BrowserRouter>
|
||||
<CategoriesProvider>
|
||||
<BrowserRouter>
|
||||
<AppRoutes />
|
||||
</BrowserRouter>
|
||||
</CategoriesProvider>
|
||||
</FollowProvider>
|
||||
</WSProvider>
|
||||
<GlobalPlayer />
|
||||
|
||||
Reference in New Issue
Block a user