Skip to content

Commit a8a2422

Browse files
erudenkoclaude
andcommitted
feat(landing): Add manifesto page with full markdown rendering
- Created /manifesto route rendering MANIFESTO.md content - Modified left bottom panel to show manifesto excerpt and link - Added comprehensive markdown styling (headings, code, tables, quotes, lists) - Used is:global styles for dynamically injected HTML - Implemented sticky navigation with links to home and GitHub - Added CTA section at bottom with GitHub star and examples links - Server-side rendered with no client-side JavaScript 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 7411228 commit a8a2422

2 files changed

Lines changed: 425 additions & 45 deletions

File tree

langingpage/src/components/react/App.tsx

Lines changed: 63 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import { useState, useEffect } from 'react';
1+
import { useState } from 'react';
22
import { ChevronDown, ChevronRight } from 'lucide-react';
33
import { CodeComparison } from './CodeComparison';
44
import logoImage from '../../assets/dingo-logo.png';
55
import ReactMarkdown from 'react-markdown';
66
import remarkGfm from 'remark-gfm';
7+
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
8+
import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism';
79

810
interface Example {
911
id: number;
@@ -17,6 +19,7 @@ interface Example {
1719
summary?: string;
1820
complexity?: string;
1921
order?: number;
22+
reasoning?: string;
2023
}
2124

2225
interface AppProps {
@@ -57,7 +60,6 @@ function groupExamples(examples: Example[]) {
5760

5861
export default function App({ examples }: AppProps) {
5962
const [selectedId, setSelectedId] = useState(1);
60-
const [readmeContent, setReadmeContent] = useState('');
6163

6264
const groupedExamples = groupExamples(examples);
6365

@@ -80,30 +82,6 @@ export default function App({ examples }: AppProps) {
8082
});
8183
};
8284

83-
// Step 1: Define difficulty colors object for full button backgrounds
84-
const difficultyColors = {
85-
basic: {
86-
bg: 'bg-green-50',
87-
text: 'text-green-700',
88-
},
89-
intermediate: {
90-
bg: 'bg-amber-50',
91-
text: 'text-amber-700',
92-
},
93-
advanced: {
94-
bg: 'bg-red-50',
95-
text: 'text-red-700',
96-
},
97-
};
98-
99-
// Fetch README.md content
100-
useEffect(() => {
101-
fetch('https://raw.githubusercontent.com/MadAppGang/dingo/refs/heads/main/README.md')
102-
.then(response => response.text())
103-
.then(data => setReadmeContent(data))
104-
.catch(error => console.error('Error fetching README:', error));
105-
}, []);
106-
10785
return (
10886
<div className="flex h-screen bg-white">
10987
{/* Sidebar */}
@@ -153,10 +131,6 @@ export default function App({ examples }: AppProps) {
153131
>
154132
<div className="space-y-1 pl-2">
155133
{categoryExamples.map((example) => {
156-
// Step 4: Use difficultyColors object for full button background
157-
const colors = example.complexity
158-
? difficultyColors[example.complexity as keyof typeof difficultyColors]
159-
: undefined;
160134
const isSelected = selectedId === example.id;
161135

162136
// Build complete class name for Tailwind (dynamic classes don't work)
@@ -199,14 +173,25 @@ export default function App({ examples }: AppProps) {
199173
})}
200174
</nav>
201175

202-
{/* Description section */}
203-
<div className="p-6 border-t border-gray-200 bg-gray-50">
204-
<h3 className="text-gray-900 mb-2 text-sm">About This Tool</h3>
176+
{/* Manifesto excerpt section */}
177+
<a
178+
href="/manifesto"
179+
className="block p-6 border-t border-gray-200 bg-gradient-to-br from-blue-50 to-indigo-50 hover:from-blue-100 hover:to-indigo-100 transition-all cursor-pointer group"
180+
>
181+
<div className="flex items-start justify-between mb-2">
182+
<h3 className="text-gray-900 text-sm font-semibold">The Dingo Manifesto</h3>
183+
<span className="text-blue-600 text-xs group-hover:translate-x-1 transition-transform"></span>
184+
</div>
185+
<p className="text-gray-700 text-xs leading-relaxed mb-3 italic">
186+
"Go Broke Free. Are You Ready?"
187+
</p>
205188
<p className="text-gray-600 text-xs leading-relaxed">
206-
Compare code examples side by side to understand best practices and modern patterns.
207-
Each example shows the transformation from older or less optimal code to improved implementations.
189+
You love Go. But you've typed <code className="bg-white px-1 py-0.5 rounded text-xs">if err != nil</code> for the 47th time and thought: "There has to be a better way."
208190
</p>
209-
</div>
191+
<p className="text-blue-600 text-xs mt-3 font-medium group-hover:underline">
192+
Read the full manifesto →
193+
</p>
194+
</a>
210195
</div>
211196

212197
{/* Main Content */}
@@ -219,11 +204,11 @@ export default function App({ examples }: AppProps) {
219204
language={selectedExample.language}
220205
/>
221206

222-
{/* Description of the change */}
207+
{/* Reasoning content for this example */}
223208
<div className="p-8 bg-white">
224209
<div className="max-w-4xl mx-auto markdown-content">
225-
{readmeContent ? (
226-
<ReactMarkdown
210+
{selectedExample.reasoning || selectedExample.description ? (
211+
<ReactMarkdown
227212
remarkPlugins={[remarkGfm]}
228213
components={{
229214
h1: ({node, ...props}) => <h1 className="mt-4 mb-2 text-sm" {...props} />,
@@ -234,10 +219,43 @@ export default function App({ examples }: AppProps) {
234219
ul: ({node, ...props}) => <ul className="mb-2 ml-4 list-disc text-gray-700 text-xs" {...props} />,
235220
ol: ({node, ...props}) => <ol className="mb-2 ml-4 list-decimal text-gray-700 text-xs" {...props} />,
236221
li: ({node, ...props}) => <li className="mb-1 text-xs" {...props} />,
237-
code: ({node, inline, ...props}) =>
238-
inline
239-
? <code className="bg-gray-100 px-1 py-0.5 rounded text-xs text-gray-800" {...props} />
240-
: <code className="block bg-gray-100 p-2 rounded text-xs overflow-x-auto" {...props} />,
222+
code: ({node, className, children, ...props}: any) => {
223+
const inline = !className;
224+
const match = /language-(\w+)/.exec(className || '');
225+
const language = match ? match[1] : '';
226+
227+
if (!inline && language) {
228+
// Block code with language - use syntax highlighter
229+
return (
230+
<SyntaxHighlighter
231+
language={language === 'dingo' ? 'go' : language}
232+
style={vscDarkPlus}
233+
customStyle={{
234+
margin: '0.5rem 0',
235+
padding: '1rem',
236+
borderRadius: '0.375rem',
237+
fontSize: '0.75rem',
238+
lineHeight: '1.5',
239+
}}
240+
showLineNumbers={false}
241+
PreTag="div"
242+
>
243+
{String(children).replace(/\n$/, '')}
244+
</SyntaxHighlighter>
245+
);
246+
}
247+
248+
// Inline code or code without language
249+
return inline ? (
250+
<code className="inline-block bg-gray-100 px-1 py-0.5 rounded text-xs text-gray-800" {...props}>
251+
{children}
252+
</code>
253+
) : (
254+
<code className="bg-gray-100 p-2 rounded text-xs overflow-x-auto block" {...props}>
255+
{children}
256+
</code>
257+
);
258+
},
241259
pre: ({node, ...props}) => <pre className="mb-2 bg-gray-100 p-2 rounded overflow-x-auto text-xs" {...props} />,
242260
a: ({node, ...props}) => <a className="text-blue-600 hover:underline text-xs" {...props} />,
243261
blockquote: ({node, ...props}) => <blockquote className="border-l-4 border-gray-300 pl-3 italic text-gray-600 mb-2 text-xs" {...props} />,
@@ -251,10 +269,10 @@ export default function App({ examples }: AppProps) {
251269
td: ({node, ...props}) => <td className="px-2 py-1 text-gray-700 text-xs" {...props} />,
252270
}}
253271
>
254-
{readmeContent}
272+
{selectedExample.reasoning || selectedExample.description}
255273
</ReactMarkdown>
256274
) : (
257-
<p className="text-gray-500">Loading README...</p>
275+
<p className="text-gray-500 text-xs">No reasoning documentation available for this example.</p>
258276
)}
259277
</div>
260278
</div>

0 commit comments

Comments
 (0)