Makes some document previews

This commit is contained in:
2025-07-26 13:26:31 -07:00
parent 4a109d152c
commit c7083a9b56
8 changed files with 135 additions and 10 deletions

View File

@@ -0,0 +1,35 @@
import * as Icons from "./Icons";
import { useState, Children } from "react";
export function EditToggle({ children }: React.PropsWithChildren) {
const [isEditing, setIsEditing] = useState(false);
const editChildren = (
Children.toArray(children) as React.ReactElement[]
).filter((c) => c.type === Editing);
const nonEditChildren = (
Children.toArray(children) as React.ReactElement[]
).filter((c) => c.type !== Editing);
return (
<div className="relative">
<div className="absolute right-0 top-0 z-50">
<button
type="button"
className="inline-flex items-center justify-center rounded-full bg-violet-600 hover:bg-violet-700 text-white w-8 h-8 focus:outline-none focus:ring-2 focus:ring-violet-400"
aria-label={isEditing ? "Exit edit mode" : "Enter edit mode"}
onClick={() => setIsEditing(!isEditing)}
>
<Icons.Edit />
</button>
</div>
{isEditing ? editChildren : nonEditChildren}
</div>
);
}
export const Editing = ({ children }: React.PropsWithChildren) => (
<>{children}</>
);
export const NotEditing = ({ children }: React.PropsWithChildren) => (
<>{children}</>
);

View File

@@ -0,0 +1,15 @@
import { FormattedText } from "../FormattedText";
export type Props = {
title?: string;
description?: string;
};
export const BasicPreview = ({ title, description }: Props) => {
return (
<div>
{title && <h4 className="font-bold">{title}</h4>}
{description && <FormattedText>{description}</FormattedText>}
</div>
);
};

View File

@@ -0,0 +1,68 @@
// Shows a preview of a document with it's relationships.
import { makeDocumentPath } from "@/lib/documentPath";
import { relationshipsForDocument } from "@/lib/relationships";
import { type AnyDocument } from "@/lib/types";
import { Link } from "@tanstack/react-router";
import { Editing, EditToggle, NotEditing } from "../EditToggle";
import { BasicPreview } from "./BasicPreview";
import { DocumentEditForm } from "./DocumentEditForm";
export const DocumentPreview = ({ doc }: { doc: AnyDocument }) => {
const relationships = relationshipsForDocument(doc);
return (
<div>
<EditToggle>
<Editing>
<DocumentEditForm document={doc} />
</Editing>
<NotEditing>
<ShowDocument doc={doc} />
</NotEditing>
</EditToggle>
<ul>
{relationships.map((relType) => (
<li>
<Link to={makeDocumentPath(doc.id, relType)}>{relType}</Link>
</li>
))}
</ul>
</div>
);
};
const ShowDocument = ({ doc }: { doc: AnyDocument }) => {
switch (doc.type) {
case "location":
return (
<BasicPreview
title={doc.data.name}
description={doc.data.description}
/>
);
case "monster":
return <BasicPreview title={doc.data.name} />;
case "npc":
return (
<BasicPreview
title={doc.data.name}
description={doc.data.description}
/>
);
case "session":
return (
<BasicPreview title={doc.created} description={doc.data.strongStart} />
);
case "secret":
return <BasicPreview title={doc.data.text} />;
case "scene":
return <BasicPreview description={doc.data.text} />;
case "treasure":
return <BasicPreview title={doc.data.text} />;
}
};

View File

@@ -9,6 +9,7 @@ import { DocumentTitle } from "./DocumentTitle";
import { Tab, TabbedLayout } from "../layout/TabbedLayout";
import { DocumentEditForm } from "./DocumentEditForm";
import { RelatedDocumentList } from "./RelatedDocumentList";
import { DocumentPreview } from "./DocumentPreview";
export function DocumentView({
documentId,
@@ -59,6 +60,7 @@ export function DocumentView({
tabs={[
<Tab
to="/document/$documentId"
key="attributes"
params={{
documentId,
}}
@@ -68,6 +70,7 @@ export function DocumentView({
...relationshipList.map((relationshipEntry) => (
<Tab
to="/document/$documentId/$relationshipType"
key={relationshipEntry}
params={{
documentId,
relationshipType: relationshipEntry,
@@ -101,5 +104,5 @@ function Flyout({ docId }: { docId: DocumentId }) {
const doc = docResult.value.doc;
return <DocumentEditForm document={doc} />;
return <DocumentPreview doc={doc} />;
}

View File

@@ -6,8 +6,9 @@ export const SessionRow = ({ session }: { session: Session }) => {
return (
<div>
<Link
to="/document/$documentId"
params={{ documentId: session.id }}
to="/campaigns/$campaignId"
params={{ campaignId: session.campaign }}
search={{ tab: "sessions", docId: session.id }}
className="block font-semibold text-lg text-slate-300"
>
<FormattedDate date={session.created} />

View File

@@ -38,8 +38,8 @@ export function TabbedLayout({
export type TabProps = {
label: string;
to: string;
params: Record<string, any>;
search: Record<string, any>;
params?: Record<string, any>;
search?: Record<string, any>;
active?: boolean;
};

View File

@@ -19,8 +19,6 @@ export const DocumentContext = createContext<DocumentContextValue | undefined>(
export function DocumentProvider({ children }: { children: ReactNode }) {
const [state, dispatch] = useReducer(reducer, initialState());
console.log("State: ", state);
return (
<DocumentContext.Provider
value={{

View File

@@ -1,7 +1,9 @@
import { DocumentPreview } from "@/components/documents/DocumentPreview";
import { DocumentRow } from "@/components/documents/DocumentRow";
import { SessionRow } from "@/components/documents/session/SessionRow";
import { Tab, TabbedLayout } from "@/components/layout/TabbedLayout";
import { Loader } from "@/components/Loader";
import { DocumentLoader } from "@/context/document/DocumentLoader";
import { useDocument } from "@/context/document/hooks";
import { pb } from "@/lib/pocketbase";
import type { Campaign, DocumentId, Relationship, Session } from "@/lib/types";
@@ -166,11 +168,14 @@ function Flyout({ docId }: { docId: DocumentId }) {
const { docResult } = useDocument(docId);
if (docResult?.type !== "ready") {
return <Loader />;
return (
<DocumentLoader documentId={docId}>
<Loader />
</DocumentLoader>
);
}
const doc = docResult.value.doc;
// TODO: Document preview
return <DocumentRow document={doc} root={doc} />;
return <DocumentPreview doc={doc} />;
}