Add a Pools browser backed by e621's /pools endpoint

- /pools: search by name, category/active filters, sort options and
  pagination per the OpenAPI spec, with covers taken from each pool's
  first post in one batched post call; blacklisted covers fall back to a
  placeholder and deleted pools get an archive marker.
- /pools/<id>: DText description, post grid kept in the pool's own order
  with chunked loading, in-library badges, a blacklist reveal toggle and
  a Follow pool button wired into the follows API.
- e621 client gains fetchPools/fetchPool; Pools nav entry added.
This commit is contained in:
2026-09-17 14:26:20 -05:00
parent c396c368dc
commit 0a7dc5a991
7 changed files with 817 additions and 0 deletions
+4
View File
@@ -20,6 +20,8 @@ import FollowedPage from "@/features/follows/FollowedPage";
import LibraryPage from "@/features/library/LibraryPage";
import Md5Redirect from "@/features/library/Md5Redirect";
import OnlinePage from "@/features/online/OnlinePage";
import PoolDetailPage from "@/features/pools/PoolDetailPage";
import PoolsPage from "@/features/pools/PoolsPage";
import UploadPage from "@/features/upload/UploadPage";
import UsersPage from "@/features/users/UsersPage";
import { isAgeVerified, markAgeVerified } from "@/lib/age";
@@ -71,6 +73,8 @@ export default function App() {
<Route path="/view/:md5" element={<Md5Redirect />} />
<Route path="/online" element={<OnlinePage />} />
<Route path="/online/view/:postId" element={<PostRedirect />} />
<Route path="/pools" element={<PoolsPage />} />
<Route path="/pools/:poolId" element={<PoolDetailPage />} />
<Route
path="/followed"
element={