diff --git a/claudedocs/kind-1337-code-snippets.md b/claudedocs/kind-1337-code-snippets.md
new file mode 100644
index 0000000..a37f17e
--- /dev/null
+++ b/claudedocs/kind-1337-code-snippets.md
@@ -0,0 +1,148 @@
+# Kind 1337 Code Snippet Renderer (NIP-C0)
+
+## Overview
+Added complete support for kind 1337 (Code Snippet) events from NIP-C0, with both feed and detail renderers.
+
+## Files Created
+
+### 1. Helper Functions (`src/lib/nip-c0-helpers.ts`)
+Tag extraction utilities using applesauce-core:
+- `getCodeLanguage()` - Programming language (l tag)
+- `getCodeName()` - Filename (name tag)
+- `getCodeExtension()` - File extension without dot (extension tag)
+- `getCodeDescription()` - Description text (description tag)
+- `getCodeRuntime()` - Runtime specification (runtime tag)
+- `getCodeLicenses()` - Array of license identifiers (license tags)
+- `getCodeDependencies()` - Array of dependencies (dep tags)
+- `getCodeRepo()` - Repository reference with type detection (URL or NIP-34 address)
+
+### 2. Feed Renderer (`src/components/nostr/kinds/Kind1337Renderer.tsx`)
+Compact view showing:
+- **Clickable title** - Opens detail view, uses filename or "Code Snippet"
+- **Language badge** - Shows programming language in styled chip
+- **Description** - Truncated to 2 lines if present
+- **Code preview** - First 5 lines with line-clamp and "..." indicator
+- Wrapped in `BaseEventContainer` for consistency
+
+### 3. Detail Renderer (`src/components/nostr/kinds/Kind1337DetailRenderer.tsx`)
+Full view with:
+- **Header** - Title with FileCode icon
+- **Metadata section** (before code):
+ - Language and Extension
+ - Description
+ - Runtime (if present)
+ - Licenses (if present)
+ - Dependencies list (if present)
+ - Repository link:
+ - NIP-34 address → clickable, opens repository event
+ - URL → external link with icon
+- **Code section**:
+ - Full code in `
` with `font-mono` styling
+ - Copy button inline (absolute positioned top-right)
+ - Matches JsonViewer pattern
+
+## Integration Points
+
+### Kinds Registry
+Already existed in `src/constants/kinds.ts`:
+```typescript
+1337: {
+ kind: 1337,
+ name: "Code",
+ description: "Code Snippet",
+ nip: "C0",
+ icon: FileCode,
+}
+```
+
+### Event Title System
+Added to `src/lib/event-title.ts`:
+```typescript
+case 1337: // Code snippet
+ title = getCodeName(event);
+ break;
+```
+Window titles show filename or fall back to "Code Snippet"
+
+### Renderer Registry
+Added to `src/components/nostr/kinds/index.tsx`:
+```typescript
+1337: Kind1337Renderer, // Code Snippet (NIP-C0)
+```
+
+## Features
+
+### Feed View
+- Clean, compact display
+- Language identification at a glance
+- Quick code preview without opening
+- Clickable to open full view
+
+### Detail View
+- Complete metadata display
+- NIP-34 repository integration (handles both URLs and Nostr addresses)
+- One-click copy functionality
+- Clean, readable code display
+- Professional layout with metadata organized before code
+
+## Design Decisions
+
+### No Syntax Highlighting (MVP)
+- Uses plain `` with `font-mono` styling (matching JsonViewer)
+- No new dependencies added
+- Can add syntax highlighting later (react-syntax-highlighter) as enhancement
+
+### No Download Button
+- Simplified to just Copy functionality
+- Users can copy and save manually
+- Reduces UI complexity
+
+### Metadata Before Code
+- More scannable - users see what the code is before reading it
+- Follows natural information hierarchy
+- Easier to understand context
+
+### Copy Button Position
+- Inline in code section (top-right absolute)
+- Matches existing JsonViewer pattern
+- Consistent UX across app
+
+## NIP-C0 Compliance
+
+Supports all NIP-C0 tags:
+- ✅ `l` - Programming language
+- ✅ `name` - Filename
+- ✅ `extension` - File extension
+- ✅ `description` - Description
+- ✅ `runtime` - Runtime specification
+- ✅ `license` - License(s) (supports multiple)
+- ✅ `dep` - Dependencies (supports multiple)
+- ✅ `repo` - Repository reference (URL or NIP-34)
+
+## Future Enhancements
+
+Potential improvements for Phase 2:
+1. **Syntax Highlighting** - Add react-syntax-highlighter for color-coded display
+2. **Line Numbers** - Optional line numbers for code blocks
+3. **Code Formatting** - Auto-format/prettify code
+4. **Run Functionality** - Execute supported languages (complex, low priority)
+5. **Download Button** - Add back if users request it
+6. **Diff View** - For patches or code changes
+
+## Testing
+
+- ✅ Type check passes
+- ✅ Integrates with existing event title system
+- ✅ Follows established component patterns
+- ✅ Uses applesauce-core helpers consistently
+- ✅ NIP-34 repository links handled correctly
+
+## Usage
+
+Users can now:
+1. View code snippets in feeds with preview
+2. Click to open full detail view
+3. See all metadata (language, runtime, deps, etc.)
+4. Copy code with one click
+5. Navigate to referenced repositories (NIP-34 or URLs)
+6. See proper window titles with filenames
diff --git a/package-lock.json b/package-lock.json
index 9b878a0..0ae15ec 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -32,6 +32,7 @@
"dexie-react-hooks": "^4.2.0",
"jotai": "^2.15.2",
"lucide-react": "latest",
+ "prismjs": "^1.30.0",
"react": "^19.2.1",
"react-dom": "^19.2.1",
"react-markdown": "^10.1.0",
@@ -48,6 +49,7 @@
"@eslint/js": "^9.17.0",
"@react-router/dev": "^7.1.0",
"@types/node": "^24.10.1",
+ "@types/prismjs": "^1.26.5",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"@types/uuid": "^10.0.0",
@@ -3841,6 +3843,13 @@
"undici-types": "~7.16.0"
}
},
+ "node_modules/@types/prismjs": {
+ "version": "1.26.5",
+ "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz",
+ "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/react": {
"version": "19.2.7",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
@@ -8033,6 +8042,15 @@
"node": ">=6.0.0"
}
},
+ "node_modules/prismjs": {
+ "version": "1.30.0",
+ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
+ "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/proc-log": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz",
diff --git a/package.json b/package.json
index 5573605..cdd58d1 100644
--- a/package.json
+++ b/package.json
@@ -40,6 +40,7 @@
"dexie-react-hooks": "^4.2.0",
"jotai": "^2.15.2",
"lucide-react": "latest",
+ "prismjs": "^1.30.0",
"react": "^19.2.1",
"react-dom": "^19.2.1",
"react-markdown": "^10.1.0",
@@ -56,6 +57,7 @@
"@eslint/js": "^9.17.0",
"@react-router/dev": "^7.1.0",
"@types/node": "^24.10.1",
+ "@types/prismjs": "^1.26.5",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"@types/uuid": "^10.0.0",
diff --git a/src/components/CodeCopyButton.tsx b/src/components/CodeCopyButton.tsx
new file mode 100644
index 0000000..c6faefe
--- /dev/null
+++ b/src/components/CodeCopyButton.tsx
@@ -0,0 +1,33 @@
+import { Copy, CopyCheck } from "lucide-react";
+
+interface CodeCopyButtonProps {
+ onCopy: () => void;
+ copied: boolean;
+ label?: string;
+ className?: string;
+}
+
+/**
+ * Reusable copy button for code blocks with consistent styling
+ * Designed to be absolutely positioned over code containers
+ */
+export function CodeCopyButton({
+ onCopy,
+ copied,
+ label = "Copy code",
+ className = "",
+}: CodeCopyButtonProps) {
+ return (
+
+ );
+}
diff --git a/src/components/DynamicWindowTitle.tsx b/src/components/DynamicWindowTitle.tsx
index be8dba1..08b1312 100644
--- a/src/components/DynamicWindowTitle.tsx
+++ b/src/components/DynamicWindowTitle.tsx
@@ -222,7 +222,7 @@ function useDynamicTitle(window: WindowInstance): WindowTitleData {
{getEventDisplayTitle(event, false)}
-
-
+
);
}, [appId, event]);
diff --git a/src/components/EventDetailViewer.tsx b/src/components/EventDetailViewer.tsx
index b3ec3ee..10a075e 100644
--- a/src/components/EventDetailViewer.tsx
+++ b/src/components/EventDetailViewer.tsx
@@ -2,14 +2,15 @@ import { useState } from "react";
import type { EventPointer, AddressPointer } from "nostr-tools/nip19";
import { useNostrEvent } from "@/hooks/useNostrEvent";
import { KindRenderer } from "./nostr/kinds";
-import { Kind0DetailRenderer } from "./nostr/kinds/Kind0DetailRenderer";
-import { Kind3DetailView } from "./nostr/kinds/Kind3Renderer";
+import { Kind0DetailRenderer } from "./nostr/kinds/ProfileDetailRenderer";
+import { Kind3DetailView } from "./nostr/kinds/ContactListRenderer";
import { IssueDetailRenderer } from "./nostr/kinds/IssueDetailRenderer";
import { PatchDetailRenderer } from "./nostr/kinds/PatchDetailRenderer";
import { PullRequestDetailRenderer } from "./nostr/kinds/PullRequestDetailRenderer";
-import { Kind9802DetailRenderer } from "./nostr/kinds/Kind9802DetailRenderer";
-import { Kind10002DetailRenderer } from "./nostr/kinds/Kind10002DetailRenderer";
-import { Kind30023DetailRenderer } from "./nostr/kinds/Kind30023DetailRenderer";
+import { Kind1337DetailRenderer } from "./nostr/kinds/CodeSnippetDetailRenderer";
+import { Kind9802DetailRenderer } from "./nostr/kinds/HighlightDetailRenderer";
+import { Kind10002DetailRenderer } from "./nostr/kinds/RelayListDetailRenderer";
+import { Kind30023DetailRenderer } from "./nostr/kinds/ArticleDetailRenderer";
import { RepositoryDetailRenderer } from "./nostr/kinds/RepositoryDetailRenderer";
import { JsonViewer } from "./JsonViewer";
import { RelayLink } from "./nostr/RelayLink";
@@ -269,6 +270,8 @@ export function EventDetailViewer({ pointer }: EventDetailViewerProps) {
) : event.kind === kinds.Contacts ? (
+ ) : event.kind === 1337 ? (
+
) : event.kind === 1617 ? (
) : event.kind === 1618 ? (
diff --git a/src/components/JsonViewer.tsx b/src/components/JsonViewer.tsx
index 9641f3a..c3d4a54 100644
--- a/src/components/JsonViewer.tsx
+++ b/src/components/JsonViewer.tsx
@@ -1,12 +1,12 @@
-import { CopyCheck, Copy } from "lucide-react";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
-import { Button } from "@/components/ui/button";
import { useCopy } from "../hooks/useCopy";
+import { CodeCopyButton } from "@/components/CodeCopyButton";
+import { SyntaxHighlight } from "@/components/SyntaxHighlight";
interface JsonViewerProps {
data: any;
@@ -31,27 +31,21 @@ export function JsonViewer({
return (