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

sleep-mode.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.

sleep-mode.tsxBlame218 lines · 1 contributor
46d6165Claude1/**
2 * Block L1 — Sleep Mode marketing page.
3 *
4 * Public, no auth. Pitch: "Toggle Sleep Mode. Walk away. Wake up to a
5 * digest of what Claude shipped overnight." Three-step "how it works",
6 * a sample digest rendered from a synthetic `SleepModeReport`, and a
7 * CTA to /settings.
8 */
9
10import { Hono } from "hono";
11import { raw } from "hono/html";
12import { Layout } from "../views/layout";
13import { softAuth } from "../middleware/auth";
14import type { AuthEnv } from "../middleware/auth";
15import {
16 renderSleepModeDigest,
17 type SleepModeReport,
18} from "../lib/sleep-mode";
19
20const sleepMode = new Hono<AuthEnv>();
21sleepMode.use("*", softAuth);
22
23/** A synthetic, on-brand report used to render the sample digest screenshot. */
24const SAMPLE_REPORT: SleepModeReport = {
25 windowHours: 24,
26 prsAutoMerged: [
27 { number: 412, title: "Bump axios to 1.7.4", repo: "api-gateway" },
28 { number: 88, title: "Fix flaky retry test", repo: "billing" },
29 { number: 134, title: "Cache stage results", repo: "workflow-runner" },
30 ],
31 issuesBuiltByAi: [
32 {
33 number: 207,
34 title: "Add /metrics endpoint with Prometheus format",
35 repo: "api-gateway",
36 prNumber: 413,
37 },
38 {
39 number: 56,
40 title: "Dark-mode toggle in admin nav",
41 repo: "dashboard",
42 prNumber: 89,
43 },
44 ],
45 aiReviewsPosted: 14,
46 securityIssuesAutoFixed: 2,
47 gateFailuresAutoRepaired: 5,
48 hoursSaved: 7.4,
49};
50
51sleepMode.get("/sleep-mode", (c) => {
52 const user = c.get("user");
53 const sample = renderSleepModeDigest(SAMPLE_REPORT, {
54 username: user?.username || "you",
55 });
56 return c.html(
57 <Layout title="Sleep Mode — gluecron" user={user}>
58 <style dangerouslySetInnerHTML={{ __html: pageCss }} />
59 <div class="sm-root">
60 <header class="sm-hero">
61 <div class="eyebrow">Sleep Mode</div>
62 <h1 class="display sm-hero-title">
63 Toggle Sleep Mode. Walk away.{" "}
64 <span class="gradient-text">Wake up to a digest.</span>
65 </h1>
66 <p class="sm-hero-sub">
67 Claude keeps your repos shipping while you sleep &mdash;
68 auto-merging green PRs, building features from{" "}
69 <code>ai:build</code> issues, reviewing code, and quietly fixing
70 the gates that fail. Sleep Mode emails you the highlights at the
71 UTC hour you pick.
72 </p>
73 <div class="sm-hero-cta">
74 <a href="/settings" class="btn btn-primary btn-lg">
75 Enable Sleep Mode in Settings &rarr;
76 </a>
77 <a href="/settings/sleep-mode/preview" class="btn btn-ghost btn-lg">
78 Preview your digest
79 </a>
80 </div>
81 </header>
82
83 <section class="sm-section">
84 <div class="section-header">
85 <div class="eyebrow">How it works</div>
86 <h2>Three steps. Then forget about it.</h2>
87 </div>
88 <div class="sm-steps">
89 <div class="sm-step">
90 <div class="sm-step-num">1</div>
91 <h3>Flip the toggle</h3>
92 <p>
93 A single checkbox in <a href="/settings">/settings</a>. Pick
94 the UTC hour you want the digest to land &mdash; default is
95 9 AM.
96 </p>
97 </div>
98 <div class="sm-step">
99 <div class="sm-step-num">2</div>
100 <h3>Claude works the night shift</h3>
101 <p>
102 The autopilot sweeps every 5 minutes. Green PRs get
103 auto-merged. <code>ai:build</code> issues become PRs. Gate
104 failures get auto-repaired. Security findings get patched.
105 </p>
106 </div>
107 <div class="sm-step">
108 <div class="sm-step-num">3</div>
109 <h3>Wake up to a digest</h3>
110 <p>
111 One email. Subject line tells you everything: "while you
112 slept, Claude shipped <em>N</em> things". Headlines, links,
113 and an estimate of hours saved.
114 </p>
115 </div>
116 </div>
117 </section>
118
119 <section class="sm-section">
120 <div class="section-header">
121 <div class="eyebrow">Sample digest</div>
122 <h2>Here&rsquo;s what lands in your inbox.</h2>
123 <p>
124 A real Sleep Mode digest, rendered from a synthetic report so
125 you can see the shape before you turn it on.
126 </p>
127 </div>
128 <div class="sm-sample">
129 <div class="sm-sample-frame">
130 <div class="sm-sample-meta">
131 <span class="sm-sample-from">no-reply@gluecron.app</span>
132 <span class="sm-sample-subject">{sample.subject}</span>
133 </div>
134 <div class="sm-sample-body">{raw(sample.html)}</div>
135 </div>
136 </div>
137 </section>
138
139 <section class="sm-section sm-cta-section">
140 <h2>Ready to walk away?</h2>
141 <p>
142 Sleep Mode is on-by-default safe &mdash; it can&rsquo;t merge
143 anything that wouldn&rsquo;t pass your branch protection rules.
144 Turn it on, sleep well.
145 </p>
146 <a href="/settings" class="btn btn-primary btn-lg">
147 Enable Sleep Mode &rarr;
148 </a>
149 </section>
150 </div>
151 </Layout>
152 );
153});
154
155const pageCss = `
156.sm-root { max-width: 1080px; margin: 0 auto; padding: 48px 24px 80px; }
157.sm-hero { text-align: center; padding: 32px 0 48px; }
158.sm-hero-title { font-size: clamp(32px, 5vw, 56px); line-height: 1.1; margin: 16px 0 20px; }
159.sm-hero-sub { max-width: 640px; margin: 0 auto; color: var(--text-muted); font-size: 17px; line-height: 1.6; }
160.sm-hero-cta { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-top: 32px; }
161.sm-section { margin: 64px 0; }
162.sm-steps {
163 display: grid;
164 grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
165 gap: 24px;
166 margin-top: 32px;
167}
168.sm-step {
169 background: var(--accent-gradient-faint);
170 border: 1px solid var(--border);
171 border-radius: 12px;
172 padding: 24px;
173}
174.sm-step h3 { margin: 16px 0 8px; font-size: 18px; }
175.sm-step p { color: var(--text-muted); line-height: 1.55; font-size: 14px; }
176.sm-step-num {
177 display: inline-flex;
178 align-items: center;
179 justify-content: center;
180 width: 36px;
181 height: 36px;
182 border-radius: 9999px;
183 background: var(--accent-gradient);
184 color: #fff;
185 font-weight: 700;
186 font-size: 15px;
187}
188.sm-sample { margin-top: 24px; display: flex; justify-content: center; }
189.sm-sample-frame {
190 background: #fff;
191 color: #111;
192 border-radius: 12px;
193 width: 100%;
194 max-width: 720px;
195 box-shadow: 0 16px 40px rgba(0,0,0,0.25);
196 overflow: hidden;
197 border: 1px solid var(--border);
198}
199.sm-sample-meta {
200 background: #f6f7fb;
201 padding: 12px 20px;
202 display: flex;
203 flex-direction: column;
204 gap: 4px;
205 border-bottom: 1px solid #e6e7ed;
206 font-size: 13px;
207 color: #4a4d59;
208}
209.sm-sample-from { font-size: 12px; color: #8a8e9c; }
210.sm-sample-subject { font-weight: 600; color: #0f1019; }
211.sm-sample-body { background: #fff; }
212.sm-sample-body > * { /* Sample digest html supplies its own padded body. */ }
213.sm-cta-section { text-align: center; padding: 48px 24px; background: var(--accent-gradient-soft); border-radius: 16px; }
214.sm-cta-section h2 { font-size: 28px; margin-bottom: 12px; }
215.sm-cta-section p { max-width: 520px; margin: 0 auto 24px; color: var(--text-muted); }
216`;
217
218export default sleepMode;