From 99236a36f87595a20a889abee8130456462b849c Mon Sep 17 00:00:00 2001 From: Drew Haven Date: Sun, 1 Jun 2025 12:34:02 -0700 Subject: [PATCH] Moves routes inside an _app for the header and builds a print route --- package.json | 2 +- src/components/documents/DocumentPrintRow.tsx | 64 ++++ .../documents/location/LocationPrintRow.tsx | 13 + .../documents/monsters/MonsterPrintRow.tsx | 8 + src/components/documents/npc/NpcPrintRow.tsx | 13 + .../documents/scene/ScenePrintRow.tsx | 8 + .../documents/secret/SecretPrintRow.tsx | 26 ++ .../documents/session/SessionPrintRow.tsx | 10 + .../documents/treasure/TreasurePrintRow.tsx | 26 ++ src/config.ts | 3 +- src/routeTree.gen.ts | 336 +++++++++++------- src/routes/__root.tsx | 69 +--- src/routes/_app.tsx | 77 ++++ src/routes/{ => _app}/_authenticated.tsx | 2 +- .../_authenticated/campaigns.$campaignId.tsx | 2 +- .../_authenticated/campaigns.index.tsx | 2 +- .../_authenticated/document.$documentId.tsx | 2 +- src/routes/{ => _app}/about.tsx | 2 +- src/routes/{ => _app}/index.tsx | 2 +- src/routes/{ => _app}/login.tsx | 2 +- ...henticated.document_.$documentId.print.tsx | 74 ++++ 21 files changed, 532 insertions(+), 211 deletions(-) create mode 100644 src/components/documents/DocumentPrintRow.tsx create mode 100644 src/components/documents/location/LocationPrintRow.tsx create mode 100644 src/components/documents/monsters/MonsterPrintRow.tsx create mode 100644 src/components/documents/npc/NpcPrintRow.tsx create mode 100644 src/components/documents/scene/ScenePrintRow.tsx create mode 100644 src/components/documents/secret/SecretPrintRow.tsx create mode 100644 src/components/documents/session/SessionPrintRow.tsx create mode 100644 src/components/documents/treasure/TreasurePrintRow.tsx create mode 100644 src/routes/_app.tsx rename src/routes/{ => _app}/_authenticated.tsx (79%) rename src/routes/{ => _app}/_authenticated/campaigns.$campaignId.tsx (96%) rename src/routes/{ => _app}/_authenticated/campaigns.index.tsx (95%) rename src/routes/{ => _app}/_authenticated/document.$documentId.tsx (95%) rename src/routes/{ => _app}/about.tsx (74%) rename src/routes/{ => _app}/index.tsx (80%) rename src/routes/{ => _app}/login.tsx (99%) create mode 100644 src/routes/_app_._authenticated.document_.$documentId.print.tsx diff --git a/package.json b/package.json index 12ad67f..95df9f2 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "type": "module", "scripts": { "dev": "mprocs \"npm run start\" \"pocketbase serve\"", - "start": "vite --port 3000", + "start": "VITE_POCKETBASE_URL=http://localhost:8090 vite --port 3000", "build": "vite build && tsc", "serve": "vite preview", "test": "vitest run", diff --git a/src/components/documents/DocumentPrintRow.tsx b/src/components/documents/DocumentPrintRow.tsx new file mode 100644 index 0000000..123fbb5 --- /dev/null +++ b/src/components/documents/DocumentPrintRow.tsx @@ -0,0 +1,64 @@ +// DocumentRow.tsx +// Generic row component for displaying any document type. +import { + isLocation, + isMonster, + isNpc, + isScene, + isSecret, + isSession, + isTreasure, + type Document, +} from "@/lib/types"; +import { LocationPrintRow } from "./location/LocationPrintRow"; +import { MonsterPrintRow } from "./monsters/MonsterPrintRow"; +import { TreasurePrintRow } from "./treasure/TreasurePrintRow"; +import { SecretPrintRow } from "./secret/SecretPrintRow"; +import { NpcPrintRow } from "./npc/NpcPrintRow"; +import { ScenePrintRow } from "./scene/ScenePrintRow"; +import { SessionPrintRow } from "./session/SessionPrintRow"; + +/** + * Renders a row for any document type. Prioritizes Session, then Secret, then falls back to ID and creation time. + * If rendering a SecretRow, uses the provided session prop if available. + */ +export const DocumentPrintRow = ({ document }: { document: Document }) => { + if (isLocation(document)) { + return ; + } + + if (isMonster(document)) { + return ; + } + + if (isNpc(document)) { + return ; + } + + if (isSession(document)) { + return ; + } + + if (isSecret(document)) { + return ; + } + + if (isScene(document)) { + return ; + } + + if (isTreasure(document)) { + return ; + } + + // Fallback: show ID and creation time + return ( +
+
+ Unrecognized Document +
+
ID: {document.id}
+
Created: {document.created}
+
+ ); +}; diff --git a/src/components/documents/location/LocationPrintRow.tsx b/src/components/documents/location/LocationPrintRow.tsx new file mode 100644 index 0000000..00c1694 --- /dev/null +++ b/src/components/documents/location/LocationPrintRow.tsx @@ -0,0 +1,13 @@ +import type { Location } from "@/lib/types"; + +/** + * Renders an print-friendly location row + */ +export const LocationPrintRow = ({ location }: { location: Location }) => { + return ( +
  • +

    {location.data.location.name}

    +

    {location.data.location.description}

    +
  • + ); +}; diff --git a/src/components/documents/monsters/MonsterPrintRow.tsx b/src/components/documents/monsters/MonsterPrintRow.tsx new file mode 100644 index 0000000..0b4fd30 --- /dev/null +++ b/src/components/documents/monsters/MonsterPrintRow.tsx @@ -0,0 +1,8 @@ +import type { Monster } from "@/lib/types"; + +/** + * Renders an editable monster row + */ +export const MonsterPrintRow = ({ monster }: { monster: Monster }) => { + return
  • {monster.data.monster.name}
  • ; +}; diff --git a/src/components/documents/npc/NpcPrintRow.tsx b/src/components/documents/npc/NpcPrintRow.tsx new file mode 100644 index 0000000..de9366c --- /dev/null +++ b/src/components/documents/npc/NpcPrintRow.tsx @@ -0,0 +1,13 @@ +import type { Npc } from "@/lib/types"; + +/** + * Renders an editable npc row + */ +export const NpcPrintRow = ({ npc }: { npc: Npc }) => { + return ( +
  • +

    {npc.data.npc.name}

    +

    {npc.data.npc.description}

    +
  • + ); +}; diff --git a/src/components/documents/scene/ScenePrintRow.tsx b/src/components/documents/scene/ScenePrintRow.tsx new file mode 100644 index 0000000..de5b162 --- /dev/null +++ b/src/components/documents/scene/ScenePrintRow.tsx @@ -0,0 +1,8 @@ +import type { Scene } from "@/lib/types"; + +/** + * Renders an editable scene row + */ +export const ScenePrintRow = ({ scene }: { scene: Scene }) => { + return
  • {scene.data.scene.text}
  • ; +}; diff --git a/src/components/documents/secret/SecretPrintRow.tsx b/src/components/documents/secret/SecretPrintRow.tsx new file mode 100644 index 0000000..3035f4d --- /dev/null +++ b/src/components/documents/secret/SecretPrintRow.tsx @@ -0,0 +1,26 @@ +// SecretRow.tsx +// Displays a single secret with discovered checkbox and text. +import type { Secret, Session } from "@/lib/types"; +import { pb } from "@/lib/pocketbase"; +import { useState } from "react"; + +/** + * Renders a secret row with a discovered checkbox and secret text. + * Handles updating the discovered state and discoveredIn relationship. + */ +export const SecretPrintRow = ({ secret }: { secret: Secret }) => { + return ( +
  • + + + {(secret.data as any)?.secret?.text || ( + (No secret text) + )} + +
  • + ); +}; diff --git a/src/components/documents/session/SessionPrintRow.tsx b/src/components/documents/session/SessionPrintRow.tsx new file mode 100644 index 0000000..3d48a07 --- /dev/null +++ b/src/components/documents/session/SessionPrintRow.tsx @@ -0,0 +1,10 @@ +import type { Session } from "@/lib/types"; + +export const SessionPrintRow = ({ session }: { session: Session }) => { + return ( +
    +

    StrongStart

    +
    {session.data.session.strongStart}
    +
    + ); +}; diff --git a/src/components/documents/treasure/TreasurePrintRow.tsx b/src/components/documents/treasure/TreasurePrintRow.tsx new file mode 100644 index 0000000..70a3d71 --- /dev/null +++ b/src/components/documents/treasure/TreasurePrintRow.tsx @@ -0,0 +1,26 @@ +// TreasureRow.tsx +// Displays a single treasure with discovered checkbox and text. +import type { Treasure, Session } from "@/lib/types"; +import { pb } from "@/lib/pocketbase"; +import { useState } from "react"; + +/** + * Renders a treasure row with a discovered checkbox and treasure text. + * Handles updating the discovered state and discoveredIn relationship. + */ +export const TreasurePrintRow = ({ treasure }: { treasure: Treasure }) => { + return ( +
  • + + + {(treasure.data as any)?.treasure?.text || ( + (No treasure text) + )} + +
  • + ); +}; diff --git a/src/config.ts b/src/config.ts index 132eeef..7d6dd19 100644 --- a/src/config.ts +++ b/src/config.ts @@ -3,4 +3,5 @@ * * This includes endpoints and other environment-specific settings. */ -export const POCKETBASE_URL: string = import.meta.env.VITE_POCKETBASE_URL || "http://127.0.0.1:8090"; // Update as needed for deployment +export const POCKETBASE_URL: string = + import.meta.env.VITE_POCKETBASE_URL || "/"; // Update as needed for deployment diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index a17a742..f35f166 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -11,208 +11,258 @@ // Import Routes import { Route as rootRoute } from './routes/__root' -import { Route as LoginImport } from './routes/login' -import { Route as AboutImport } from './routes/about' -import { Route as AuthenticatedImport } from './routes/_authenticated' -import { Route as IndexImport } from './routes/index' -import { Route as AuthenticatedCampaignsIndexImport } from './routes/_authenticated/campaigns.index' -import { Route as AuthenticatedDocumentDocumentIdImport } from './routes/_authenticated/document.$documentId' -import { Route as AuthenticatedCampaignsCampaignIdImport } from './routes/_authenticated/campaigns.$campaignId' +import { Route as AppImport } from './routes/_app' +import { Route as AppIndexImport } from './routes/_app/index' +import { Route as AppLoginImport } from './routes/_app/login' +import { Route as AppAboutImport } from './routes/_app/about' +import { Route as AppAuthenticatedImport } from './routes/_app/_authenticated' +import { Route as AppAuthenticatedCampaignsIndexImport } from './routes/_app/_authenticated/campaigns.index' +import { Route as AppAuthenticatedDocumentDocumentIdImport } from './routes/_app/_authenticated/document.$documentId' +import { Route as AppAuthenticatedCampaignsCampaignIdImport } from './routes/_app/_authenticated/campaigns.$campaignId' +import { Route as AppauthenticatedDocumentDocumentIdPrintImport } from './routes/_app_._authenticated.document_.$documentId.print' // Create/Update Routes -const LoginRoute = LoginImport.update({ - id: '/login', - path: '/login', +const AppRoute = AppImport.update({ + id: '/_app', getParentRoute: () => rootRoute, } as any) -const AboutRoute = AboutImport.update({ - id: '/about', - path: '/about', - getParentRoute: () => rootRoute, -} as any) - -const AuthenticatedRoute = AuthenticatedImport.update({ - id: '/_authenticated', - getParentRoute: () => rootRoute, -} as any) - -const IndexRoute = IndexImport.update({ +const AppIndexRoute = AppIndexImport.update({ id: '/', path: '/', - getParentRoute: () => rootRoute, + getParentRoute: () => AppRoute, } as any) -const AuthenticatedCampaignsIndexRoute = - AuthenticatedCampaignsIndexImport.update({ +const AppLoginRoute = AppLoginImport.update({ + id: '/login', + path: '/login', + getParentRoute: () => AppRoute, +} as any) + +const AppAboutRoute = AppAboutImport.update({ + id: '/about', + path: '/about', + getParentRoute: () => AppRoute, +} as any) + +const AppAuthenticatedRoute = AppAuthenticatedImport.update({ + id: '/_authenticated', + getParentRoute: () => AppRoute, +} as any) + +const AppAuthenticatedCampaignsIndexRoute = + AppAuthenticatedCampaignsIndexImport.update({ id: '/campaigns/', path: '/campaigns/', - getParentRoute: () => AuthenticatedRoute, + getParentRoute: () => AppAuthenticatedRoute, } as any) -const AuthenticatedDocumentDocumentIdRoute = - AuthenticatedDocumentDocumentIdImport.update({ +const AppAuthenticatedDocumentDocumentIdRoute = + AppAuthenticatedDocumentDocumentIdImport.update({ id: '/document/$documentId', path: '/document/$documentId', - getParentRoute: () => AuthenticatedRoute, + getParentRoute: () => AppAuthenticatedRoute, } as any) -const AuthenticatedCampaignsCampaignIdRoute = - AuthenticatedCampaignsCampaignIdImport.update({ +const AppAuthenticatedCampaignsCampaignIdRoute = + AppAuthenticatedCampaignsCampaignIdImport.update({ id: '/campaigns/$campaignId', path: '/campaigns/$campaignId', - getParentRoute: () => AuthenticatedRoute, + getParentRoute: () => AppAuthenticatedRoute, + } as any) + +const AppauthenticatedDocumentDocumentIdPrintRoute = + AppauthenticatedDocumentDocumentIdPrintImport.update({ + id: '/_app_/_authenticated/document_/$documentId/print', + path: '/document/$documentId/print', + getParentRoute: () => rootRoute, } as any) // Populate the FileRoutesByPath interface declare module '@tanstack/react-router' { interface FileRoutesByPath { - '/': { - id: '/' - path: '/' - fullPath: '/' - preLoaderRoute: typeof IndexImport - parentRoute: typeof rootRoute - } - '/_authenticated': { - id: '/_authenticated' + '/_app': { + id: '/_app' path: '' fullPath: '' - preLoaderRoute: typeof AuthenticatedImport + preLoaderRoute: typeof AppImport parentRoute: typeof rootRoute } - '/about': { - id: '/about' + '/_app/_authenticated': { + id: '/_app/_authenticated' + path: '' + fullPath: '' + preLoaderRoute: typeof AppAuthenticatedImport + parentRoute: typeof AppImport + } + '/_app/about': { + id: '/_app/about' path: '/about' fullPath: '/about' - preLoaderRoute: typeof AboutImport - parentRoute: typeof rootRoute + preLoaderRoute: typeof AppAboutImport + parentRoute: typeof AppImport } - '/login': { - id: '/login' + '/_app/login': { + id: '/_app/login' path: '/login' fullPath: '/login' - preLoaderRoute: typeof LoginImport - parentRoute: typeof rootRoute + preLoaderRoute: typeof AppLoginImport + parentRoute: typeof AppImport } - '/_authenticated/campaigns/$campaignId': { - id: '/_authenticated/campaigns/$campaignId' + '/_app/': { + id: '/_app/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof AppIndexImport + parentRoute: typeof AppImport + } + '/_app/_authenticated/campaigns/$campaignId': { + id: '/_app/_authenticated/campaigns/$campaignId' path: '/campaigns/$campaignId' fullPath: '/campaigns/$campaignId' - preLoaderRoute: typeof AuthenticatedCampaignsCampaignIdImport - parentRoute: typeof AuthenticatedImport + preLoaderRoute: typeof AppAuthenticatedCampaignsCampaignIdImport + parentRoute: typeof AppAuthenticatedImport } - '/_authenticated/document/$documentId': { - id: '/_authenticated/document/$documentId' + '/_app/_authenticated/document/$documentId': { + id: '/_app/_authenticated/document/$documentId' path: '/document/$documentId' fullPath: '/document/$documentId' - preLoaderRoute: typeof AuthenticatedDocumentDocumentIdImport - parentRoute: typeof AuthenticatedImport + preLoaderRoute: typeof AppAuthenticatedDocumentDocumentIdImport + parentRoute: typeof AppAuthenticatedImport } - '/_authenticated/campaigns/': { - id: '/_authenticated/campaigns/' + '/_app/_authenticated/campaigns/': { + id: '/_app/_authenticated/campaigns/' path: '/campaigns' fullPath: '/campaigns' - preLoaderRoute: typeof AuthenticatedCampaignsIndexImport - parentRoute: typeof AuthenticatedImport + preLoaderRoute: typeof AppAuthenticatedCampaignsIndexImport + parentRoute: typeof AppAuthenticatedImport + } + '/_app_/_authenticated/document_/$documentId/print': { + id: '/_app_/_authenticated/document_/$documentId/print' + path: '/document/$documentId/print' + fullPath: '/document/$documentId/print' + preLoaderRoute: typeof AppauthenticatedDocumentDocumentIdPrintImport + parentRoute: typeof rootRoute } } } // Create and export the route tree -interface AuthenticatedRouteChildren { - AuthenticatedCampaignsCampaignIdRoute: typeof AuthenticatedCampaignsCampaignIdRoute - AuthenticatedDocumentDocumentIdRoute: typeof AuthenticatedDocumentDocumentIdRoute - AuthenticatedCampaignsIndexRoute: typeof AuthenticatedCampaignsIndexRoute +interface AppAuthenticatedRouteChildren { + AppAuthenticatedCampaignsCampaignIdRoute: typeof AppAuthenticatedCampaignsCampaignIdRoute + AppAuthenticatedDocumentDocumentIdRoute: typeof AppAuthenticatedDocumentDocumentIdRoute + AppAuthenticatedCampaignsIndexRoute: typeof AppAuthenticatedCampaignsIndexRoute } -const AuthenticatedRouteChildren: AuthenticatedRouteChildren = { - AuthenticatedCampaignsCampaignIdRoute: AuthenticatedCampaignsCampaignIdRoute, - AuthenticatedDocumentDocumentIdRoute: AuthenticatedDocumentDocumentIdRoute, - AuthenticatedCampaignsIndexRoute: AuthenticatedCampaignsIndexRoute, +const AppAuthenticatedRouteChildren: AppAuthenticatedRouteChildren = { + AppAuthenticatedCampaignsCampaignIdRoute: + AppAuthenticatedCampaignsCampaignIdRoute, + AppAuthenticatedDocumentDocumentIdRoute: + AppAuthenticatedDocumentDocumentIdRoute, + AppAuthenticatedCampaignsIndexRoute: AppAuthenticatedCampaignsIndexRoute, } -const AuthenticatedRouteWithChildren = AuthenticatedRoute._addFileChildren( - AuthenticatedRouteChildren, -) +const AppAuthenticatedRouteWithChildren = + AppAuthenticatedRoute._addFileChildren(AppAuthenticatedRouteChildren) + +interface AppRouteChildren { + AppAuthenticatedRoute: typeof AppAuthenticatedRouteWithChildren + AppAboutRoute: typeof AppAboutRoute + AppLoginRoute: typeof AppLoginRoute + AppIndexRoute: typeof AppIndexRoute +} + +const AppRouteChildren: AppRouteChildren = { + AppAuthenticatedRoute: AppAuthenticatedRouteWithChildren, + AppAboutRoute: AppAboutRoute, + AppLoginRoute: AppLoginRoute, + AppIndexRoute: AppIndexRoute, +} + +const AppRouteWithChildren = AppRoute._addFileChildren(AppRouteChildren) export interface FileRoutesByFullPath { - '/': typeof IndexRoute - '': typeof AuthenticatedRouteWithChildren - '/about': typeof AboutRoute - '/login': typeof LoginRoute - '/campaigns/$campaignId': typeof AuthenticatedCampaignsCampaignIdRoute - '/document/$documentId': typeof AuthenticatedDocumentDocumentIdRoute - '/campaigns': typeof AuthenticatedCampaignsIndexRoute + '': typeof AppAuthenticatedRouteWithChildren + '/about': typeof AppAboutRoute + '/login': typeof AppLoginRoute + '/': typeof AppIndexRoute + '/campaigns/$campaignId': typeof AppAuthenticatedCampaignsCampaignIdRoute + '/document/$documentId': typeof AppAuthenticatedDocumentDocumentIdRoute + '/campaigns': typeof AppAuthenticatedCampaignsIndexRoute + '/document/$documentId/print': typeof AppauthenticatedDocumentDocumentIdPrintRoute } export interface FileRoutesByTo { - '/': typeof IndexRoute - '': typeof AuthenticatedRouteWithChildren - '/about': typeof AboutRoute - '/login': typeof LoginRoute - '/campaigns/$campaignId': typeof AuthenticatedCampaignsCampaignIdRoute - '/document/$documentId': typeof AuthenticatedDocumentDocumentIdRoute - '/campaigns': typeof AuthenticatedCampaignsIndexRoute + '': typeof AppAuthenticatedRouteWithChildren + '/about': typeof AppAboutRoute + '/login': typeof AppLoginRoute + '/': typeof AppIndexRoute + '/campaigns/$campaignId': typeof AppAuthenticatedCampaignsCampaignIdRoute + '/document/$documentId': typeof AppAuthenticatedDocumentDocumentIdRoute + '/campaigns': typeof AppAuthenticatedCampaignsIndexRoute + '/document/$documentId/print': typeof AppauthenticatedDocumentDocumentIdPrintRoute } export interface FileRoutesById { __root__: typeof rootRoute - '/': typeof IndexRoute - '/_authenticated': typeof AuthenticatedRouteWithChildren - '/about': typeof AboutRoute - '/login': typeof LoginRoute - '/_authenticated/campaigns/$campaignId': typeof AuthenticatedCampaignsCampaignIdRoute - '/_authenticated/document/$documentId': typeof AuthenticatedDocumentDocumentIdRoute - '/_authenticated/campaigns/': typeof AuthenticatedCampaignsIndexRoute + '/_app': typeof AppRouteWithChildren + '/_app/_authenticated': typeof AppAuthenticatedRouteWithChildren + '/_app/about': typeof AppAboutRoute + '/_app/login': typeof AppLoginRoute + '/_app/': typeof AppIndexRoute + '/_app/_authenticated/campaigns/$campaignId': typeof AppAuthenticatedCampaignsCampaignIdRoute + '/_app/_authenticated/document/$documentId': typeof AppAuthenticatedDocumentDocumentIdRoute + '/_app/_authenticated/campaigns/': typeof AppAuthenticatedCampaignsIndexRoute + '/_app_/_authenticated/document_/$documentId/print': typeof AppauthenticatedDocumentDocumentIdPrintRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath fullPaths: - | '/' | '' | '/about' | '/login' + | '/' | '/campaigns/$campaignId' | '/document/$documentId' | '/campaigns' + | '/document/$documentId/print' fileRoutesByTo: FileRoutesByTo to: - | '/' | '' | '/about' | '/login' + | '/' | '/campaigns/$campaignId' | '/document/$documentId' | '/campaigns' + | '/document/$documentId/print' id: | '__root__' - | '/' - | '/_authenticated' - | '/about' - | '/login' - | '/_authenticated/campaigns/$campaignId' - | '/_authenticated/document/$documentId' - | '/_authenticated/campaigns/' + | '/_app' + | '/_app/_authenticated' + | '/_app/about' + | '/_app/login' + | '/_app/' + | '/_app/_authenticated/campaigns/$campaignId' + | '/_app/_authenticated/document/$documentId' + | '/_app/_authenticated/campaigns/' + | '/_app_/_authenticated/document_/$documentId/print' fileRoutesById: FileRoutesById } export interface RootRouteChildren { - IndexRoute: typeof IndexRoute - AuthenticatedRoute: typeof AuthenticatedRouteWithChildren - AboutRoute: typeof AboutRoute - LoginRoute: typeof LoginRoute + AppRoute: typeof AppRouteWithChildren + AppauthenticatedDocumentDocumentIdPrintRoute: typeof AppauthenticatedDocumentDocumentIdPrintRoute } const rootRouteChildren: RootRouteChildren = { - IndexRoute: IndexRoute, - AuthenticatedRoute: AuthenticatedRouteWithChildren, - AboutRoute: AboutRoute, - LoginRoute: LoginRoute, + AppRoute: AppRouteWithChildren, + AppauthenticatedDocumentDocumentIdPrintRoute: + AppauthenticatedDocumentDocumentIdPrintRoute, } export const routeTree = rootRoute @@ -225,40 +275,54 @@ export const routeTree = rootRoute "__root__": { "filePath": "__root.tsx", "children": [ - "/", - "/_authenticated", - "/about", - "/login" + "/_app", + "/_app_/_authenticated/document_/$documentId/print" ] }, - "/": { - "filePath": "index.tsx" - }, - "/_authenticated": { - "filePath": "_authenticated.tsx", + "/_app": { + "filePath": "_app.tsx", "children": [ - "/_authenticated/campaigns/$campaignId", - "/_authenticated/document/$documentId", - "/_authenticated/campaigns/" + "/_app/_authenticated", + "/_app/about", + "/_app/login", + "/_app/" ] }, - "/about": { - "filePath": "about.tsx" + "/_app/_authenticated": { + "filePath": "_app/_authenticated.tsx", + "parent": "/_app", + "children": [ + "/_app/_authenticated/campaigns/$campaignId", + "/_app/_authenticated/document/$documentId", + "/_app/_authenticated/campaigns/" + ] }, - "/login": { - "filePath": "login.tsx" + "/_app/about": { + "filePath": "_app/about.tsx", + "parent": "/_app" }, - "/_authenticated/campaigns/$campaignId": { - "filePath": "_authenticated/campaigns.$campaignId.tsx", - "parent": "/_authenticated" + "/_app/login": { + "filePath": "_app/login.tsx", + "parent": "/_app" }, - "/_authenticated/document/$documentId": { - "filePath": "_authenticated/document.$documentId.tsx", - "parent": "/_authenticated" + "/_app/": { + "filePath": "_app/index.tsx", + "parent": "/_app" }, - "/_authenticated/campaigns/": { - "filePath": "_authenticated/campaigns.index.tsx", - "parent": "/_authenticated" + "/_app/_authenticated/campaigns/$campaignId": { + "filePath": "_app/_authenticated/campaigns.$campaignId.tsx", + "parent": "/_app/_authenticated" + }, + "/_app/_authenticated/document/$documentId": { + "filePath": "_app/_authenticated/document.$documentId.tsx", + "parent": "/_app/_authenticated" + }, + "/_app/_authenticated/campaigns/": { + "filePath": "_app/_authenticated/campaigns.index.tsx", + "parent": "/_app/_authenticated" + }, + "/_app_/_authenticated/document_/$documentId/print": { + "filePath": "_app_._authenticated.document_.$documentId.print.tsx" } } } diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index 246a026..6fd10a0 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -1,75 +1,12 @@ -import { Link, Outlet, createRootRoute } from "@tanstack/react-router"; -import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; -import { AuthProvider, useAuth } from "@/context/auth/AuthContext"; +import { AuthProvider } from "@/context/auth/AuthContext"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; - -/** - * Root header with navigation and user authentication controls. - */ -function RootHeader() { - const { user, logout, isLoading } = useAuth(); - return ( -
    -

    - DM's Table Companion -

    - -
    - {user ? ( - <> - - {user.email} - - - - ) : ( - - Log in - - )} -
    -
    - ); -} +import { Outlet, createRootRoute } from "@tanstack/react-router"; +import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; export const Route = createRootRoute({ component: () => ( <> - diff --git a/src/routes/_app.tsx b/src/routes/_app.tsx new file mode 100644 index 0000000..abdc260 --- /dev/null +++ b/src/routes/_app.tsx @@ -0,0 +1,77 @@ +import { useAuth } from "@/context/auth/AuthContext"; +import { Link, Outlet, createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/_app")({ + component: RouteComponent, +}); + +/** + * Root header with navigation and user authentication controls. + */ +function AppHeader() { + const { user, logout, isLoading } = useAuth(); + return ( +
    +

    + DM's Table Companion +

    + +
    + {user ? ( + <> + + {user.email} + + + + ) : ( + + Log in + + )} +
    +
    + ); +} + +function RouteComponent() { + return ( + <> + + + + ); +} diff --git a/src/routes/_authenticated.tsx b/src/routes/_app/_authenticated.tsx similarity index 79% rename from src/routes/_authenticated.tsx rename to src/routes/_app/_authenticated.tsx index f123cd7..fea59c5 100644 --- a/src/routes/_authenticated.tsx +++ b/src/routes/_app/_authenticated.tsx @@ -1,7 +1,7 @@ import { isAuthenticated } from "@/lib/pocketbase"; import { createFileRoute, redirect } from "@tanstack/react-router"; -export const Route = createFileRoute("/_authenticated")({ +export const Route = createFileRoute("/_app/_authenticated")({ beforeLoad: () => { if (!isAuthenticated()) { throw redirect({ diff --git a/src/routes/_authenticated/campaigns.$campaignId.tsx b/src/routes/_app/_authenticated/campaigns.$campaignId.tsx similarity index 96% rename from src/routes/_authenticated/campaigns.$campaignId.tsx rename to src/routes/_app/_authenticated/campaigns.$campaignId.tsx index 13a82dc..a008734 100644 --- a/src/routes/_authenticated/campaigns.$campaignId.tsx +++ b/src/routes/_app/_authenticated/campaigns.$campaignId.tsx @@ -6,7 +6,7 @@ import { Button } from "@headlessui/react"; import { useQueryClient, useSuspenseQuery } from "@tanstack/react-query"; import { Loader } from "@/components/Loader"; -export const Route = createFileRoute("/_authenticated/campaigns/$campaignId")({ +export const Route = createFileRoute("/_app/_authenticated/campaigns/$campaignId")({ component: RouteComponent, pendingComponent: Loader, }); diff --git a/src/routes/_authenticated/campaigns.index.tsx b/src/routes/_app/_authenticated/campaigns.index.tsx similarity index 95% rename from src/routes/_authenticated/campaigns.index.tsx rename to src/routes/_app/_authenticated/campaigns.index.tsx index 57aed67..170ca22 100644 --- a/src/routes/_authenticated/campaigns.index.tsx +++ b/src/routes/_app/_authenticated/campaigns.index.tsx @@ -6,7 +6,7 @@ import { Loader } from "@/components/Loader"; import { CreateCampaignButton } from "@/components/CreateCampaignButton"; import { useRouter } from "@tanstack/react-router"; -export const Route = createFileRoute("/_authenticated/campaigns/")({ +export const Route = createFileRoute("/_app/_authenticated/campaigns/")({ loader: async () => { const records = await pb.collection("campaigns").getFullList(); return { diff --git a/src/routes/_authenticated/document.$documentId.tsx b/src/routes/_app/_authenticated/document.$documentId.tsx similarity index 95% rename from src/routes/_authenticated/document.$documentId.tsx rename to src/routes/_app/_authenticated/document.$documentId.tsx index 60813e5..9d49d0e 100644 --- a/src/routes/_authenticated/document.$documentId.tsx +++ b/src/routes/_app/_authenticated/document.$documentId.tsx @@ -10,7 +10,7 @@ import { import { RelationshipList } from "@/components/RelationshipList"; import { SessionForm } from "@/components/documents/session/SessionForm"; -export const Route = createFileRoute("/_authenticated/document/$documentId")({ +export const Route = createFileRoute("/_app/_authenticated/document/$documentId")({ loader: async ({ params }) => { const doc = await pb.collection("documents").getOne(params.documentId); const relationships: Relationship[] = await pb diff --git a/src/routes/about.tsx b/src/routes/_app/about.tsx similarity index 74% rename from src/routes/about.tsx rename to src/routes/_app/about.tsx index 1e6c706..c2721ac 100644 --- a/src/routes/about.tsx +++ b/src/routes/_app/about.tsx @@ -1,6 +1,6 @@ import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/about')({ +export const Route = createFileRoute('/_app/about')({ component: RouteComponent, }) diff --git a/src/routes/index.tsx b/src/routes/_app/index.tsx similarity index 80% rename from src/routes/index.tsx rename to src/routes/_app/index.tsx index a0a2dfa..a8f8b4a 100644 --- a/src/routes/index.tsx +++ b/src/routes/_app/index.tsx @@ -1,6 +1,6 @@ import { createFileRoute } from "@tanstack/react-router"; -export const Route = createFileRoute("/")({ +export const Route = createFileRoute("/_app/")({ component: App, }); diff --git a/src/routes/login.tsx b/src/routes/_app/login.tsx similarity index 99% rename from src/routes/login.tsx rename to src/routes/_app/login.tsx index fb2547b..f300f49 100644 --- a/src/routes/login.tsx +++ b/src/routes/_app/login.tsx @@ -8,7 +8,7 @@ import { useState } from "react"; * Login and signup page for authentication. * Allows users to log in or create a new account. */ -export const Route = createFileRoute("/login")({ +export const Route = createFileRoute("/_app/login")({ beforeLoad: () => { if (isAuthenticated()) { throw redirect({ diff --git a/src/routes/_app_._authenticated.document_.$documentId.print.tsx b/src/routes/_app_._authenticated.document_.$documentId.print.tsx new file mode 100644 index 0000000..608714f --- /dev/null +++ b/src/routes/_app_._authenticated.document_.$documentId.print.tsx @@ -0,0 +1,74 @@ +import { DocumentPrintRow } from "@/components/documents/DocumentPrintRow"; +import { SessionPrintRow } from "@/components/documents/session/SessionPrintRow"; +import { Loader } from "@/components/Loader"; +import { RelationshipList } from "@/components/RelationshipList"; +import { pb } from "@/lib/pocketbase"; +import { RelationshipType, type Relationship, type Session } from "@/lib/types"; +import { useSuspenseQuery } from "@tanstack/react-query"; +import { createFileRoute } from "@tanstack/react-router"; +import _ from "lodash"; + +export const Route = createFileRoute( + "/_app_/_authenticated/document_/$documentId/print", +)({ + component: RouteComponent, + pendingComponent: Loader, +}); + +function RouteComponent() { + const params = Route.useParams(); + const { + data: { session, relationships }, + } = useSuspenseQuery({ + queryKey: ["session", "relationships"], + queryFn: async () => { + const session = await pb + .collection("documents") + .getOne(params.documentId); + const relationships: Relationship[] = await pb + .collection("relationships") + .getFullList({ + filter: `primary = "${params.documentId}"`, + expand: "secondary", + }); + console.log("Fetched data: ", relationships); + return { + session: session as Session, + relationships: _.mapValues( + _.groupBy(relationships, (r) => r.type), + (rs: Relationship[]) => rs.flatMap((r) => r.expand?.secondary), + ), + }; + }, + }); + + console.log("Parsed data: ", relationships); + + return ( +
    + + + {[ + RelationshipType.Scenes, + RelationshipType.Secrets, + RelationshipType.Locations, + RelationshipType.Npcs, + RelationshipType.Monsters, + RelationshipType.Treasures, + ].map((relationshipType) => ( +
    +

    + {relationshipType.charAt(0).toUpperCase() + + relationshipType.slice(1)} +

    + +
      + {(relationships[relationshipType] ?? []).map((item) => ( + + ))} +
    +
    + ))} +
    + ); +}