Skip to content

Commit 15f0808

Browse files
feat: add visual upgrades — trust bar, project showcase, FAQ accordion
Cherry-picked visual improvements from PR #4 redesign while preserving existing discovery-first copy, Firebase infrastructure, and booking CTAs. - TrustBar: animated marquee with correct proof points (1,550+ stars, 270+ plugins, 1,537 skills) - ProjectShowcase: upgraded project grid with gradient borders and scroll-reveal - FAQSection: accessible accordion with real business FAQs - Replaced React Products component with static Astro ProjectShowcase Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent db95365 commit 15f0808

4 files changed

Lines changed: 780 additions & 2 deletions

File tree

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
---
2+
const faqs = [
3+
{
4+
question: 'What exactly is a Claude Code setup?',
5+
answer:
6+
'I configure Claude Code for your specific tech stack, team size, and workflows. This includes custom CLAUDE.md files, curated plugin packs, slash commands, MCP server connections, and hooks—everything tuned so your team gets maximum value from day one.',
7+
},
8+
{
9+
question: 'Do I need to know how to code?',
10+
answer:
11+
'Not at all. The Learn track is specifically designed for decision-makers and team leads. I\'ll show you what Claude Code can do, how it fits your org, and what to watch for—no coding required.',
12+
},
13+
{
14+
question: 'What\'s included in the discovery call?',
15+
answer:
16+
'A 30-minute conversation where I learn about your team, workflows, and goals. I\'ll give honest recommendations on which tier makes sense—or if Claude Code isn\'t the right fit. No pressure, no pitch deck.',
17+
},
18+
{
19+
question: 'Can you work with teams outside the US?',
20+
answer:
21+
'Absolutely. I work with remote teams across all time zones. Sessions are scheduled around your availability, and all training materials are async-friendly.',
22+
},
23+
{
24+
question: 'What happens after the initial setup?',
25+
answer:
26+
'Every tier includes a support window (30–90 days depending on tier). I\'m available for questions, plugin tweaks, and workflow adjustments. Enterprise clients get ongoing retainer relationships with quarterly workshops.',
27+
},
28+
{
29+
question: 'How is this different from just reading the docs?',
30+
answer:
31+
'The docs tell you what buttons to press. I show you how to build systems that make your team faster. Custom plugins, team workflows, CI/CD integration, and training that sticks—things you won\'t find in any documentation.',
32+
},
33+
];
34+
---
35+
36+
<section id="faq" class="faq-section" aria-labelledby="faq-title">
37+
<div class="container">
38+
<h2 id="faq-title" class="section-title">frequently asked questions</h2>
39+
40+
<div class="faq-list" role="list">
41+
{faqs.map((faq, index) => (
42+
<div class="faq-item" role="listitem">
43+
<button
44+
class="faq-trigger"
45+
aria-expanded="false"
46+
aria-controls={`faq-panel-${index}`}
47+
id={`faq-btn-${index}`}
48+
>
49+
<span class="faq-question">{faq.question}</span>
50+
<span class="faq-icon" aria-hidden="true">
51+
<svg class="icon-plus" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
52+
<line x1="10" y1="3" x2="10" y2="17" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
53+
<line x1="3" y1="10" x2="17" y2="10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
54+
</svg>
55+
<svg class="icon-minus" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
56+
<line x1="3" y1="10" x2="17" y2="10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
57+
</svg>
58+
</span>
59+
</button>
60+
61+
<div
62+
class="faq-panel"
63+
id={`faq-panel-${index}`}
64+
role="region"
65+
aria-labelledby={`faq-btn-${index}`}
66+
hidden
67+
>
68+
<div class="faq-answer">
69+
<p>{faq.answer}</p>
70+
</div>
71+
</div>
72+
</div>
73+
))}
74+
</div>
75+
</div>
76+
</section>
77+
78+
<style>
79+
.faq-section {
80+
padding: 6rem 0;
81+
background: rgb(9 9 11); /* zinc-950 */
82+
}
83+
84+
.container {
85+
max-width: 48rem;
86+
margin: 0 auto;
87+
padding: 0 2rem;
88+
}
89+
90+
.section-title {
91+
font-size: 2rem;
92+
line-height: 1.3;
93+
letter-spacing: -0.01em;
94+
font-weight: 700;
95+
color: rgb(250 250 250); /* zinc-50 */
96+
text-align: center;
97+
margin-bottom: 3.5rem;
98+
}
99+
100+
.faq-list {
101+
display: flex;
102+
flex-direction: column;
103+
gap: 0.75rem;
104+
}
105+
106+
.faq-item {
107+
background: rgb(39 39 42 / 0.6);
108+
border: 1px solid rgb(39 39 42 / 0.4);
109+
border-radius: 0.75rem;
110+
backdrop-filter: blur(8px);
111+
overflow: hidden;
112+
transition: border-color 0.3s cubic-bezier(0.4, 0, 0.2, 1);
113+
}
114+
115+
.faq-item:has(.faq-trigger[aria-expanded="true"]) {
116+
border-color: rgb(82 82 91); /* zinc-600 */
117+
}
118+
119+
.faq-trigger {
120+
width: 100%;
121+
display: flex;
122+
align-items: center;
123+
justify-content: space-between;
124+
gap: 1.5rem;
125+
padding: 1.25rem 1.5rem;
126+
background: none;
127+
border: none;
128+
cursor: pointer;
129+
text-align: left;
130+
}
131+
132+
.faq-trigger:focus-visible {
133+
outline: 2px solid rgb(228 228 231);
134+
outline-offset: -2px;
135+
border-radius: 0.625rem;
136+
}
137+
138+
.faq-question {
139+
font-size: 0.9375rem;
140+
font-weight: 500;
141+
color: rgb(228 228 231); /* zinc-200 */
142+
line-height: 1.5;
143+
transition: color 0.2s ease;
144+
}
145+
146+
.faq-trigger:hover .faq-question,
147+
.faq-trigger[aria-expanded="true"] .faq-question {
148+
color: rgb(250 250 250); /* zinc-50 */
149+
}
150+
151+
.faq-icon {
152+
flex-shrink: 0;
153+
color: rgb(113 113 122); /* zinc-500 */
154+
transition: color 0.2s ease;
155+
position: relative;
156+
width: 20px;
157+
height: 20px;
158+
}
159+
160+
.faq-trigger:hover .faq-icon,
161+
.faq-trigger[aria-expanded="true"] .faq-icon {
162+
color: rgb(212 212 216); /* zinc-300 */
163+
}
164+
165+
.icon-plus,
166+
.icon-minus {
167+
position: absolute;
168+
inset: 0;
169+
transition: opacity 0.2s ease;
170+
}
171+
172+
.icon-minus {
173+
opacity: 0;
174+
}
175+
176+
.faq-trigger[aria-expanded="true"] .icon-plus {
177+
opacity: 0;
178+
}
179+
180+
.faq-trigger[aria-expanded="true"] .icon-minus {
181+
opacity: 1;
182+
}
183+
184+
.faq-panel {
185+
/* Panel is toggled via the `hidden` attribute; height animation done via JS */
186+
overflow: hidden;
187+
}
188+
189+
.faq-panel[hidden] {
190+
display: none;
191+
}
192+
193+
/* When animating, hidden is removed but we still need height transition */
194+
.faq-panel.is-animating {
195+
display: block !important;
196+
}
197+
198+
.faq-answer {
199+
padding: 0 1.5rem 1.25rem;
200+
border-top: 1px solid rgb(39 39 42 / 0.6);
201+
padding-top: 1rem;
202+
}
203+
204+
.faq-answer p {
205+
font-size: 0.9375rem;
206+
line-height: 1.75;
207+
color: rgb(161 161 170); /* zinc-400 */
208+
margin: 0;
209+
}
210+
211+
@media (max-width: 640px) {
212+
.container {
213+
padding: 0 1.25rem;
214+
}
215+
216+
.section-title {
217+
font-size: 1.75rem;
218+
}
219+
220+
.faq-trigger {
221+
padding: 1rem 1.25rem;
222+
}
223+
224+
.faq-answer {
225+
padding: 0 1.25rem 1rem;
226+
padding-top: 0.875rem;
227+
}
228+
}
229+
</style>
230+
231+
<script>
232+
// Smooth accordion with height animation
233+
function setupFAQ() {
234+
const triggers = document.querySelectorAll<HTMLButtonElement>('.faq-trigger');
235+
236+
triggers.forEach((trigger) => {
237+
trigger.addEventListener('click', () => {
238+
const isExpanded = trigger.getAttribute('aria-expanded') === 'true';
239+
const panelId = trigger.getAttribute('aria-controls');
240+
if (!panelId) return;
241+
const panel = document.getElementById(panelId);
242+
if (!panel) return;
243+
244+
if (isExpanded) {
245+
// Collapse
246+
collapse(trigger, panel);
247+
} else {
248+
// Close any currently open item first
249+
triggers.forEach((otherTrigger) => {
250+
if (otherTrigger !== trigger && otherTrigger.getAttribute('aria-expanded') === 'true') {
251+
const otherId = otherTrigger.getAttribute('aria-controls');
252+
if (!otherId) return;
253+
const otherPanel = document.getElementById(otherId);
254+
if (otherPanel) collapse(otherTrigger, otherPanel);
255+
}
256+
});
257+
expand(trigger, panel);
258+
}
259+
});
260+
});
261+
}
262+
263+
function expand(trigger: HTMLButtonElement, panel: HTMLElement) {
264+
trigger.setAttribute('aria-expanded', 'true');
265+
panel.classList.add('is-animating');
266+
panel.removeAttribute('hidden');
267+
268+
const targetHeight = panel.scrollHeight;
269+
panel.style.height = '0px';
270+
271+
// Force reflow
272+
panel.offsetHeight;
273+
274+
panel.style.transition = 'height 0.3s cubic-bezier(0.4, 0, 0.2, 1)';
275+
panel.style.height = `${targetHeight}px`;
276+
277+
panel.addEventListener('transitionend', () => {
278+
panel.style.height = '';
279+
panel.style.transition = '';
280+
panel.classList.remove('is-animating');
281+
}, { once: true });
282+
}
283+
284+
function collapse(trigger: HTMLButtonElement, panel: HTMLElement) {
285+
trigger.setAttribute('aria-expanded', 'false');
286+
panel.classList.add('is-animating');
287+
288+
const startHeight = panel.scrollHeight;
289+
panel.style.height = `${startHeight}px`;
290+
291+
// Force reflow
292+
panel.offsetHeight;
293+
294+
panel.style.transition = 'height 0.3s cubic-bezier(0.4, 0, 0.2, 1)';
295+
panel.style.height = '0px';
296+
297+
panel.addEventListener('transitionend', () => {
298+
panel.setAttribute('hidden', '');
299+
panel.style.height = '';
300+
panel.style.transition = '';
301+
panel.classList.remove('is-animating');
302+
}, { once: true });
303+
}
304+
305+
// Run on DOMContentLoaded and after Astro view transitions
306+
document.addEventListener('DOMContentLoaded', setupFAQ);
307+
document.addEventListener('astro:page-load', setupFAQ);
308+
</script>

0 commit comments

Comments
 (0)