Online browser + post detail: SPA talks to e621 directly

Backend:
- POST /api/files/lookup/ reports which MD5s are already in the library

Frontend:
- e621 client extended with post/tag/favorite types and helpers: post
  search, post detail, batch posts by id, tag autocomplete, toggle
  favorite
- /online: tag search with autocomplete, post grid with rating colors
  and in-library badges, numbered pagination, page tag cloud, blacklist
  panel and filtered counts from /users/me.json, anonymous hint
- /online/view/🆔 media viewer (sample or original, video support),
  taxonomy-colored tags by category, specs sheet, favorite/unfavorite,
  description, sources, pools and parent/children thumbnails
- Shared CollapsibleSidebar extracted from the library page; Online
  added to the nav, command palette and sidebar toggle
This commit is contained in:
2026-09-17 09:00:17 -05:00
parent b6409523e6
commit 04448bf615
14 changed files with 1273 additions and 41 deletions
+9 -1
View File
@@ -10,10 +10,12 @@ import { api } from "@/lib/api";
import { cn } from "@/lib/cn";
import type { SystemStatus } from "@/lib/types";
import { useAuth } from "@/store/auth";
import { useE621 } from "@/store/e621";
import { useUi } from "@/store/ui";
const navItems = [
{ to: "/", label: "Library" },
{ to: "/online", label: "Online" },
{ to: "/upload", label: "Upload" },
];
@@ -21,9 +23,14 @@ export function AppShell() {
const user = useAuth((state) => state.user);
const logout = useAuth((state) => state.logout);
const toggleSidebar = useUi((state) => state.toggleSidebar);
const loadE621 = useE621((state) => state.load);
const location = useLocation();
const [paletteOpen, setPaletteOpen] = useState(false);
useEffect(() => {
void loadE621();
}, [loadE621]);
const statusQuery = useQuery({
queryKey: ["status"],
queryFn: () => api<SystemStatus>("/api/status/"),
@@ -53,7 +60,8 @@ export function AppShell() {
return () => window.removeEventListener("keydown", handleKeyDown);
}, [toggleSidebar]);
const showSidebarToggle = location.pathname === "/";
const showSidebarToggle =
location.pathname === "/" || location.pathname === "/online";
return (
<div className="flex min-h-screen flex-col">