Skip to content

Commit 86cd7e2

Browse files
dylanroscoverclaude
andcommitted
fix(web): consistent grid background + theme tokens across standalone pages
An audit of the standalone "misc" pages (auth / onboarding / utility / legal) found verify-2fa's missing grid background was systemic, plus scattered hardcoded colors. Bring them all in line with the canonical pattern: - Restore the grid background (dot-grid + blueprint-grid overlays on a relative wrapper, card lifted via relative z-10, solid bg-card) on the six auth-card pages that were missing it: login, register, forgot-password, reset-password, add, unsubscribe — including their Suspense/loading states. - Hardcoded text-white -> text-foreground (cli/authorize, unsubscribe); unsubscribe card bg-secondary -> bg-card. - Legal pages (privacy, terms): text-white headings -> text-foreground, prose-invert -> dark:prose-invert (theme-ready), privacy gets bg-background. - Polish: fix dead hover states, "Loading..." -> "loading...", and lowercase the 2fa/setup flow copy (titles/headings/buttons/labels) per the UI convention. Toast copy left as-is to stay consistent with the rest of the app. Verified: lint, tsc, and the unit suite are green; the 2fa/auth e2e specs use case-insensitive matchers, so the copy lowercasing doesn't break the gate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent d0272ca commit 86cd7e2

11 files changed

Lines changed: 139 additions & 105 deletions

File tree

