feat(pets): register module navigation

This commit is contained in:
ginnoir
2026-07-10 02:57:45 -05:00
parent 7704924d88
commit 86444bc850
5 changed files with 95 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
import Link from "next/link";
import { listPets } from "@/modules/pets/server/queries";
export default async function PetsPage() {
const pets = await listPets();
return (
<div className="page-content">
<div className="mb-6 flex items-center justify-between gap-4">
<h1 className="page-title mb-0">Pets</h1>
<Link href="/pets/new" className="btn btn-primary">
Add pet
</Link>
</div>
{pets.length === 0 ? (
<p className="text-sm text-[var(--ink-mute)]">No pets yet.</p>
) : (
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
{pets.map((pet) => (
<Link
key={pet.id}
href={`/pets/${pet.id}`}
className="card p-4 hover:bg-[var(--surface-2)]"
>
<h2 className="font-semibold">{pet.name}</h2>
<p className="text-sm capitalize text-[var(--ink-mute)]">
{[pet.species, pet.breed].filter(Boolean).join(" · ")}
</p>
</Link>
))}
</div>
)}
</div>
);
}
+2
View File
@@ -3,6 +3,7 @@ import {
BookHeart,
Calendar,
Sprout,
PawPrint,
CalendarDays,
CheckSquare,
ChevronDown,
@@ -73,6 +74,7 @@ const ICONS: Record<string, React.ComponentType<LucideProps>> = {
filter: Filter,
sun: Sun,
sprout: Sprout,
"paw-print": PawPrint,
mail: Mail,
menu: Menu,
"message-circle": MessageCircle,
+2
View File
@@ -4,6 +4,7 @@ import calendarManifest from "./calendar/manifest";
import listsManifest from "./lists/manifest";
import notesManifest from "./notes/manifest";
import gardenManifest from "./garden/manifest";
import petsManifest from "./pets/manifest";
import bangsManifest from "./bangs/manifest";
import journalManifest from "./journal/manifest";
import agentManifest from "./agent/manifest";
@@ -13,6 +14,7 @@ registerModule(calendarManifest);
registerModule(listsManifest);
registerModule(notesManifest);
registerModule(gardenManifest);
registerModule(petsManifest);
registerModule(bangsManifest);
registerModule(journalManifest);
registerModule(agentManifest);
+49
View File
@@ -0,0 +1,49 @@
import { z } from "zod";
import type { ModuleManifest } from "../_core/module";
import { searchPets } from "./server/queries";
const petsManifest: ModuleManifest = {
id: "pets",
name: "Pets",
nav: { href: "/pets", label: "Pets", icon: "paw-print" },
entities: [
{
type: "pets.pet",
label: { singular: "Pet", plural: "Pets" },
search: { search: searchPets },
reminder: { canRemind: true },
resolveUrl: (id) => `/pets/${id}`,
renderActivity: (entry) => {
const name = entry.payload?.name as string | undefined;
if (entry.action === "create") return `Added pet${name ? ` "${name}"` : ""}`;
if (entry.action === "delete") return `Removed pet${name ? ` "${name}"` : ""}`;
return `Updated pet${name ? ` "${name}"` : ""}`;
},
},
],
dashboardWidgets: [
{
id: "pets.overview",
title: "Pets overview",
description: "Pet count and medical items due within 30 days.",
category: "Pets",
defaultSize: { w: 3, h: 2 },
minSize: { w: 2, h: 2 },
defaultPriority: 60,
configSchema: z.object({}),
defaultConfig: {},
render: () => null,
},
],
quickAdds: [
{
id: "pets.add",
label: "Add pet",
icon: "paw-print",
url: "/pets/new",
createKey: "pets.pet",
},
],
};
export default petsManifest;
+8
View File
@@ -0,0 +1,8 @@
import assert from "node:assert/strict";
import test from "node:test";
import petsManifest from "../../src/modules/pets/manifest";
test("pets manifest contributes visible navigation and a quick add action", () => {
assert.deepEqual(petsManifest.nav, { href: "/pets", label: "Pets", icon: "paw-print" });
assert.equal(petsManifest.quickAdds?.[0]?.createKey, "pets.pet");
});