feat: story library, player and builder UI
All checks were successful
/ checks (push) Successful in 41s
/ deploy (push) Successful in 4s

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nholtware 2026-11-05 12:45:06 -06:00
parent 52778622a4
commit 364a911794
14 changed files with 1149 additions and 41 deletions

59
src/routes/BuildList.tsx Normal file
View file

@ -0,0 +1,59 @@
import { Link, useLoaderData, useNavigate, useRevalidator } from "react-router";
import {
createStory,
deleteStory,
emptyDoc,
listStories,
type StorySummary,
} from "../lib/stories";
export const buildListLoader = () => listStories(true);
export function BuildList() {
const stories = useLoaderData() as StorySummary[];
const navigate = useNavigate();
const { revalidate } = useRevalidator();
async function create() {
const { story } = await createStory({
title: "Untitled adventure",
description: "",
doc: emptyDoc(),
});
navigate(`/build/${story.id}`);
}
async function remove(s: StorySummary) {
if (!confirm(`Delete "${s.title}"? This cannot be undone.`)) return;
await deleteStory(s.id);
await revalidate();
}
return (
<section>
<h1>Your stories</h1>
<p>
<button onClick={create}>New story</button>
</p>
<ul className="cards">
{stories.map((s) => (
<li key={s.id}>
<h2>
{s.title}{" "}
<span className="badge">
{s.published ? "published" : "draft"}
</span>
</h2>
<small>{s.nodeCount} scenes</small>{" "}
<Link className="button" to={`/build/${s.id}`}>
Edit
</Link>{" "}
<button className="link" onClick={() => remove(s)}>
Delete
</button>
</li>
))}
</ul>
</section>
);
}