Skip to content

Commit fdb0f87

Browse files
nullcoderclaude
andauthored
feat: implement GistViewer component (#61) (#84)
* feat: implement GistViewer component (#61) - Add read-only gist viewer with vertical file layout - Support syntax highlighting via CodeEditor in read-only mode - Include copy to clipboard and download functionality per file - Add global settings for line numbers and word wrap - Implement responsive design with mobile-friendly layout - Add comprehensive test suite (12 tests, 100% passing) - Include demo page showcasing all features - Use consistent GitHub-style presentation The component displays multiple files vertically with clear headers, individual action buttons, and proper accessibility support. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * docs: update tracking for completed GistViewer (#61) --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 03dc15c commit fdb0f87

File tree

8 files changed

+777
-20
lines changed

8 files changed

+777
-20
lines changed

app/demo/gist-viewer/page.tsx

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
"use client";
2+
3+
import { GistViewer } from "@/components/gist-viewer";
4+
import type { File } from "@/types";
5+
6+
export default function GistViewerDemo() {
7+
const sampleFiles: File[] = [
8+
{
9+
name: "hello.js",
10+
content: `// A simple JavaScript example
11+
function greet(name) {
12+
return \`Hello, \${name}!\`;
13+
}
14+
15+
console.log(greet("World"));
16+
console.log(greet("GhostPaste"));
17+
18+
// Export for module usage
19+
export { greet };`,
20+
language: "javascript",
21+
},
22+
{
23+
name: "styles.css",
24+
content: `/* Modern CSS Reset */
25+
*, *::before, *::after {
26+
box-sizing: border-box;
27+
}
28+
29+
* {
30+
margin: 0;
31+
}
32+
33+
body {
34+
line-height: 1.5;
35+
-webkit-font-smoothing: antialiased;
36+
}
37+
38+
img, picture, video, canvas, svg {
39+
display: block;
40+
max-width: 100%;
41+
}
42+
43+
input, button, textarea, select {
44+
font: inherit;
45+
}
46+
47+
p, h1, h2, h3, h4, h5, h6 {
48+
overflow-wrap: break-word;
49+
}`,
50+
language: "css",
51+
},
52+
{
53+
name: "index.html",
54+
content: `<!DOCTYPE html>
55+
<html lang="en">
56+
<head>
57+
<meta charset="UTF-8">
58+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
59+
<title>GhostPaste Demo</title>
60+
<link rel="stylesheet" href="styles.css">
61+
</head>
62+
<body>
63+
<div id="app">
64+
<h1>Welcome to GhostPaste</h1>
65+
<p>Share code snippets securely with zero-knowledge encryption.</p>
66+
</div>
67+
<script src="hello.js" type="module"></script>
68+
</body>
69+
</html>`,
70+
language: "html",
71+
},
72+
{
73+
name: "README.md",
74+
content: `# GhostPaste Demo
75+
76+
This is a demo of the GistViewer component.
77+
78+
## Features
79+
80+
- Syntax highlighting for multiple languages
81+
- Tab navigation for multiple files
82+
- Copy to clipboard functionality
83+
- Download files individually or all at once
84+
- Toggle line numbers and word wrap
85+
- Responsive design
86+
87+
## Usage
88+
89+
\`\`\`tsx
90+
import { GistViewer } from "@/components/gist-viewer";
91+
92+
function MyComponent() {
93+
const files = [
94+
{ name: "file.js", content: "code here", language: "javascript" }
95+
];
96+
97+
return <GistViewer files={files} />;
98+
}
99+
\`\`\``,
100+
language: "markdown",
101+
},
102+
];
103+
104+
const manyFiles: File[] = Array.from({ length: 8 }, (_, i) => ({
105+
name: `component-${i + 1}.tsx`,
106+
content: `import React from 'react';
107+
108+
export function Component${i + 1}() {
109+
return (
110+
<div className="component-${i + 1}">
111+
<h2>Component ${i + 1}</h2>
112+
<p>This is component number ${i + 1}</p>
113+
</div>
114+
);
115+
}`,
116+
language: "typescript",
117+
}));
118+
119+
return (
120+
<div className="container mx-auto space-y-12 py-8">
121+
<div>
122+
<h1 className="mb-4 text-3xl font-bold">GistViewer Component Demo</h1>
123+
<p className="text-muted-foreground mb-8">
124+
A read-only viewer for displaying code snippets with syntax
125+
highlighting, file navigation, and download capabilities.
126+
</p>
127+
</div>
128+
129+
<section className="space-y-4">
130+
<h2 className="text-2xl font-semibold">Basic Example (4 files)</h2>
131+
<p className="text-muted-foreground text-sm">
132+
Files are displayed in a vertical layout with individual copy and
133+
download buttons.
134+
</p>
135+
<div className="rounded-lg border p-4">
136+
<GistViewer files={sampleFiles} />
137+
</div>
138+
</section>
139+
140+
<section className="space-y-4">
141+
<h2 className="text-2xl font-semibold">Many Files Example (8 files)</h2>
142+
<p className="text-muted-foreground text-sm">
143+
The vertical layout scales well for any number of files.
144+
</p>
145+
<div className="rounded-lg border p-4">
146+
<GistViewer files={manyFiles} />
147+
</div>
148+
</section>
149+
150+
<section className="space-y-4">
151+
<h2 className="text-2xl font-semibold">Empty State</h2>
152+
<p className="text-muted-foreground text-sm">
153+
When no files are provided, a friendly message is shown.
154+
</p>
155+
<div className="rounded-lg border p-4">
156+
<GistViewer files={[]} />
157+
</div>
158+
</section>
159+
160+
<section className="space-y-4">
161+
<h2 className="text-2xl font-semibold">Features</h2>
162+
<ul className="text-muted-foreground list-inside list-disc space-y-2">
163+
<li>Syntax highlighting powered by CodeMirror</li>
164+
<li>Vertical file layout with clear file headers</li>
165+
<li>Individual copy and download buttons per file</li>
166+
<li>Download all files at once</li>
167+
<li>Toggle line numbers on/off</li>
168+
<li>Toggle word wrap on/off</li>
169+
<li>Responsive design for mobile devices</li>
170+
<li>Dark mode support</li>
171+
<li>Keyboard accessible</li>
172+
<li>Clean, GitHub-style presentation</li>
173+
</ul>
174+
</section>
175+
</div>
176+
);
177+
}

0 commit comments

Comments
 (0)