mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-12 16:37:06 +02:00
Add rich renderer for kind 10063 Blossom server list
- Create BlossomServerListRenderer.tsx with feed and detail views - Show user's configured Blossom servers with clickable links - Clicking a server opens the Blossom window with server info - Register renderers for kind 10063 (BUD-03) - Fix lint error by renaming useFallbackServers to applyFallbackServers
This commit is contained in:
@@ -109,7 +109,7 @@ export function BlossomUploadDialog({
|
||||
}, [open]);
|
||||
|
||||
// Helper to set fallback servers
|
||||
const useFallbackServers = useCallback(() => {
|
||||
const applyFallbackServers = useCallback(() => {
|
||||
setServers(FALLBACK_SERVERS);
|
||||
setSelectedServers(new Set([FALLBACK_SERVERS[0]])); // Select first by default
|
||||
setUsingFallback(true);
|
||||
@@ -172,7 +172,7 @@ export function BlossomUploadDialog({
|
||||
const timeout = setTimeout(() => {
|
||||
setLoadingServers(false);
|
||||
if (!foundUserServers) {
|
||||
useFallbackServers();
|
||||
applyFallbackServers();
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
@@ -180,7 +180,7 @@ export function BlossomUploadDialog({
|
||||
subscription?.unsubscribe();
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
}, [open, pubkey, eventStore, useFallbackServers]);
|
||||
}, [open, pubkey, eventStore, applyFallbackServers]);
|
||||
|
||||
// Create preview URL for selected file
|
||||
useEffect(() => {
|
||||
|
||||
127
src/components/nostr/kinds/BlossomServerListRenderer.tsx
Normal file
127
src/components/nostr/kinds/BlossomServerListRenderer.tsx
Normal file
@@ -0,0 +1,127 @@
|
||||
import { BaseEventProps, BaseEventContainer } from "./BaseEventRenderer";
|
||||
import { NostrEvent } from "@/types/nostr";
|
||||
import { getServersFromEvent } from "@/services/blossom";
|
||||
import { useGrimoire } from "@/core/state";
|
||||
import { HardDrive, ExternalLink } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
/**
|
||||
* Kind 10063 Renderer - Blossom User Server List (Feed View)
|
||||
* Shows the user's configured Blossom blob storage servers
|
||||
*/
|
||||
export function BlossomServerListRenderer({ event }: BaseEventProps) {
|
||||
const { addWindow } = useGrimoire();
|
||||
const servers = getServersFromEvent(event);
|
||||
|
||||
const handleServerClick = (serverUrl: string) => {
|
||||
// Open the blossom viewer with server info
|
||||
addWindow(
|
||||
"blossom",
|
||||
{ subcommand: "servers", serverUrl },
|
||||
`blossom servers`,
|
||||
undefined,
|
||||
);
|
||||
};
|
||||
|
||||
if (servers.length === 0) {
|
||||
return (
|
||||
<BaseEventContainer event={event}>
|
||||
<div className="text-xs text-muted-foreground italic">
|
||||
No Blossom servers configured
|
||||
</div>
|
||||
</BaseEventContainer>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BaseEventContainer event={event}>
|
||||
<div className="flex flex-col gap-0.5">
|
||||
{servers.map((url) => (
|
||||
<div
|
||||
key={url}
|
||||
className="flex items-center gap-2 py-0.5 group cursor-pointer hover:bg-muted/30 rounded px-1 -mx-1"
|
||||
onClick={() => handleServerClick(url)}
|
||||
>
|
||||
<HardDrive className="size-4 text-muted-foreground flex-shrink-0" />
|
||||
<span className="font-mono text-xs underline decoration-dotted flex-1 truncate">
|
||||
{url}
|
||||
</span>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-6 opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
window.open(url, "_blank");
|
||||
}}
|
||||
>
|
||||
<ExternalLink className="size-3" />
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</BaseEventContainer>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Kind 10063 Detail Renderer - Blossom User Server List (Detail View)
|
||||
* Shows full Blossom server list with clickable links
|
||||
*/
|
||||
export function BlossomServerListDetailRenderer({
|
||||
event,
|
||||
}: {
|
||||
event: NostrEvent;
|
||||
}) {
|
||||
const { addWindow } = useGrimoire();
|
||||
const servers = getServersFromEvent(event);
|
||||
|
||||
const handleServerClick = (serverUrl: string) => {
|
||||
addWindow(
|
||||
"blossom",
|
||||
{ subcommand: "servers", serverUrl },
|
||||
`blossom servers`,
|
||||
undefined,
|
||||
);
|
||||
};
|
||||
|
||||
if (servers.length === 0) {
|
||||
return (
|
||||
<div className="p-4 text-center text-muted-foreground text-sm">
|
||||
No Blossom servers configured
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2 p-4">
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground mb-2">
|
||||
<HardDrive className="size-4" />
|
||||
<span>Blossom Servers ({servers.length})</span>
|
||||
</div>
|
||||
{servers.map((url) => (
|
||||
<div
|
||||
key={url}
|
||||
className="flex items-center gap-3 p-2 rounded hover:bg-muted/30 cursor-pointer group"
|
||||
onClick={() => handleServerClick(url)}
|
||||
>
|
||||
<HardDrive className="size-4 text-muted-foreground flex-shrink-0" />
|
||||
<span className="font-mono text-sm underline decoration-dotted flex-1 truncate">
|
||||
{url}
|
||||
</span>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-7 opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
window.open(url, "_blank");
|
||||
}}
|
||||
>
|
||||
<ExternalLink className="size-4" />
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -26,6 +26,10 @@ import { Kind9802Renderer } from "./HighlightRenderer";
|
||||
import { Kind9802DetailRenderer } from "./HighlightDetailRenderer";
|
||||
import { Kind10002Renderer } from "./RelayListRenderer";
|
||||
import { Kind10002DetailRenderer } from "./RelayListDetailRenderer";
|
||||
import {
|
||||
BlossomServerListRenderer,
|
||||
BlossomServerListDetailRenderer,
|
||||
} from "./BlossomServerListRenderer";
|
||||
import { Kind10317Renderer } from "./GraspListRenderer";
|
||||
import { Kind10317DetailRenderer } from "./GraspListDetailRenderer";
|
||||
import { Kind30023Renderer } from "./ArticleRenderer";
|
||||
@@ -96,6 +100,7 @@ const kindRenderers: Record<number, React.ComponentType<BaseEventProps>> = {
|
||||
9802: Kind9802Renderer, // Highlight
|
||||
777: SpellRenderer, // Spell (Grimoire)
|
||||
10002: Kind10002Renderer, // Relay List Metadata (NIP-65)
|
||||
10063: BlossomServerListRenderer, // Blossom User Server List (BUD-03)
|
||||
10317: Kind10317Renderer, // User Grasp List (NIP-34)
|
||||
10006: GenericRelayListRenderer, // Blocked Relays (NIP-51)
|
||||
10007: GenericRelayListRenderer, // Search Relays (NIP-51)
|
||||
@@ -170,6 +175,7 @@ const detailRenderers: Record<
|
||||
1621: IssueDetailRenderer, // Issue Detail (NIP-34)
|
||||
9802: Kind9802DetailRenderer, // Highlight Detail
|
||||
10002: Kind10002DetailRenderer, // Relay List Detail (NIP-65)
|
||||
10063: BlossomServerListDetailRenderer, // Blossom User Server List Detail (BUD-03)
|
||||
10317: Kind10317DetailRenderer, // User Grasp List Detail (NIP-34)
|
||||
777: SpellDetailRenderer, // Spell Detail
|
||||
30023: Kind30023DetailRenderer, // Long-form Article Detail
|
||||
|
||||
Reference in New Issue
Block a user