web/app/add/page.tsx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,10 @@ export default function AddMachinePage() {
148148

149149
if (authLoading || loading) {
150150
return (
151-
<div className="flex items-center justify-center min-h-screen bg-background">
152-
<Loader2 className="h-8 w-8 animate-spin text-accent-cyan" />
151+
<div className="relative flex items-center justify-center min-h-screen">
152+
<div className="absolute inset-0 dot-grid opacity-30" />
153+
<div className="absolute inset-0 blueprint-grid opacity-15" />
154+
<Loader2 className="relative z-10 h-8 w-8 animate-spin text-accent-cyan" />
153155
</div>
154156
);
155157
}
@@ -159,8 +161,11 @@ export default function AddMachinePage() {
159161
// Success state
160162
if (isAuthorized) {
161163
return (
162-
<div className="flex min-h-screen items-center justify-center p-4 bg-background">
163-
<Card className="w-full max-w-md bg-card/50 border-border text-center">
164+
<div className="relative flex min-h-screen items-center justify-center p-4">
165+
{/* Grid background */}
166+
<div className="absolute inset-0 dot-grid opacity-30" />
167+
<div className="absolute inset-0 blueprint-grid opacity-15" />
168+
<Card className="relative z-10 w-full max-w-md border-border bg-card text-center">
164169
<CardContent className="pt-10 pb-10 space-y-6">
165170
<div className="mx-auto w-20 h-20 rounded-full bg-emerald-500/20 flex items-center justify-center">
166171
<CheckCircle2 className="h-10 w-10 text-emerald-500" />
@@ -186,8 +191,11 @@ export default function AddMachinePage() {
186191
}
187192

188193
return (
189-
<div className="flex min-h-screen items-center justify-center p-4 bg-background">
190-
<Card className="w-full max-w-lg bg-card/50 border-border">
194+
<div className="relative flex min-h-screen items-center justify-center p-4">
195+
{/* Grid background */}
196+
<div className="absolute inset-0 dot-grid opacity-30" />
197+
<div className="absolute inset-0 blueprint-grid opacity-15" />
198+
<Card className="relative z-10 w-full max-w-lg border-border bg-card">
191199
<CardHeader className="space-y-4 flex flex-col items-center">
192200
<OwletteEyeIcon size={48} />
193201
<div className="space-y-1 text-center">
@@ -233,7 +241,7 @@ export default function AddMachinePage() {
233241
</Select>
234242
) : (
235243
<p className="text-sm text-muted-foreground">
236-
No sites available. Create a site on the dashboard first.
244+
no sites available. create a site on the dashboard first.
237245
</p>
238246
)}
239247
</div>

web/app/cli/authorize/page.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ function CliAuthorizeInner() {
9595
<PageHeader currentPage="api keys" />
9696
<main className="max-w-xl mx-auto px-6 py-8">
9797
<div className="mb-6">
98-
<h1 className="text-2xl font-semibold text-white flex items-center gap-2">
98+
<h1 className="text-2xl font-semibold text-foreground flex items-center gap-2">
9999
<KeyRound className="h-5 w-5" /> authorise cli
100100
</h1>
101101
<p className="text-sm text-muted-foreground mt-1">
@@ -106,7 +106,7 @@ function CliAuthorizeInner() {
106106
{done ? (
107107
<Card className="border-green-500/50 bg-green-500/5 p-6 text-center space-y-3">
108108
<CheckCircle2 className="h-8 w-8 text-green-400 mx-auto" />
109-
<p className="text-sm text-white">cli authorised</p>
109+
<p className="text-sm text-foreground">cli authorised</p>
110110
<p className="text-xs text-muted-foreground">
111111
return to your terminal — the cli is polling and will pick up the key
112112
within a few seconds.
@@ -124,7 +124,7 @@ function CliAuthorizeInner() {
124124
</div>
125125

126126
<div className="space-y-2">
127-
<Label htmlFor="cliKeyName" className="text-white">
127+
<Label htmlFor="cliKeyName" className="text-foreground">
128128
key name
129129
</Label>
130130
<Input
@@ -133,20 +133,20 @@ function CliAuthorizeInner() {
133133
value={name}
134134
onChange={(e) => setName(e.target.value)}
135135
placeholder="e.g. laptop-dev, ci-runner"
136-
className="bg-background border-border text-white"
136+
className="bg-background border-border text-foreground"
137137
disabled={submitting}
138138
/>
139139
</div>
140140

141141
<div className="grid grid-cols-2 gap-3">
142142
<div className="space-y-2">
143-
<Label className="text-white">environment</Label>
143+
<Label className="text-foreground">environment</Label>
144144
<Select
145145
value={environment}
146146
onValueChange={(v) => setEnvironment(v as ApiKeyEnvironment)}
147147
disabled={submitting}
148148
>
149-
<SelectTrigger className="bg-background border-border text-white">
149+
<SelectTrigger className="bg-background border-border text-foreground">
150150
<SelectValue />
151151
</SelectTrigger>
152152
<SelectContent>
@@ -156,7 +156,7 @@ function CliAuthorizeInner() {
156156
</Select>
157157
</div>
158158
<div className="space-y-2">
159-
<Label htmlFor="cliTtlDays" className="text-white">
159+
<Label htmlFor="cliTtlDays" className="text-foreground">
160160
ttl (days)
161161
</Label>
162162
<Input
@@ -166,20 +166,20 @@ function CliAuthorizeInner() {
166166
max={MAX_TTL_DAYS}
167167
value={ttlDays}
168168
onChange={(e) => setTtlDays(Number(e.target.value) || DEFAULT_TTL_DAYS)}
169-
className="bg-background border-border text-white"
169+
className="bg-background border-border text-foreground"
170170
disabled={submitting}
171171
/>
172172
</div>
173173
</div>
174174

175175
<div className="space-y-2">
176-
<Label className="text-white">scope preset</Label>
176+
<Label className="text-foreground">scope preset</Label>
177177
<Select
178178
value={preset}
179179
onValueChange={(v) => setPreset(v as ApiKeyScopePreset)}
180180
disabled={submitting}
181181
>
182-
<SelectTrigger className="bg-background border-border text-white">
182+
<SelectTrigger className="bg-background border-border text-foreground">
183183
<SelectValue />
184184
</SelectTrigger>
185185
<SelectContent>

web/app/forgot-password/page.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,11 @@ export default function ForgotPasswordPage() {
3232
};
3333

3434
return (
35-
<div className="flex min-h-screen items-center justify-center p-4">
36-
<Card className="w-full max-w-md bg-card/50 border-border">
35+
<div className="relative flex min-h-screen items-center justify-center p-4">
36+
{/* Grid background */}
37+
<div className="absolute inset-0 dot-grid opacity-30" />
38+
<div className="absolute inset-0 blueprint-grid opacity-15" />
39+
<Card className="relative z-10 w-full max-w-md border-border bg-card">
3740
<CardHeader className="space-y-4 flex flex-col items-center">
3841
<OwletteEyeIcon size={80} />
3942
<div className="space-y-1 text-center">

web/app/login/page.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,11 @@ function LoginForm() {
197197
};
198198

199199
return (
200-
<div className="flex min-h-screen items-center justify-center p-4">
201-
<Card className="w-full max-w-md bg-card/50 border-border">
200+
<div className="relative flex min-h-screen items-center justify-center p-4">
201+
{/* Grid background */}
202+
<div className="absolute inset-0 dot-grid opacity-30" />
203+
<div className="absolute inset-0 blueprint-grid opacity-15" />
204+
<Card className="relative z-10 w-full max-w-md border-border bg-card">
202205
<CardHeader className="space-y-4 flex flex-col items-center">
203206
<OwletteEyeIcon size={80} />
204207
<div className="space-y-1 text-center">
@@ -251,7 +254,7 @@ function LoginForm() {
251254
<span className="w-full border-t border-border" />
252255
</div>
253256
<div className="relative flex justify-center text-xs uppercase">
254-
<span className="bg-card/50 px-2 text-muted-foreground">
257+
<span className="bg-card px-2 text-muted-foreground">
255258
or continue with
256259
</span>
257260
</div>
@@ -313,8 +316,11 @@ function LoginForm() {
313316
export default function LoginPage() {
314317
return (
315318
<Suspense fallback={
316-
<div className="flex min-h-screen items-center justify-center p-4">
317-
<Card className="w-full max-w-md bg-card/50 border-border">
319+
<div className="relative flex min-h-screen items-center justify-center p-4">
320+
{/* Grid background */}
321+
<div className="absolute inset-0 dot-grid opacity-30" />
322+
<div className="absolute inset-0 blueprint-grid opacity-15" />
323+
<Card className="relative z-10 w-full max-w-md border-border bg-card">
318324
<CardHeader className="space-y-4 flex flex-col items-center">
319325
<OwletteEyeIcon size={80} />
320326
<div className="space-y-1 text-center">

web/app/privacy/page.tsx

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,24 @@ export default function PrivacyPage() {
88
const router = useRouter();
99

1010
return (
11-
<div className="min-h-screen py-12 px-4">
11+
<div className="min-h-screen bg-background py-12 px-4">
1212
<div className="max-w-3xl mx-auto">
1313
<div className="mb-8">
1414
<button
1515
onClick={() => router.back()}
16-
className="text-accent-cyan hover:text-accent-cyan text-sm cursor-pointer"
16+
className="text-accent-cyan hover:text-accent-cyan-hover text-sm cursor-pointer"
1717
>
1818
&larr; back
1919
</button>
2020
</div>
2121

22-
<article className="prose prose-invert prose-slate max-w-none">
23-
<h1 className="text-3xl font-bold text-white mb-2">privacy policy</h1>
22+
<article className="prose dark:prose-invert prose-slate max-w-none">
23+
<h1 className="text-3xl font-bold text-foreground mb-2">privacy policy</h1>
2424
<p className="text-muted-foreground text-sm mb-8">last updated: {lastUpdated}</p>
2525

2626
<div className="space-y-8 text-muted-foreground">
2727
<section>
28-
<h2 className="text-xl font-semibold text-white mb-4">1. introduction</h2>
28+
<h2 className="text-xl font-semibold text-foreground mb-4">1. introduction</h2>
2929
<p>
3030
The Experiential Company, LLC (&quot;TEC,&quot; &quot;we,&quot; &quot;our,&quot; or &quot;us&quot;) operates owlette, a cloud-connected
3131
process management and remote deployment system. this privacy policy explains how we
@@ -38,9 +38,9 @@ export default function PrivacyPage() {
3838
</section>
3939

4040
<section>
41-
<h2 className="text-xl font-semibold text-white mb-4">2. information we collect</h2>
41+
<h2 className="text-xl font-semibold text-foreground mb-4">2. information we collect</h2>
4242

43-
<h3 className="text-lg font-medium text-white mt-6 mb-3">account information</h3>
43+
<h3 className="text-lg font-medium text-foreground mt-6 mb-3">account information</h3>
4444
<p>when you create an account, we collect:</p>
4545
<ul className="list-disc pl-6 mt-2 space-y-1">
4646
<li>email address</li>
@@ -49,7 +49,7 @@ export default function PrivacyPage() {
4949
<li>two-factor authentication secrets (encrypted)</li>
5050
</ul>
5151

52-
<h3 className="text-lg font-medium text-white mt-6 mb-3">machine data</h3>
52+
<h3 className="text-lg font-medium text-foreground mt-6 mb-3">machine data</h3>
5353
<p>when you install the owlette agent on a machine, we collect:</p>
5454
<ul className="list-disc pl-6 mt-2 space-y-1">
5555
<li>machine hostname and unique identifiers</li>
@@ -59,7 +59,7 @@ export default function PrivacyPage() {
5959
<li>agent heartbeat and online/offline status</li>
6060
</ul>
6161

62-
<h3 className="text-lg font-medium text-white mt-6 mb-3">usage data</h3>
62+
<h3 className="text-lg font-medium text-foreground mt-6 mb-3">usage data</h3>
6363
<p>we automatically collect:</p>
6464
<ul className="list-disc pl-6 mt-2 space-y-1">
6565
<li>actions performed (process starts, stops, deployments)</li>
@@ -69,7 +69,7 @@ export default function PrivacyPage() {
6969
</section>
7070

7171
<section>
72-
<h2 className="text-xl font-semibold text-white mb-4">3. how we use your information</h2>
72+
<h2 className="text-xl font-semibold text-foreground mb-4">3. how we use your information</h2>
7373
<p>we use the collected information to:</p>
7474
<ul className="list-disc pl-6 mt-2 space-y-1">
7575
<li>provide and maintain the owlette service</li>
@@ -83,7 +83,7 @@ export default function PrivacyPage() {
8383
</section>
8484

8585
<section>
86-
<h2 className="text-xl font-semibold text-white mb-4">4. data storage and security</h2>
86+
<h2 className="text-xl font-semibold text-foreground mb-4">4. data storage and security</h2>
8787
<p>
8888
your data is stored using Google Firebase and Google Cloud Platform infrastructure.
8989
we implement industry-standard security measures including:
@@ -102,7 +102,7 @@ export default function PrivacyPage() {
102102
</section>
103103

104104
<section>
105-
<h2 className="text-xl font-semibold text-white mb-4">5. data retention</h2>
105+
<h2 className="text-xl font-semibold text-foreground mb-4">5. data retention</h2>
106106
<p>we retain your data as follows:</p>
107107
<ul className="list-disc pl-6 mt-2 space-y-1">
108108
<li><strong>account data:</strong> until you delete your account</li>
@@ -116,7 +116,7 @@ export default function PrivacyPage() {
116116
</section>
117117

118118
<section>
119-
<h2 className="text-xl font-semibold text-white mb-4">6. third-party services</h2>
119+
<h2 className="text-xl font-semibold text-foreground mb-4">6. third-party services</h2>
120120
<p>we use the following third-party services to operate owlette:</p>
121121
<ul className="list-disc pl-6 mt-2 space-y-1">
122122
<li><strong>Google Firebase:</strong> authentication, database, and hosting</li>
@@ -128,13 +128,13 @@ export default function PrivacyPage() {
128128
</section>
129129

130130
<section>
131-
<h2 className="text-xl font-semibold text-white mb-4">7. your rights</h2>
131+
<h2 className="text-xl font-semibold text-foreground mb-4">7. your rights</h2>
132132
<p>
133133
depending on your location, you may have certain rights regarding your personal
134134
information:
135135
</p>
136136

137-
<h3 className="text-lg font-medium text-white mt-6 mb-3">California residents (CCPA)</h3>
137+
<h3 className="text-lg font-medium text-foreground mt-6 mb-3">California residents (CCPA)</h3>
138138
<p>you have the right to:</p>
139139
<ul className="list-disc pl-6 mt-2 space-y-1">
140140
<li>know what personal information is collected</li>
@@ -143,7 +143,7 @@ export default function PrivacyPage() {
143143
<li>non-discrimination for exercising your privacy rights</li>
144144
</ul>
145145

146-
<h3 className="text-lg font-medium text-white mt-6 mb-3">all users</h3>
146+
<h3 className="text-lg font-medium text-foreground mt-6 mb-3">all users</h3>
147147
<p>you can:</p>
148148
<ul className="list-disc pl-6 mt-2 space-y-1">
149149
<li>access your account data through the dashboard</li>
@@ -154,7 +154,7 @@ export default function PrivacyPage() {
154154
</section>
155155

156156
<section>
157-
<h2 className="text-xl font-semibold text-white mb-4">8. cookies and tracking</h2>
157+
<h2 className="text-xl font-semibold text-foreground mb-4">8. cookies and tracking</h2>
158158
<p>
159159
owlette uses cookies and similar technologies for authentication and session
160160
management. these are essential for the service to function and cannot be
@@ -167,7 +167,7 @@ export default function PrivacyPage() {
167167
</section>
168168

169169
<section>
170-
<h2 className="text-xl font-semibold text-white mb-4">9. children&apos;s privacy</h2>
170+
<h2 className="text-xl font-semibold text-foreground mb-4">9. children&apos;s privacy</h2>
171171
<p>
172172
owlette is not intended for use by anyone under the age of 13. we do not knowingly
173173
collect personal information from children under 13. if you are a parent or guardian
@@ -176,7 +176,7 @@ export default function PrivacyPage() {
176176
</section>
177177

178178
<section>
179-
<h2 className="text-xl font-semibold text-white mb-4">10. changes to this policy</h2>
179+
<h2 className="text-xl font-semibold text-foreground mb-4">10. changes to this policy</h2>
180180
<p>
181181
we may update this privacy policy from time to time. we will notify you of any
182182
changes by posting the new privacy policy on this page and updating the
@@ -188,7 +188,7 @@ export default function PrivacyPage() {
188188
</section>
189189

190190
<section>
191-
<h2 className="text-xl font-semibold text-white mb-4">11. contact us</h2>
191+
<h2 className="text-xl font-semibold text-foreground mb-4">11. contact us</h2>
192192
<p>
193193
if you have any questions about this privacy policy or our data practices,
194194
please contact us at:

web/app/register/page.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,11 @@ export default function RegisterPage() {
9090
};
9191

9292
return (
93-
<div className="flex min-h-screen items-center justify-center p-4">
94-
<Card className="w-full max-w-md bg-card/50 border-border">
93+
<div className="relative flex min-h-screen items-center justify-center p-4">
94+
{/* Grid background */}
95+
<div className="absolute inset-0 dot-grid opacity-30" />
96+
<div className="absolute inset-0 blueprint-grid opacity-15" />
97+
<Card className="relative z-10 w-full max-w-md border-border bg-card">
9598
<CardHeader className="space-y-4 flex flex-col items-center">
9699
<OwletteEyeIcon size={80} />
97100
<div className="space-y-1 text-center">
@@ -200,7 +203,7 @@ export default function RegisterPage() {
200203
<span className="w-full border-t border-border" />
201204
</div>
202205
<div className="relative flex justify-center text-xs uppercase">
203-
<span className="bg-card/50 px-2 text-muted-foreground">
206+
<span className="bg-card px-2 text-muted-foreground">
204207
or continue with
205208
</span>
206209
</div>

0 commit comments

Comments
 (0)