Skip to content

Commit b89ca43

Browse files
Strawbangclaude
andcommitted
Fix favicon, canonical, OG tags, mobile nav, releases skeleton, team avatar
- Layout: fix favicon refs (ico+svg), dynamic canonical per page, twitter:card → summary_large_image, correct OG image dimensions - Nav: hamburger menu on mobile with animated icon and overlay - Releases: skeleton loader while fetching, graceful empty state, always visible (no display:none flash) - Team: photo as 64px circular avatar instead of full-width square Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 3559e5b commit b89ca43

4 files changed

Lines changed: 146 additions & 36 deletions

File tree

src/components/Nav.astro

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
<nav id="nav">
55
<a href="/" class="nav-logo">rustkit<span>.</span>ai</a>
6-
<ul class="nav-links">
6+
<ul class="nav-links" id="nav-links">
77
<li><a href="/#projects">Projects</a></li>
88
<li><a href="/team">Team</a></li>
99
<li>
@@ -15,6 +15,9 @@
1515
</a>
1616
</li>
1717
</ul>
18+
<button class="hamburger" id="hamburger" aria-label="Toggle menu" aria-expanded="false">
19+
<span></span><span></span><span></span>
20+
</button>
1821
</nav>
1922

2023
<style>
@@ -80,9 +83,66 @@
8083

8184
.nav-gh:hover { background: var(--rust-glow); }
8285

86+
.hamburger {
87+
display: none;
88+
flex-direction: column;
89+
justify-content: center;
90+
gap: 5px;
91+
background: none;
92+
border: none;
93+
cursor: pointer;
94+
padding: 0.25rem;
95+
}
96+
97+
.hamburger span {
98+
display: block;
99+
width: 20px;
100+
height: 1.5px;
101+
background: var(--text-muted);
102+
transition: transform 0.25s ease, opacity 0.25s ease;
103+
}
104+
105+
.hamburger.open span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
106+
.hamburger.open span:nth-child(2) { opacity: 0; }
107+
.hamburger.open span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }
108+
83109
@media (max-width: 640px) {
84110
nav { padding: 1rem 1.25rem; }
85-
.nav-links { display: none; }
111+
112+
.hamburger { display: flex; }
113+
114+
.nav-links {
115+
display: none;
116+
position: fixed;
117+
top: 57px;
118+
left: 0;
119+
right: 0;
120+
background: rgba(14, 13, 12, 0.97);
121+
backdrop-filter: blur(12px);
122+
border-bottom: 1px solid var(--border);
123+
flex-direction: column;
124+
gap: 0;
125+
padding: 0.5rem 0;
126+
}
127+
128+
.nav-links.open { display: flex; }
129+
130+
.nav-links li { width: 100%; }
131+
132+
.nav-links a {
133+
display: block;
134+
padding: 0.9rem 1.25rem;
135+
border-bottom: 1px solid var(--border);
136+
font-size: 0.9rem;
137+
}
138+
139+
.nav-links li:last-child a { border-bottom: none; }
140+
141+
.nav-gh {
142+
border: none !important;
143+
border-radius: 0 !important;
144+
padding: 0.9rem 1.25rem !important;
145+
}
86146
}
87147
</style>
88148

@@ -91,4 +151,21 @@
91151
window.addEventListener('scroll', () => {
92152
nav?.classList.toggle('scrolled', window.scrollY > 40);
93153
}, { passive: true });
154+
155+
const hamburger = document.getElementById('hamburger');
156+
const navLinks = document.getElementById('nav-links');
157+
158+
hamburger?.addEventListener('click', () => {
159+
const open = hamburger.classList.toggle('open');
160+
hamburger.setAttribute('aria-expanded', String(open));
161+
navLinks?.classList.toggle('open', open);
162+
});
163+
164+
navLinks?.querySelectorAll('a').forEach((a) => {
165+
a.addEventListener('click', () => {
166+
hamburger?.classList.remove('open');
167+
hamburger?.setAttribute('aria-expanded', 'false');
168+
navLinks.classList.remove('open');
169+
});
170+
});
94171
</script>

src/components/Releases.astro

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ import { projects } from '../data/projects';
44
const releaseProjects = projects.filter((p) => p.hasReleases);
55
---
66

7-
<section id="releases" style="display:none">
7+
<section id="releases">
88
<div class="section-inner">
99
<div class="section-label reveal">Changelog</div>
1010
<h2 class="reveal">Latest releases</h2>
1111
<p class="section-sub reveal">Recent updates across our open source projects.</p>
1212

13-
<div class="releases-list reveal" id="releases-list"></div>
13+
<div class="releases-list reveal" id="releases-list">
14+
<div class="skeleton-item"><div class="sk sk-tag"></div><div class="sk sk-name"></div><div class="sk sk-date"></div></div>
15+
<div class="skeleton-item"><div class="sk sk-tag"></div><div class="sk sk-name"></div><div class="sk sk-date"></div></div>
16+
</div>
1417

1518
<div class="all-links reveal" id="all-links"></div>
1619
</div>
@@ -42,11 +45,14 @@ const releaseProjects = projects.filter((p) => p.hasReleases);
4245
);
4346

4447
const valid = results.filter(Boolean);
45-
if (valid.length === 0) return;
46-
4748
const list = document.getElementById('releases-list');
4849
const allLinks = document.getElementById('all-links');
4950

51+
if (valid.length === 0) {
52+
list.innerHTML = '<p class="releases-empty">No releases found.</p>';
53+
return;
54+
}
55+
5056
list.innerHTML = valid.map(({ project: p, release: r }) => `
5157
<a href="${r.html_url}" target="_blank" rel="noopener" class="release-item latest">
5258
<div class="release-left">
@@ -66,19 +72,6 @@ const releaseProjects = projects.filter((p) => p.hasReleases);
6672
</a>
6773
`).join('');
6874

