Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesPull RequestsActionsSecurityInsightsSettings
✨ AI
More
Blame · Line-by-line history

landing.tsx

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

landing.tsxBlame443 lines · 1 contributor
2b821b7Claude1/**
2 * Marketing landing page for logged-out visitors.
3 *
4 * Pure presentational component — no props required. Drops into an existing
5 * <Layout user={null}> as a single fragment. All styles are scoped under the
6 * `landing-` class prefix so they don't leak into the rest of the app.
7 *
8 * Tone: confident, technical, specific. No "revolutionary", no "game-changing".
9 */
10
11import type { FC } from "hono/jsx";
12
13export interface LandingPageProps {
14 stats?: {
15 publicRepos?: number;
16 users?: number;
17 };
18}
19
20export const LandingPage: FC<LandingPageProps> = () => {
21 return (
22 <>
23 <style>{landingCss}</style>
24
25 {/* ---------- Hero ---------- */}
26 <section class="landing-hero">
27 <h1 class="landing-hero-title">
28 GitHub, but the AI actually ships the code.
29 </h1>
30 <p class="landing-hero-sub">
31 gluecron is a self-hostable code platform with AI review, dependency
32 updates, semantic search, and a workflow runner built in. No plugins.
33 No bolt-ons. One binary.
34 </p>
35 <div class="landing-hero-ctas">
36 <a href="/register" class="btn btn-primary landing-cta-primary">
37 Start free
38 </a>
39 <a href="/explore" class="btn landing-cta-secondary">
40 Explore public repos
41 </a>
42 </div>
43 <p class="landing-trust">
44 Self-hostable &middot; AI built in &middot; Open source mindset
45 </p>
46 </section>
47
48 {/* ---------- Features grid ---------- */}
49 <section class="landing-section">
50 <h2 class="landing-section-title">Everything in one binary</h2>
51 <p class="landing-section-sub">
52 The features GitHub sells as separate products (Dependabot, Copilot,
53 Actions, Advanced Security) ship with gluecron by default.
54 </p>
55 <div class="landing-grid">
56 <FeatureCard
57 icon="\u2728"
58 title="AI code review"
59 desc="Claude Sonnet reviews every PR with inline comments. Can block merges when configured in branch protection."
60 />
61 <FeatureCard
62 icon="\u21BB"
63 title="AI dependency updates"
64 desc="Scans package.json, opens PRs with bump tables, writes the branch via git plumbing. Dependabot without the setup."
65 />
66 <FeatureCard
67 icon="\u2315"
68 title="Semantic code search"
69 desc="voyage-code-3 embeddings over every chunk, with lexical fallback. Finds code by intent, not just text."
70 />
71 <FeatureCard
72 icon="\u{1F4D6}"
73 title="Explain this codebase"
74 desc="One click gets you a per-commit cached Markdown tour of the repo. Onboarding that writes itself."
75 />
76 <FeatureCard
77 icon="\u2713"
78 title="Signed commit verification"
79 desc="GPG and SSH signatures, Issuer Fingerprint extraction, a green Verified badge on the commit list."
80 />
81 <FeatureCard
82 icon="\u21C4"
83 title="Merge queues + required checks"
84 desc="Serialised merges with re-test against the latest base. Per-branch required check matrix, enforced at merge."
85 />
86 <FeatureCard
87 icon="\u2699"
88 title="Self-hosted workflow runner"
89 desc="Actions-equivalent runner reads .gluecron/workflows/*.yml. Bun subprocesses, size-capped logs, per-step timeouts."
90 />
91 <FeatureCard
92 icon="\u{1F4E6}"
93 title="npm-protocol package registry"
94 desc="Publish, install, yank over the real npm protocol. PAT-auth via .npmrc. No separate service to run."
95 />
96 <FeatureCard
97 icon="\u{1F510}"
98 title="Enterprise SSO (OIDC)"
99 desc="Okta, Azure AD, Auth0, Google Workspace. Auth-code flow, state+nonce, optional email-domain allow-list."
100 />
101 </div>
102 </section>
103
104 {/* ---------- vs GitHub ---------- */}
105 <section class="landing-section landing-compare">
106 <h2 class="landing-section-title">gluecron vs GitHub</h2>
107 <p class="landing-section-sub">
108 Honest comparison. GitHub is excellent at what it does. gluecron is
109 built for teams that want AI and CI in one place, on infrastructure
110 they control.
111 </p>
112 <div class="landing-compare-grid">
113 <div class="landing-compare-col landing-compare-us">
114 <h3>gluecron</h3>
115 <ul>
116 <li><span class="landing-check">{"\u2713"}</span> Self-host on your own box</li>
117 <li><span class="landing-check">{"\u2713"}</span> AI review and completion included</li>
118 <li><span class="landing-check">{"\u2713"}</span> Dependency updater included</li>
119 <li><span class="landing-check">{"\u2713"}</span> Workflow runner included</li>
120 <li><span class="landing-check">{"\u2713"}</span> Semantic search included</li>
121 <li><span class="landing-check">{"\u2713"}</span> Green-by-default (gates, protection, codeowners)</li>
122 <li><span class="landing-check">{"\u2713"}</span> One binary. One database. One deploy.</li>
123 </ul>
124 </div>
125 <div class="landing-compare-col landing-compare-them">
126 <h3>GitHub</h3>
127 <ul>
128 <li><span class="landing-dash">{"\u2013"}</span> SaaS-first (Enterprise Server is separate)</li>
129 <li><span class="landing-dash">{"\u2013"}</span> Copilot billed per seat</li>
130 <li><span class="landing-dash">{"\u2013"}</span> Dependabot configured per repo</li>
131 <li><span class="landing-dash">{"\u2013"}</span> Actions minutes metered</li>
132 <li><span class="landing-dash">{"\u2013"}</span> Code search is lexical by default</li>
133 <li><span class="landing-dash">{"\u2013"}</span> Advanced Security is an add-on</li>
134 <li><span class="landing-dash">{"\u2013"}</span> Many moving pieces to wire together</li>
135 </ul>
136 </div>
137 </div>
138 </section>
139
140 {/* ---------- How it works ---------- */}
141 <section class="landing-section">
142 <h2 class="landing-section-title">How it works</h2>
143 <div class="landing-steps">
144 <div class="landing-step">
145 <div class="landing-step-num">1</div>
146 <h3>Push code</h3>
147 <p>
148 <code>git push</code> to gluecron. Standard Smart HTTP. No agent
149 to install.
150 </p>
151 </div>
152 <div class="landing-step">
153 <div class="landing-step-num">2</div>
154 <h3>Gates + AI review run</h3>
155 <p>
156 Secret scanner, security gate, AI reviewer, and your workflows
157 fire automatically. Rulesets enforce push policy.
158 </p>
159 </div>
160 <div class="landing-step">
161 <div class="landing-step-num">3</div>
162 <h3>Green pushes auto-deploy</h3>
163 <p>
164 Default-branch commits that pass all gates deploy through
165 Crontech. Failed deploys open an AI-authored incident issue.
166 </p>
167 </div>
168 </div>
169 </section>
170
171 {/* ---------- Final CTA band ---------- */}
172 <section class="landing-cta-band">
173 <h2>Ready to push?</h2>
174 <p>
175 Create an account, push a repo, watch the gates run. No credit card,
176 no trial clock.
177 </p>
178 <div class="landing-hero-ctas">
179 <a href="/register" class="btn btn-primary landing-cta-primary">
180 Start free
181 </a>
182 <a href="/explore" class="btn landing-cta-secondary">
183 Browse public repos
184 </a>
185 </div>
186 </section>
187
188 {/* ---------- Footer row ---------- */}
189 <section class="landing-foot">
190 <a href="/explore">Explore</a>
191 <span class="landing-foot-sep">&middot;</span>
192 <a href="/marketplace">Marketplace</a>
193 <span class="landing-foot-sep">&middot;</span>
194 <a href="/api/graphql">GraphQL API</a>
195 <span class="landing-foot-sep">&middot;</span>
196 <a href="/shortcuts">Keyboard shortcuts</a>
197 <span class="landing-foot-sep">&middot;</span>
198 <a href="/terms">Terms</a>
199 </section>
200 </>
201 );
202};
203
204const FeatureCard: FC<{ icon: string; title: string; desc: string }> = ({
205 icon,
206 title,
207 desc,
208}) => (
209 <div class="landing-feature">
210 <div class="landing-feature-icon" aria-hidden="true">
211 {icon}
212 </div>
213 <h3 class="landing-feature-title">{title}</h3>
214 <p class="landing-feature-desc">{desc}</p>
215 </div>
216);
217
218const landingCss = `
219 /* ---------- Hero ---------- */
220 .landing-hero {
221 padding: 72px 16px 56px;
222 text-align: center;
223 max-width: 860px;
224 margin: 0 auto;
225 border-bottom: 1px solid var(--border);
226 }
227 .landing-hero-title {
228 font-size: 44px;
229 line-height: 1.1;
230 letter-spacing: -0.02em;
231 margin: 0 0 20px;
232 color: var(--text);
233 font-weight: 700;
234 }
235 .landing-hero-sub {
236 font-size: 18px;
237 color: var(--text-muted);
238 margin: 0 auto 32px;
239 max-width: 640px;
240 line-height: 1.5;
241 }
242 .landing-hero-ctas {
243 display: flex;
244 gap: 12px;
245 justify-content: center;
246 flex-wrap: wrap;
247 margin-bottom: 16px;
248 }
249 .landing-cta-primary,
250 .landing-cta-secondary {
251 padding: 10px 20px;
252 font-size: 15px;
253 font-weight: 600;
254 }
255 .landing-trust {
256 font-size: 13px;
257 color: var(--text-muted);
258 margin-top: 12px;
259 letter-spacing: 0.02em;
260 }
261
262 /* ---------- Section scaffolding ---------- */
263 .landing-section {
264 padding: 64px 16px;
265 max-width: 1080px;
266 margin: 0 auto;
267 border-bottom: 1px solid var(--border);
268 }
269 .landing-section-title {
270 font-size: 28px;
271 font-weight: 700;
272 margin: 0 0 12px;
273 color: var(--text);
274 letter-spacing: -0.01em;
275 }
276 .landing-section-sub {
277 font-size: 15px;
278 color: var(--text-muted);
279 margin: 0 0 36px;
280 max-width: 680px;
281 line-height: 1.6;
282 }
283
284 /* ---------- Features grid ---------- */
285 .landing-grid {
286 display: grid;
287 grid-template-columns: repeat(3, 1fr);
288 gap: 16px;
289 }
290 .landing-feature {
291 border: 1px solid var(--border);
292 border-radius: var(--radius);
293 padding: 20px;
294 background: var(--bg-secondary);
295 transition: border-color 0.15s;
296 }
297 .landing-feature:hover { border-color: var(--text-muted); }
298 .landing-feature-icon {
299 font-size: 22px;
300 margin-bottom: 10px;
301 line-height: 1;
302 }
303 .landing-feature-title {
304 font-size: 15px;
305 font-weight: 600;
306 margin: 0 0 6px;
307 color: var(--text);
308 }
309 .landing-feature-desc {
310 font-size: 13px;
311 color: var(--text-muted);
312 line-height: 1.55;
313 margin: 0;
314 }
315
316 /* ---------- Compare strip ---------- */
317 .landing-compare-grid {
318 display: grid;
319 grid-template-columns: 1fr 1fr;
320 gap: 16px;
321 }
322 .landing-compare-col {
323 border: 1px solid var(--border);
324 border-radius: var(--radius);
325 padding: 24px;
326 background: var(--bg-secondary);
327 }
328 .landing-compare-us { border-color: var(--accent); }
329 .landing-compare-col h3 {
330 font-size: 18px;
331 font-weight: 700;
332 margin: 0 0 16px;
333 color: var(--text);
334 }
335 .landing-compare-col ul {
336 list-style: none;
337 margin: 0;
338 padding: 0;
339 }
340 .landing-compare-col li {
341 font-size: 14px;
342 color: var(--text);
343 padding: 6px 0;
344 line-height: 1.5;
345 }
346 .landing-check { color: var(--green); font-weight: 700; margin-right: 8px; }
347 .landing-dash { color: var(--text-muted); font-weight: 700; margin-right: 8px; }
348 .landing-compare-them li { color: var(--text-muted); }
349
350 /* ---------- How it works ---------- */
351 .landing-steps {
352 display: grid;
353 grid-template-columns: repeat(3, 1fr);
354 gap: 16px;
355 }
356 .landing-step {
357 border: 1px solid var(--border);
358 border-radius: var(--radius);
359 padding: 24px;
360 background: var(--bg-secondary);
361 }
362 .landing-step-num {
363 display: inline-flex;
364 align-items: center;
365 justify-content: center;
366 width: 28px;
367 height: 28px;
368 border-radius: 50%;
369 background: var(--accent);
370 color: #fff;
371 font-weight: 700;
372 font-size: 14px;
373 margin-bottom: 12px;
374 }
375 .landing-step h3 {
376 font-size: 16px;
377 font-weight: 600;
378 margin: 0 0 6px;
379 color: var(--text);
380 }
381 .landing-step p {
382 font-size: 13px;
383 color: var(--text-muted);
384 line-height: 1.55;
385 margin: 0;
386 }
387 .landing-step code {
388 font-family: var(--font-mono);
389 font-size: 12px;
390 background: var(--bg-tertiary);
391 padding: 1px 6px;
392 border-radius: 3px;
393 color: var(--text);
394 }
395
396 /* ---------- Final CTA band ---------- */
397 .landing-cta-band {
398 padding: 72px 16px;
399 text-align: center;
400 max-width: 860px;
401 margin: 0 auto;
402 border-bottom: 1px solid var(--border);
403 }
404 .landing-cta-band h2 {
405 font-size: 32px;
406 font-weight: 700;
407 margin: 0 0 12px;
408 color: var(--text);
409 }
410 .landing-cta-band p {
411 font-size: 15px;
412 color: var(--text-muted);
413 margin: 0 auto 28px;
414 max-width: 560px;
415 }
416
417 /* ---------- Foot row ---------- */
418 .landing-foot {
419 padding: 32px 16px 48px;
420 text-align: center;
421 font-size: 13px;
422 color: var(--text-muted);
423 }
424 .landing-foot a { color: var(--text-muted); }
425 .landing-foot a:hover { color: var(--text); text-decoration: none; }
426 .landing-foot-sep { margin: 0 10px; color: var(--border); }
427
428 /* ---------- Responsive ---------- */
429 @media (max-width: 820px) {
430 .landing-hero { padding: 48px 16px 40px; }
431 .landing-hero-title { font-size: 32px; }
432 .landing-hero-sub { font-size: 16px; }
433 .landing-section { padding: 48px 16px; }
434 .landing-section-title { font-size: 24px; }
435 .landing-grid { grid-template-columns: 1fr; }
436 .landing-compare-grid { grid-template-columns: 1fr; }
437 .landing-steps { grid-template-columns: 1fr; }
438 .landing-cta-band { padding: 48px 16px; }
439 .landing-cta-band h2 { font-size: 24px; }
440 }
441`;
442
443export default LandingPage;