Skip to content

Commit d9c7f91

Browse files
committed
feat: add projects page, update home with product links, fix dark theme tags
- Add /projects page showing all 6 products with GitHub/PyPI links - Home page now features only HashPrep (Beta) and FuzzyBunny (Live) - Add Projects nav link between Home and Blog - Fix dark theme tag readability with dedicated tag CSS variables - Add card accent stripes and product link sections
1 parent d0b7c46 commit d9c7f91

7 files changed

Lines changed: 278 additions & 60 deletions

File tree

src/App.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
1010
const routes = {
1111
"/": () => import("./pages/Home.svelte"),
12+
"/projects": () => import("./pages/Projects.svelte"),
1213
"/blog": () => import("./pages/Blog.svelte"),
1314
};
1415

src/components/BlogCard.svelte

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,24 @@
1111
</script>
1212

1313
<a href="/blog/{slug}" class="card">
14-
<div class="meta">
15-
<span class="category">{category}</span>
16-
<span class="date">{formatDate(date)}</span>
14+
<div class="card-accent"></div>
15+
<div class="card-body">
16+
<div class="meta">
17+
<span class="category">{category}</span>
18+
<span class="date">{formatDate(date)}</span>
19+
</div>
20+
<h3 class="title">{title}</h3>
21+
<p class="excerpt">{excerpt}</p>
22+
<span class="read-more">Read more &rarr;</span>
1723
</div>
18-
<h3 class="title">{title}</h3>
19-
<p class="excerpt">{excerpt}</p>
20-
<span class="read-more">Read more &rarr;</span>
2124
</a>
2225