69-
const section = document.getElementById('releases');
70-
section.style.display = '';
71-
72-
const observer = new IntersectionObserver((entries) => {
73-
entries.forEach((entry) => {
74-
if (entry.isIntersecting) {
75-
entry.target.classList.add('visible');
76-
observer.unobserve(entry.target);
77-
}
78-
});
79-
}, { threshold: 0.1 });
80-
81-
section.querySelectorAll('.reveal').forEach((el) => observer.observe(el));
8275
}
8376

8477
loadReleases();
@@ -188,6 +181,41 @@ const releaseProjects = projects.filter((p) => p.hasReleases);
188181

189182
#releases .all-releases:hover { color: var(--rust); }
190183

184+
#releases .releases-empty {
185+
font-family: 'IBM Plex Mono', monospace;
186+
font-size: 0.8rem;
187+
color: var(--text-dim);
188+
padding: 1.5rem;
189+
text-align: center;
190+
}
191+
192+
/* Skeleton */
193+
#releases .skeleton-item {
194+
display: flex;
195+
align-items: center;
196+
gap: 1rem;
197+
padding: 1rem 1.5rem;
198+
border-bottom: 1px solid var(--border);
199+
background: var(--bg-2);
200+
}
201+
202+
#releases .skeleton-item:last-child { border-bottom: none; }
203+
204+
#releases .sk {
205+
background: var(--border-hi);
206+
border-radius: 3px;
207+
animation: sk-pulse 1.4s ease-in-out infinite;
208+
}
209+
210+
#releases .sk-tag { width: 60px; height: 14px; }
211+
#releases .sk-name { width: 160px; height: 12px; flex: 1; max-width: 200px; }
212+
#releases .sk-date { width: 80px; height: 12px; margin-left: auto; }
213+
214+
@keyframes sk-pulse {
215+
0%, 100% { opacity: 0.4; }
216+
50% { opacity: 0.8; }
217+
}
218+
191219
@media (max-width: 640px) {
192220
#releases .release-item {
193221
grid-template-columns: auto 1fr auto;

src/layouts/Layout.astro

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ const {
99
description = 'AI-native developer tools, built in Rust. Open source tooling for the next generation of AI-assisted development.',
1010
} = Astro.props;
1111
12-
const canonical = 'https://rustkit-ai.github.io';
13-
const ogImage = `${canonical}/og-image.png`;
12+
const canonical = Astro.url.href;
13+
const ogImage = `https://rustkit-ai.github.io/og-image.png`;
1414
---
1515

1616
<!doctype html>
@@ -21,7 +21,8 @@ const ogImage = `${canonical}/og-image.png`;
2121
<title>{title}</title>
2222
<meta name="description" content={description} />
2323
<link rel="canonical" href={canonical} />
24-
<link rel="icon" type="image/png" href="/og-image.png" />
24+
<link rel="icon" href="/favicon.ico" sizes="any" />
25+
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
2526
<link rel="preconnect" href="https://fonts.googleapis.com" />
2627
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
2728
<link href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=IBM+Plex+Sans:wght@300;400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet" />
@@ -32,12 +33,12 @@ const ogImage = `${canonical}/og-image.png`;
3233
<meta property="og:description" content={description} />
3334
<meta property="og:url" content={canonical} />
3435
<meta property="og:image" content={ogImage} />
35-
<meta property="og:image:width" content="460" />
36-
<meta property="og:image:height" content="460" />
36+
<meta property="og:image:width" content="1200" />
37+
<meta property="og:image:height" content="630" />
3738
<meta property="og:site_name" content="rustkit-ai" />
3839

3940
<!-- Twitter -->
40-
<meta name="twitter:card" content="summary" />
41+
<meta name="twitter:card" content="summary_large_image" />
4142
<meta name="twitter:title" content={title} />
4243
<meta name="twitter:description" content={description} />
4344
<meta name="twitter:image" content={ogImage} />

src/pages/team.astro

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -168,15 +168,27 @@ const founders = [
168168

169169
.founder-card:hover { border-color: var(--rust-dim); }
170170

171+
.card-body {
172+
padding: 1.75rem;
173+
display: flex;
174+
flex-direction: column;
175+
gap: 0.5rem;
176+
flex: 1;
177+
}
178+
171179
.card-photo {
172-
width: 100%;
173-
aspect-ratio: 1 / 1;
180+
width: 64px;
181+
height: 64px;
182+
border-radius: 50%;
174183
overflow: hidden;
175184
background: var(--bg-3);
185+
border: 2px solid var(--border-hi);
176186
position: relative;
177187
display: flex;
178188
align-items: center;
179189
justify-content: center;
190+
flex-shrink: 0;
191+
margin-bottom: 0.75rem;
180192
}
181193

182194
.card-photo img {
@@ -194,19 +206,11 @@ const founders = [
194206
align-items: center;
195207
justify-content: center;
196208
font-family: 'Space Mono', monospace;
197-
font-size: 3rem;
209+
font-size: 1.2rem;
198210
color: var(--rust);
199211
background: var(--bg-3);
200212
}
201213

202-
.card-body {
203-
padding: 1.75rem;
204-
display: flex;
205-
flex-direction: column;
206-
gap: 0.5rem;
207-
flex: 1;
208-
}
209-
210214
.card-meta {
211215
display: flex;
212216
align-items: baseline;

0 commit comments

Comments
 (0)