Skip to content

Commit d0f6916

Browse files
feat: initial draft of testimonials
1 parent a05d6cf commit d0f6916

11 files changed

+653
-3
lines changed

app/page.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import AdaptiveTerminal from '@/components/AdaptiveTerminal'
99
import LaunchWebAppButton from '@/components/WebAppButton'
1010
import StarOnGithubButton from '@/components/GithubButton'
1111
import VideoComposite from '@/components/VideoComposite'
12+
import Testimonials from '@/components/Testimonials'
1213

1314
const GOOGLE_PLAY_LINK = 'https://play.google.com/store/apps/details?id=com.ex3ndr.happy'
1415
const APP_STORE_LINK = 'https://apps.apple.com/us/app/happy-claude-code-client/id6748571505'
@@ -144,9 +145,13 @@ export default function Home() {
144145

145146

146147
<section className="max-w-[72ch] mx-auto py-12 px-2.5 md:px-0">
147-
<TextBasedFeatures />
148-
<div className="h-12"></div>
149-
<TextBasedHowItWorks />
148+
<TextBasedFeatures />
149+
</section>
150+
<section className="max-w-5xl mx-auto">
151+
<Testimonials layout="masonry" />
152+
</section>
153+
<section className="max-w-[72ch] mx-auto py-12 px-2.5 md:px-0">
154+
<TextBasedHowItWorks />
150155
</section>
151156
{/*
152157
<YoutubeDemoSection

components/Testimonials.css

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
/* CSS Variables */
2+
:root {
3+
--clr-text: #374151;
4+
--clr-text-lt: hsla(217, 19%, 37%, 1);
5+
--clr-primary: #6701E6;
6+
--clr-background: #ffffff;
7+
--clr-border: hsla(0, 0%, 90%, 1);
8+
--clr-highlight: #ffcd3640;
9+
--clr-rating: #FBBF24;
10+
--box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.07);
11+
--border-radius: 1rem;
12+
--border-width: 1px;
13+
--padding: 16px;
14+
--font: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
15+
}
16+
17+
/* Dark mode variables when .dark class is applied to html */
18+
.dark {
19+
--clr-background: #000000;
20+
--clr-primary: #28DBC9;
21+
--clr-text: #F4F4F5;
22+
--clr-highlight: #ffcd3640;
23+
--clr-text-lt: hsla(240, 5%, 86%, 1);
24+
--clr-rating: #FBBF24;
25+
--clr-border: hsla(0, 0%, 10%, 1);
26+
--font: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
27+
--box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.07);
28+
}
29+
30+
/* Dark mode fallback using prefers-color-scheme */
31+
@media (prefers-color-scheme: dark) {
32+
:root:not(.light) {
33+
--clr-background: #000000;
34+
--clr-primary: #28DBC9;
35+
--clr-text: #F4F4F5;
36+
--clr-highlight: #ffcd3640;
37+
--clr-text-lt: hsla(240, 5%, 86%, 1);
38+
--clr-rating: #FBBF24;
39+
--clr-border: hsla(0, 0%, 10%, 1);
40+
--font: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
41+
--box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.07);
42+
}
43+
}
44+
45+
.swiper-horizontal {
46+
touch-action: pan-y;
47+
}
48+
.swiper, swiper-container {
49+
margin-left: auto;
50+
margin-right: auto;
51+
position: relative;
52+
overflow: hidden;
53+
list-style: none;
54+
padding: 0;
55+
z-index: 1;
56+
display: block;
57+
}
58+
59+
.swipper-wrapper {
60+
position: relative;
61+
width: 100%;
62+
height: 100%;
63+
z-index: 1;
64+
display: flex;
65+
transition-property: transform;
66+
transition-timing-function: var(--swiper-wrapper-transition-timing-function, initial);
67+
box-sizing: content-box;
68+
}
69+
70+
.sj-card .sj-card-details {
71+
align-items: center;
72+
font-size: .875rem;
73+
line-height: 1.25rem;
74+
gap: .5rem;
75+
display: flex;
76+
}
77+
.sj-card .sj-card-details {
78+
color: var(--clr-text-lt);
79+
font-size: .875rem;
80+
line-height: 1.25rem;
81+
}
82+
83+
.sj-card {
84+
background-color: var(--clr-background);
85+
box-shadow: var(--box-shadow);
86+
border-radius: var(--border-radius);
87+
box-sizing: border-box;
88+
overflow: hidden;
89+
position: relative;
90+
font-family: var(--font);
91+
}
92+
93+
.sj-card .sj-text-card {
94+
padding: var(--padding);
95+
border-width: var(--border-width);
96+
box-shadow: var(--box-shadow);
97+
border-color: var(--clr-border);
98+
border-radius: var(--border-radius);
99+
}
100+
101+
.sj-card .sj-card-content {
102+
display: flex;
103+
flex-direction: column;
104+
gap: 0.5rem;
105+
}
106+
107+
.sj-endorser-view-container {
108+
display: flex;
109+
width: 100%;
110+
align-items: center;
111+
gap: 1rem;
112+
}
113+
114+
.sj-avatar-container {
115+
position: relative;
116+
flex-shrink: 0;
117+
}
118+
119+
.sj-endorser-name {
120+
color: var(--clr-text);
121+
font-weight: 500;
122+
font-size: 16px;
123+
line-height: 20px;
124+
}
125+
126+
.sj-desc {
127+
color: var(--clr-text-lt);
128+
font-size: 14px;
129+
line-height: 18px;
130+
}
131+
132+
.sj-spacer {
133+
flex-grow: 1;
134+
}
135+
136+
.sj-integration-fixed-icon {
137+
margin-top: 0.25rem;
138+
align-self: flex-start;
139+
}
140+
141+
.sj-content {
142+
font-size: 16px;
143+
color: var(--clr-text);
144+
line-height: 24px;
145+
white-space: pre-line;
146+
letter-spacing: -0.025em;
147+
}
148+
149+
.sj-content a {
150+
color: var(--clr-primary);
151+
}
152+
153+
.sj-attachment-container {
154+
border-radius: 0.25rem;
155+
overflow: hidden;
156+
}
157+
158+
.sj-media {
159+
border-radius: 0.25rem;
160+
width: 100%;
161+
max-height: 400px;
162+
object-fit: cover;
163+
}
164+
165+
.sj-card-details {
166+
align-items: center;
167+
font-size: 0.875rem;
168+
line-height: 1.25rem;
169+
gap: 0.5rem;
170+
display: flex;
171+
color: var(--clr-text-lt);
172+
}
173+
174+
.sj-heart {
175+
color: #9ca3af;
176+
}
177+
178+
.sj-heart:hover {
179+
fill: currentColor;
180+
color: #f87171;
181+
}
182+
183+
.sj-card .sj-content a {
184+
color: var(--clr-primary);
185+
}
186+
187+
/* Masonry layout styles */
188+
.masonry-grid {
189+
column-gap: 1rem;
190+
orphans: 1;
191+
widows: 1;
192+
}
193+
194+
.masonry-item {
195+
break-inside: avoid;
196+
margin-bottom: 1rem;
197+
width: 100%;
198+
}
199+
200+
/* Mobile horizontal scroll improvements */
201+
@media (max-width: 768px) {
202+
.sj-container {
203+
-webkit-overflow-scrolling: touch;
204+
scrollbar-width: none; /* Firefox */
205+
-ms-overflow-style: none; /* IE and Edge */
206+
}
207+
208+
.sj-container::-webkit-scrollbar {
209+
display: none; /* Chrome, Safari, Opera */
210+
}
211+
212+
/* Ensure cards don't shrink too much on mobile */
213+
.sj-card {
214+
min-width: 280px;
215+
}
216+
217+
/* Add scroll indicators for mobile */
218+
.sj-container > div > div {
219+
position: relative;
220+
}
221+
222+
.sj-container > div > div::after {
223+
content: '';
224+
position: absolute;
225+
right: -8px;
226+
top: 50%;
227+
transform: translateY(-50%);
228+
width: 4px;
229+
height: 40px;
230+
background: linear-gradient(90deg, transparent, rgba(0,0,0,0.1));
231+
border-radius: 2px;
232+
pointer-events: none;
233+
}
234+
235+
/* Improve touch scrolling */
236+
.sj-container > div > div {
237+
touch-action: pan-x;
238+
overscroll-behavior-x: contain;
239+
}
240+
241+
/* Add scroll snap for better mobile experience */
242+
.sj-container > div > div {
243+
scroll-snap-type: x mandatory;
244+
}
245+
246+
.sj-container > div > div > div {
247+
scroll-snap-align: start;
248+
}
249+
}
250+
251+
/* Smooth transitions for layout changes */
252+
.sj-container > div > div {
253+
transition: all 0.3s ease-in-out;
254+
}
255+
256+
/* Ensure masonry items have smooth transitions */
257+
.masonry-item {
258+
transition: opacity 0.3s ease-in-out;
259+
}

0 commit comments

Comments
 (0)