2326
<style>
2427
.card {
2528
display: flex;
26-
flex-direction: column;
27-
gap: 10px;
29+
overflow: hidden;
2830
background-color: var(--bg-primary);
2931
border: var(--border-width) solid var(--border-default);
30-
padding: 24px;
3132
transition: border-color 0.15s ease;
3233
text-decoration: none;
3334
color: inherit;
@@ -37,6 +38,21 @@
3738
border-color: var(--border-hover);
3839
}
3940
41+
.card-accent {
42+
width: 4px;
43+
flex-shrink: 0;
44+
background-color: var(--text-primary);
45+
}
46+
47+
.card-body {
48+
display: flex;
49+
flex-direction: column;
50+
gap: 10px;
51+
padding: 24px;
52+
flex: 1;
53+
min-width: 0;
54+
}
55+
4056
.meta {
4157
display: flex;
4258
align-items: center;

src/components/Navbar.svelte

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
77
const links = [
88
{ href: "/", label: "Home" },
9+
{ href: "/projects", label: "Projects" },
910
{ href: "/blog", label: "Blog" },
1011
];
1112
@@ -27,7 +28,7 @@
2728
<a
2829
href={link.href}
2930
class="nav-link"
30-
class:active={currentPath === link.href || (link.href === "/blog" && currentPath.startsWith("/blog"))}
31+
class:active={currentPath === link.href || (link.href === "/blog" && currentPath.startsWith("/blog")) || (link.href === "/projects" && currentPath.startsWith("/projects"))}
3132
>
3233
{link.label}
3334
</a>
@@ -64,7 +65,7 @@
6465
<a
6566
href={link.href}
6667
class="mobile-link"
67-
class:active={currentPath === link.href || (link.href === "/blog" && currentPath.startsWith("/blog"))}
68+
class:active={currentPath === link.href || (link.href === "/blog" && currentPath.startsWith("/blog")) || (link.href === "/projects" && currentPath.startsWith("/projects"))}
6869
onclick={closeMobile}
6970
>
7071
{link.label}

src/components/ProductCard.svelte

Lines changed: 77 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,63 @@
11
<script>
2-
let { name, description, status, features = [] } = $props();
2+
let { name, description, status, features = [], links = {} } = $props();
33
</script>
44

55
<article class="card">
6-
<div class="header">
7-
<h3 class="name">{name}</h3>
8-
<span class="status">{status}</span>
6+
<div class="card-accent"></div>
7+
<div class="card-body">
8+
<div class="header">
9+
<h3 class="name">{name}</h3>
10+
<span class="status" class:status-live={status === "Live"} class:status-beta={status === "Beta"}>{status}</span>
11+
</div>
12+
<p class="description">{description}</p>
13+
{#if features.length > 0}
14+
<ul class="features">
15+
{#each features as feature}
16+
<li>{feature}</li>
17+
{/each}
18+
</ul>
19+
{/if}
20+
{#if Object.keys(links).length > 0}
21+
<div class="card-links">
22+
{#if links.website}
23+
<a href={links.website} target="_blank" rel="noopener noreferrer" class="card-link">{links.website.replace("https://", "")}</a>
24+
{/if}
25+
{#if links.pypi}
26+
<a href={links.pypi} target="_blank" rel="noopener noreferrer" class="card-link">PyPI</a>
27+
{/if}
28+
{#if links.github}
29+
<a href={links.github} target="_blank" rel="noopener noreferrer" class="card-link">GitHub</a>
30+
{/if}
31+
</div>
32+
{/if}
933
</div>
10-
<p class="description">{description}</p>
11-
{#if features.length > 0}
12-
<ul class="features">
13-
{#each features as feature}
14-
<li>{feature}</li>
15-
{/each}
16-
</ul>
17-
{/if}
1834
</article>
1935

2036
<style>
2137
.card {
2238
background-color: var(--bg-primary);
2339
border: var(--border-width) solid var(--border-default);
24-
padding: 28px;
2540
transition: border-color 0.15s ease;
41+
display: flex;
42+
overflow: hidden;
2643
}
2744
2845
.card:hover {
2946
border-color: var(--border-hover);
3047
}
3148
49+
.card-accent {
50+
width: 4px;
51+
flex-shrink: 0;
52+
background-color: var(--text-primary);
53+
}
54+
55+
.card-body {
56+
padding: 28px;
57+
flex: 1;
58+
min-width: 0;
59+
}
60+
3261
.header {
3362
display: flex;
3463
align-items: center;
@@ -49,12 +78,22 @@
4978
text-transform: uppercase;
5079
letter-spacing: 0.06em;
5180
padding: 3px 8px;
52-
border: var(--border-width) solid var(--border-default);
53-
color: var(--text-muted);
81+
border: var(--border-width) solid var(--tag-border);
82+
color: var(--tag-text);
5483
white-space: nowrap;
5584
line-height: 1.4;
5685
}
5786
87+
.status-live {
88+
border-color: var(--accent);
89+
color: var(--accent);
90+
}
91+
92+
.status-beta {
93+
border-color: var(--accent);
94+
color: var(--accent);
95+
}
96+
5897
.description {
5998
font-size: 0.9375rem;
6099
color: var(--text-secondary);
@@ -70,10 +109,31 @@
70109
71110
.features li {
72111
font-size: 0.8125rem;
73-
color: var(--text-muted);
112+
color: var(--tag-text);
74113
padding: 4px 10px;
75114
background-color: var(--bg-surface);
76-
border: 1px solid var(--border-default);
115+
border: 1px solid var(--tag-border);
77116
font-weight: 500;
78117
}
118+
119+
.card-links {
120+
display: flex;
121+
flex-wrap: wrap;
122+
gap: 12px;
123+
margin-top: 16px;
124+
padding-top: 16px;
125+
border-top: 1px solid var(--border-default);
126+
}
127+
128+
.card-link {
129+
font-size: 0.8125rem;
130+
font-weight: 500;
131+
color: var(--accent);
132+
text-decoration: none;
133+
transition: color 0.15s ease;
134+
}
135+
136+
.card-link:hover {
137+
color: var(--accent-hover);
138+
}
79139
</style>

src/pages/Home.svelte

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,23 @@
88
{
99
name: "HashPrep",
1010
description: "Intelligent dataset debugging and preparation platform that catches critical data quality issues before they derail your ML pipeline.",
11-
status: "Under Dev",
11+
status: "Beta",
1212
features: ["Smart Detection", "Auto-Fix Suggestions", "Comprehensive Profiling", "Pipeline Integration"],
13+
links: {
14+
website: "https://hashprep.com",
15+
pypi: "https://pypi.org/project/hashprep/",
16+
github: "https://github.com/cachevector/hashprep",
17+
},
1318
},
1419
{
1520
name: "FuzzyBunny",
1621
description: "High-performance string matching engine with C++ SIMD optimization and Pybind11 bindings for Python runtimes.",
1722
status: "Live",
1823
features: ["Levenshtein Optimization", "Token-Based Similarity", "Hybrid Scoring", "Unicode Support"],
19-
},
20-
{
21-
name: "Noise2Normal",
22-
description: "Statistical image restoration using Central Limit Theorem convergence for noise-free reconstruction without neural networks.",
23-
status: "Research",
24-
features: ["CLT-Based Denoising", "OpenCV Integration"],
25-
},
26-
{
27-
name: "Comprexx",
28-
description: "Modern compression engineering exploring entropy coding, dictionary methods, and asymmetric numeral systems.",
29-
status: "Research",
30-
features: ["Huffman Coding", "LZ77", "ANS Analysis"],
31-
},
32-
{
33-
name: "TokenWise",
34-
description: "Efficient binary data serialization with length-prefixed protocols designed for high-throughput systems.",
35-
status: "Research",
36-
features: ["TOON Format", "Zero-Copy Reads"],
37-
},
38-
{
39-
name: "MCPI",
40-
description: "Monte Carlo probabilistic computing experiments exploring random sampling methods and convergence analysis.",
41-
status: "Research",
42-
features: ["Mersenne Twister PRNG", "Convergence Visualization"],
24+
links: {
25+
pypi: "https://pypi.org/project/fuzzybunny/",
26+
github: "https://github.com/cachevector/fuzzybunny",
27+
},
4328
},
4429
];
4530
@@ -82,6 +67,9 @@
8267
<ProductCard {...product} />
8368
{/each}
8469
</div>
70+
<div class="view-all-projects">
71+
<a href="/projects">View all projects &rarr;</a>
72+
</div>
8573
</section>
8674

8775
<section class="section">
@@ -92,8 +80,11 @@
9280
<div class="mission-grid">
9381
{#each mission as item}
9482
<article class="mission-card">
95-
<h3>{item.title}</h3>
96-
<p>{item.text}</p>
83+
<div class="mission-accent"></div>
84+
<div class="mission-body">
85+
<h3>{item.title}</h3>
86+
<p>{item.text}</p>
87+
</div>
9788
</article>
9889
{/each}
9990
</div>
@@ -154,14 +145,27 @@
154145
.mission-card {
155146
background-color: var(--bg-primary);
156147
border: var(--border-width) solid var(--border-default);
157-
padding: 24px;
148+
display: flex;
149+
overflow: hidden;
158150
transition: border-color 0.15s ease;
159151
}
160152
161153
.mission-card:hover {
162154
border-color: var(--border-hover);
163155
}
164156
157+
.mission-accent {
158+
width: 4px;
159+
flex-shrink: 0;
160+
background-color: var(--text-primary);
161+
}
162+
163+
.mission-body {
164+
padding: 24px;
165+
flex: 1;
166+
min-width: 0;
167+
}
168+
165169
.mission-card h3 {
166170
font-family: var(--font-heading);
167171
font-weight: 600;
@@ -204,6 +208,23 @@
204208
color: var(--accent-hover);
205209
}
206210
211+
.view-all-projects {
212+
margin-top: 24px;
213+
text-align: center;
214+
}
215+
216+
.view-all-projects a {
217+
font-weight: 500;
218+
font-size: 0.9375rem;
219+
color: var(--accent);
220+
text-decoration: none;
221+
transition: color 0.15s ease;
222+
}
223+
224+
.view-all-projects a:hover {
225+
color: var(--accent-hover);
226+
}
227+
207228
@media (min-width: 641px) {
208229
.section {
209230
padding: 80px 0;
@@ -223,10 +244,6 @@
223244
}
224245
225246
@media (min-width: 1025px) {
226-
.product-grid {
227-
grid-template-columns: repeat(3, 1fr);
228-
}
229-
230247
.blog-grid {
231248
grid-template-columns: repeat(3, 1fr);
232249
}

0 commit comments

Comments
 (0)