Skip to content

Commit 1d8988e

Browse files
authored
Add Samples Gallery Page (#63)
* Added card for DocumentDB Samples * Created a website page for documentdb samples * Remove .claude from tracking and fix .gitignore
1 parent 7096cc2 commit 1d8988e

File tree

14 files changed

+702
-129
lines changed

14 files changed

+702
-129
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,6 @@ yarn-error.log*
4848

4949
# typescript
5050
*.tsbuildinfo
51-
next-env.d.ts
51+
next-env.d.ts
52+
53+
.claude/

app/components/Navbar.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ export default function Navbar() {
8787
>
8888
Blogs
8989
</Link>
90+
<Link
91+
href="/samples"
92+
className="text-gray-300 hover:text-blue-400 transition-colors duration-200 font-medium"
93+
>
94+
Samples
95+
</Link>
9096
</div>
9197
</div>
9298
</div>

app/components/SampleCard.tsx

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { Sample } from '../types/Sample';
2+
import { TagPill } from './TagPill';
3+
4+
const languageIcons: Record<string, string> = {
5+
'Node.js': '⬡',
6+
Python: '🐍',
7+
TypeScript: '𝗧𝗦',
8+
Go: '◉',
9+
Java: '☕',
10+
'C#': '♯',
11+
Rust: '⚙',
12+
};
13+
14+
const languageColors: Record<string, string> = {
15+
'Node.js': 'from-green-500 to-green-600',
16+
Python: 'from-blue-500 to-yellow-500',
17+
TypeScript: 'from-blue-500 to-blue-600',
18+
Go: 'from-cyan-500 to-cyan-600',
19+
Java: 'from-orange-500 to-red-500',
20+
'C#': 'from-purple-500 to-purple-600',
21+
Rust: 'from-orange-600 to-red-700',
22+
};
23+
24+
export function SampleCard({ sample }: { sample: Sample }) {
25+
const gradient = languageColors[sample.language] ?? 'from-neutral-500 to-neutral-600';
26+
const icon = languageIcons[sample.language] ?? '◈';
27+
28+
return (
29+
<article className="group relative flex flex-col h-full">
30+
<div className="absolute inset-0 bg-gradient-to-r from-purple-500/10 to-teal-500/10 rounded-2xl blur-xl opacity-0 group-hover:opacity-100 transition-all duration-500"></div>
31+
<div className="relative flex flex-col h-full bg-neutral-800/80 backdrop-blur-sm rounded-2xl border border-neutral-700/50 hover:border-purple-500/40 transition-all duration-300 overflow-hidden">
32+
<div className="p-6 flex flex-col flex-1">
33+
{/* Header */}
34+
<div className="flex items-start justify-between mb-4">
35+
<div className="flex items-center gap-3">
36+
<div className={`w-9 h-9 bg-gradient-to-br ${gradient} rounded-lg flex items-center justify-center text-white text-sm font-bold shrink-0`}>
37+
{icon}
38+
</div>
39+
<div>
40+
<span className="text-teal-400 text-xs font-medium">{sample.language}</span>
41+
<p className="text-gray-500 text-xs">{sample.industry}</p>
42+
</div>
43+
</div>
44+
<TagPill tag={sample.difficulty} variant="difficulty" />
45+
</div>
46+
47+
{/* Title */}
48+
<h2 className="text-base font-bold text-white mb-2 group-hover:text-purple-300 transition-colors leading-snug">
49+
{sample.title}
50+
</h2>
51+
52+
{/* Description */}
53+
<p className="text-gray-400 text-sm leading-relaxed mb-4 flex-1">
54+
{sample.description}
55+
</p>
56+
57+
{/* Tags */}
58+
<div className="flex flex-wrap gap-1.5 mb-5">
59+
{sample.tags.map((tag) => (
60+
<TagPill key={tag} tag={tag} variant="default" />
61+
))}
62+
</div>
63+
64+
{/* CTA */}
65+
<a
66+
href={sample.githubUrl}
67+
target="_blank"
68+
rel="noopener noreferrer"
69+
className="inline-flex items-center text-teal-400 hover:text-teal-300 transition-colors font-medium text-sm mt-auto"
70+
>
71+
View on GitHub
72+
<svg
73+
className="w-3.5 h-3.5 ml-1.5 group-hover:translate-x-1 transition-transform"
74+
fill="none"
75+
stroke="currentColor"
76+
viewBox="0 0 24 24"
77+
>
78+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
79+
</svg>
80+
</a>
81+
</div>
82+
</div>
83+
</article>
84+
);
85+
}

app/components/TagPill.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
interface TagPillProps {
2+
tag: string;
3+
variant?: 'default' | 'active' | 'language' | 'difficulty';
4+
onClick?: () => void;
5+
}
6+
7+
const difficultyColors: Record<string, string> = {
8+
Beginner: 'bg-green-500/20 text-green-400 border-green-500/30',
9+
Intermediate: 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30',
10+
Advanced: 'bg-red-500/20 text-red-400 border-red-500/30',
11+
};
12+
13+
const defaultStyle = 'bg-neutral-700/50 text-gray-400 border-neutral-600/50';
14+
15+
export function TagPill({ tag, variant = 'default', onClick }: TagPillProps) {
16+
const base = 'inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium border transition-colors duration-150';
17+
18+
const styles: Record<string, string> = {
19+
default: defaultStyle,
20+
active: 'bg-purple-500/20 text-purple-300 border-purple-500/40',
21+
language: 'bg-teal-500/15 text-teal-400 border-teal-500/30',
22+
difficulty: difficultyColors[tag] ?? defaultStyle,
23+
};
24+
25+
return (
26+
<span
27+
className={`${base} ${styles[variant]} ${onClick ? 'cursor-pointer hover:opacity-80' : ''}`}
28+
onClick={onClick}
29+
>
30+
{tag}
31+
</span>
32+
);
33+
}

app/data/samples.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// This file is auto-generated by scripts/compile-samples.tsx — do not edit manually.
2+
// To add or update samples, open a PR to: https://github.com/documentdb/documentdb-samples-gallery
3+
import { Sample } from '../types/Sample';
4+
5+
export const samples: Sample[] = [
6+
{
7+
id: 'book-finder-js',
8+
title: 'BookFinder: AI-Powered Semantic Book Discovery',
9+
description: 'A Node.js/Express app that uses OpenAI embeddings and DocumentDB vector search to let users discover books through natural language queries like \'dystopian future with rebellion\'.',
10+
language: 'Node.js',
11+
industry: 'AI/ML',
12+
difficulty: 'Intermediate',
13+
tags: ['Vector Search', 'OpenAI', 'Embeddings', 'Express', 'Semantic Search'],
14+
githubUrl: 'https://github.com/documentdb/documentdb-samples-gallery/tree/main/book-finder-js',
15+
}
16+
];

app/docs/page.tsx

Lines changed: 12 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -52,46 +52,17 @@ export default function Docs() {
5252
{/* Documentation Grid */}
5353
<div className="grid grid-cols-2 gap-6 max-w-2xl mx-auto">
5454
{articleContent.landing.links.map((item) => {
55+
const isExternal = item.link.startsWith("http");
5556
const isReference = item.link === "/docs/reference";
56-
57-
if (isReference) {
58-
return (
59-
<Link
60-
key={item.link}
61-
href={item.link}
62-
className="group relative cursor-pointer"
63-
>
64-
<div className="absolute inset-0 bg-gradient-to-r from-blue-500/20 to-cyan-500/20 rounded-lg blur-md group-hover:blur-lg transition-all duration-500 opacity-0 group-hover:opacity-100"></div>
65-
<div className="relative bg-neutral-800/80 backdrop-blur-sm rounded-lg border border-neutral-700/50 hover:border-blue-500/50 transition-all duration-500 group-hover:transform group-hover:scale-105 overflow-hidden h-40">
66-
<div className="p-4 h-full flex flex-col items-center justify-center text-center">
67-
<div className="w-10 h-10 bg-neutral-700/60 backdrop-blur-sm rounded-lg flex items-center justify-center mb-3 border border-neutral-600/30">
68-
<svg
69-
className="w-5 h-5 text-blue-400"
70-
fill="none"
71-
stroke="currentColor"
72-
viewBox="0 0 24 24"
73-
>
74-
<path
75-
strokeLinecap="round"
76-
strokeLinejoin="round"
77-
strokeWidth={2}
78-
d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"
79-
/>
80-
</svg>
81-
</div>
82-
<h2 className="text-sm font-medium text-white group-hover:text-blue-300 transition-colors leading-tight">
83-
{item.title}
84-
</h2>
85-
</div>
86-
</div>
87-
</Link>
88-
);
89-
}
57+
const Wrapper = isExternal ? "a" : Link;
58+
const wrapperProps = isExternal
59+
? { href: item.link, target: "_blank", rel: "noopener noreferrer" }
60+
: { href: item.link };
9061

9162
return (
92-
<Link
63+
<Wrapper
9364
key={item.link}
94-
href={item.link}
65+
{...(wrapperProps as any)}
9566
className="group relative cursor-pointer"
9667
>
9768
<div className="absolute inset-0 bg-gradient-to-r from-blue-500/20 to-cyan-500/20 rounded-lg blur-md group-hover:blur-lg transition-all duration-500 opacity-0 group-hover:opacity-100"></div>
@@ -108,7 +79,10 @@ export default function Docs() {
10879
strokeLinecap="round"
10980
strokeLinejoin="round"
11081
strokeWidth={2}
111-
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.746 0 3.332.477 4.5 1.253v13C19.832 18.477 18.246 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"
82+
d={isReference
83+
? "M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"
84+
: "M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.746 0 3.332.477 4.5 1.253v13C19.832 18.477 18.246 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"
85+
}
11286
/>
11387
</svg>
11488
</div>
@@ -117,7 +91,7 @@ export default function Docs() {
11791
</h2>
11892
</div>
11993
</div>
120-
</Link>
94+
</Wrapper>
12195
);
12296
})}
12397
</div>

0 commit comments

Comments
 (0)