mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-10 07:27:23 +02:00
feat: enhance spell/spellbook renderers with clickable titles and inferred kinds
- Use ClickableEventTitle for spell and spellbook titles in all views - Infer event kinds from spellbook windows and display KindBadges in feed/detail views - Ensure consistent styling and navigation across spell/spellbook components
This commit is contained in:
@@ -223,7 +223,14 @@ export function SpellDetailRenderer({ event }: BaseEventProps) {
|
||||
return (
|
||||
<div className="flex flex-col gap-6 p-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
{spell.name && <h2 className="text-2xl font-bold">{spell.name}</h2>}
|
||||
{spell.name && (
|
||||
<ClickableEventTitle
|
||||
event={event}
|
||||
className="text-2xl font-bold hover:underline cursor-pointer"
|
||||
>
|
||||
{spell.name}
|
||||
</ClickableEventTitle>
|
||||
)}
|
||||
{spell.description && (
|
||||
<p className="text-muted-foreground">{spell.description}</p>
|
||||
)}
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
ClickableEventTitle,
|
||||
} from "./BaseEventRenderer";
|
||||
import { parseSpellbook } from "@/lib/spellbook-manager";
|
||||
import { SpellbookEvent } from "@/types/spell";
|
||||
import { SpellbookEvent, ParsedSpellbook } from "@/types/spell";
|
||||
import { NostrEvent } from "@/types/nostr";
|
||||
import { BookHeart, Layout, ExternalLink, Play, Eye, Share2 } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -14,6 +14,23 @@ import { toast } from "sonner";
|
||||
import { useProfile } from "@/hooks/useProfile";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import { useNavigate } from "react-router";
|
||||
import { KindBadge } from "@/components/KindBadge";
|
||||
import { WindowInstance } from "@/types/app";
|
||||
|
||||
/**
|
||||
* Helper to extract all unique event kinds from a spellbook's windows
|
||||
*/
|
||||
function getSpellbookKinds(spellbook: ParsedSpellbook): number[] {
|
||||
const kinds = new Set<number>();
|
||||
Object.values(spellbook.content.windows).forEach((w) => {
|
||||
const window = w as WindowInstance;
|
||||
// If it's a req window, extract kinds from filter
|
||||
if (window.appId === "req" && window.props?.filter?.kinds) {
|
||||
window.props.filter.kinds.forEach((k: number) => kinds.add(k));
|
||||
}
|
||||
});
|
||||
return Array.from(kinds).sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Preview Button Component
|
||||
@@ -100,6 +117,22 @@ export function SpellbookRenderer({ event }: BaseEventProps) {
|
||||
<PreviewButton event={event} identifier={spellbook.slug} size="sm" className="flex-shrink-0" />
|
||||
</div>
|
||||
|
||||
{/* Kind Badges */}
|
||||
{getSpellbookKinds(spellbook).length > 0 && (
|
||||
<div className="flex flex-wrap gap-1.5 mt-1">
|
||||
{getSpellbookKinds(spellbook).map((kind) => (
|
||||
<KindBadge
|
||||
key={kind}
|
||||
kind={kind}
|
||||
variant="compact"
|
||||
className="text-[10px]"
|
||||
showName
|
||||
clickable
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Stats */}
|
||||
<div className="flex gap-4 mt-1 text-xs text-muted-foreground font-mono">
|
||||
<div className="flex items-center gap-1">
|
||||
@@ -167,8 +200,27 @@ export function SpellbookDetailRenderer({ event }: { event: NostrEvent }) {
|
||||
<div className="p-2.5 bg-accent/10 rounded-xl">
|
||||
<BookHeart className="size-8 text-accent" />
|
||||
</div>
|
||||
<h2 className="text-3xl font-bold truncate">{spellbook.title}</h2>
|
||||
<ClickableEventTitle
|
||||
event={event}
|
||||
className="text-3xl font-bold truncate hover:underline cursor-pointer"
|
||||
>
|
||||
{spellbook.title}
|
||||
</ClickableEventTitle>
|
||||
</div>
|
||||
|
||||
{getSpellbookKinds(spellbook).length > 0 && (
|
||||
<div className="flex flex-wrap gap-2 py-1">
|
||||
{getSpellbookKinds(spellbook).map((kind) => (
|
||||
<KindBadge
|
||||
key={kind}
|
||||
kind={kind}
|
||||
showName
|
||||
clickable
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{spellbook.description && (
|
||||
<p className="text-lg text-muted-foreground">
|
||||
{spellbook.description}
|
||||
|
||||
Reference in New Issue
Block a user