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