Skip to content

Commit 9865e93

Browse files
committed
fix: align Cron Builder with InfraLens's tool chrome, fix card-bg tokens sitewide
- Cron Builder: "Next runs" now always renders in English (was following the visitor's browser locale), back link now points to /tools, and its background is opaque like every other tool instead of showing the homepage's decorative grid/glow - extracted ToolPageShell/ToolHeader (src/components/layout/) as the shared chrome for every /tools page — InfraLens's layout and Cron Builder now share the same back-link position and max-w-4xl content width instead of drifting independently - InfraLens's cards used the page's own background (bg-background/50) instead of the elevated --card token across landing, the full scan-results display, and compare/docs/privacy — fixed to bg-card/50 everywhere, matching the one section that already had it right - fixed a resulting WCAG contrast regression on Cron Builder's cards (text-zinc-500 -> text-zinc-400) - Cron Builder's Day of week/Month range picker now uses the same pill-button style as the rest of the tool instead of native selects
1 parent 7c34d49 commit 9865e93

24 files changed

Lines changed: 284 additions & 130 deletions

CHANGELOG.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,43 @@ InfraLens's history as a standalone product (2026-01-06 to 2026-08-10) is
99
frozen in [`docs/infralens/CHANGELOG.md`](docs/infralens/CHANGELOG.md).
1010
InfraLens changes since its native migration are recorded here.
1111

12+
## [1.2.1] — 2026-08-15
13+
14+
### Fixed
15+
16+
- Cron Builder's "Next runs" dates rendered in the visitor's browser
17+
locale (e.g. French on a French system) instead of the tool's
18+
English-only UI — the formatter now forces `en-US` regardless of the
19+
visitor's locale.
20+
- Cron Builder's back link pointed at the homepage map instead of
21+
`/tools`, and its decorative background let the homepage's grid/glow
22+
show through instead of the flat, opaque background every other tool
23+
uses.
24+
- InfraLens's card backgrounds (`bg-background/50`) used the page's own
25+
background color instead of the elevated `--card` token, making them
26+
blend into the page instead of standing out — fixed across the
27+
landing sections, the entire scan-results display (report header,
28+
category/check cards, priority summary, recommendations, the score
29+
dialog), and the compare/docs/privacy pages. Only the "example
30+
report" preview card used the correct token before this.
31+
- A resulting color-contrast regression (`text-zinc-500` on Cron
32+
Builder's now-lighter card backgrounds fell under the WCAG AA 4.5:1
33+
minimum) caught by the axe accessibility check and fixed to
34+
`text-zinc-400`.
35+
36+
### Changed
37+
38+
- Extracted `ToolPageShell`/`ToolHeader` (`src/components/layout/`) as
39+
the shared chrome for every tool under `/tools` — opaque background,
40+
"back to tools" link, and a common `max-w-4xl` content width — and
41+
moved both InfraLens's layout and Cron Builder onto it, so their back
42+
links and content now line up pixel-for-pixel instead of each tool
43+
drifting on its own width.
44+
- Cron Builder's Range-mode picker for labeled fields (Day of week,
45+
Month) replaced native `<select>` elements with the same pill-button
46+
style used everywhere else in the tool, for visual consistency and
47+
more uniform touch targets.
48+
1249
## [1.2.0] — 2026-08-15
1350

1451
### Added

app/tools/cron-builder/page.tsx

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import { PageShell } from "@/components/layout/page-shell";
1+
import { ToolHeader } from "@/components/layout/tool-header";
2+
import { ToolPageShell } from "@/components/layout/tool-page-shell";
23
import { CronBuilder } from "@/cron-builder/components/cron-builder";
34
import { CronReference } from "@/cron-builder/components/cron-reference";
45
import { brand } from "@/lib/brand";
5-
import type { Metadata } from "next";
6+
import { Clock } from "lucide-react";
7+
import type { Metadata, Viewport } from "next";
68

79
export const metadata: Metadata = {
810
title: "Cron Builder — Randy Code",
@@ -11,17 +13,28 @@ export const metadata: Metadata = {
1113
alternates: { canonical: "/tools/cron-builder" },
1214
};
1315

16+
// Matches InfraLens's own tool-page theme color — the mobile browser chrome
17+
// should read "tools" consistently across the whole /tools family.
18+
export const viewport: Viewport = {
19+
themeColor: brand.colors.green[500],
20+
};
21+
1422
export default function CronBuilderPage() {
1523
return (
16-
<PageShell
17-
label="Developer Tool"
18-
title="Cron Builder"
19-
tagline="Build, validate, and understand cron expressions without memorizing the syntax."
20-
color={brand.colors.green[500]}
21-
icon="clock"
22-
>
23-
<CronBuilder />
24-
<CronReference />
25-
</PageShell>
24+
<ToolPageShell>
25+
<main className="flex min-h-screen flex-col bg-background px-6 pb-16 text-foreground">
26+
<div className="mx-auto w-full max-w-4xl">
27+
<ToolHeader
28+
icon={Clock}
29+
label="Developer Tool"
30+
title="Cron Builder"
31+
tagline="Build, validate, and understand cron expressions without memorizing the syntax."
32+
color={brand.colors.green[500]}
33+
/>
34+
<CronBuilder />
35+
<CronReference />
36+
</div>
37+
</main>
38+
</ToolPageShell>
2639
);
2740
}

app/tools/infralens/docs/page.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export default function DocsPage() {
4949
</div>
5050

5151
{/* Overview */}
52-
<Card className="border-border bg-background/50">
52+
<Card className="border-border bg-card/50">
5353
<CardHeader>
5454
<CardTitle className="text-2xl">Overview</CardTitle>
5555
<CardDescription className="text-muted-foreground">
@@ -156,7 +156,7 @@ export default function DocsPage() {
156156
</Card>
157157

158158
{/* Network & DNS */}
159-
<Card className="border-border bg-background/50">
159+
<Card className="border-border bg-card/50">
160160
<CardHeader>
161161
<CardTitle className="text-2xl">Network & DNS</CardTitle>
162162
<CardDescription className="text-muted-foreground">
@@ -266,7 +266,7 @@ export default function DocsPage() {
266266
</Card>
267267

268268
{/* HTTP & Security */}
269-
<Card className="border-border bg-background/50">
269+
<Card className="border-border bg-card/50">
270270
<CardHeader>
271271
<CardTitle className="text-2xl">HTTP & Security</CardTitle>
272272
<CardDescription className="text-muted-foreground">
@@ -397,7 +397,7 @@ export default function DocsPage() {
397397
</Card>
398398

399399
{/* Infrastructure */}
400-
<Card className="border-border bg-background/50">
400+
<Card className="border-border bg-card/50">
401401
<CardHeader>
402402
<CardTitle className="text-2xl">Infrastructure</CardTitle>
403403
<CardDescription className="text-muted-foreground">
@@ -423,7 +423,7 @@ export default function DocsPage() {
423423
</Card>
424424

425425
{/* Website Structure */}
426-
<Card className="border-border bg-background/50">
426+
<Card className="border-border bg-card/50">
427427
<CardHeader>
428428
<CardTitle className="text-2xl">Website Structure</CardTitle>
429429
<CardDescription className="text-muted-foreground">
@@ -469,7 +469,7 @@ export default function DocsPage() {
469469
</Card>
470470

471471
{/* Metadata & Stack */}
472-
<Card className="border-border bg-background/50">
472+
<Card className="border-border bg-card/50">
473473
<CardHeader>
474474
<CardTitle className="text-2xl">
475475
Metadata & Technology Stack
@@ -567,7 +567,7 @@ export default function DocsPage() {
567567
</Card>
568568

569569
{/* Performance Signals */}
570-
<Card className="border-border bg-background/50">
570+
<Card className="border-border bg-card/50">
571571
<CardHeader>
572572
<CardTitle className="text-2xl">Performance Signals</CardTitle>
573573
<CardDescription className="text-muted-foreground">
@@ -623,7 +623,7 @@ export default function DocsPage() {
623623
</Card>
624624

625625
{/* Scoring */}
626-
<Card className="border-border bg-background/50">
626+
<Card className="border-border bg-card/50">
627627
<CardHeader>
628628
<CardTitle className="text-2xl">Scoring System</CardTitle>
629629
<CardDescription className="text-muted-foreground">
@@ -692,7 +692,7 @@ export default function DocsPage() {
692692
</Card>
693693

694694
{/* Comparing reports */}
695-
<Card className="border-border bg-background/50">
695+
<Card className="border-border bg-card/50">
696696
<CardHeader>
697697
<CardTitle className="text-2xl">Comparing Reports</CardTitle>
698698
<CardDescription className="text-muted-foreground">
@@ -720,7 +720,7 @@ export default function DocsPage() {
720720
</Card>
721721

722722
{/* Notes */}
723-
<Card className="border-border bg-background/50">
723+
<Card className="border-border bg-card/50">
724724
<CardHeader>
725725
<CardTitle className="text-2xl">Notes & Limitations</CardTitle>
726726
</CardHeader>

app/tools/infralens/layout.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ToolBackLink } from "@/components/layout/tool-back-link";
1+
import { ToolPageShell } from "@/components/layout/tool-page-shell";
22
import { siteMetadata } from "@infralens-lib/metadata";
33
import type { Metadata, Viewport } from "next";
44

@@ -15,12 +15,7 @@ export default function InfraLensLayout({
1515
}>) {
1616
return (
1717
<div className="infralens-scope">
18-
<div className="bg-background px-6 pt-4 sm:px-8 md:px-12">
19-
<div className="mx-auto max-w-4xl">
20-
<ToolBackLink />
21-
</div>
22-
</div>
23-
{children}
18+
<ToolPageShell>{children}</ToolPageShell>
2419
</div>
2520
);
2621
}

app/tools/infralens/privacy/page.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export default function PrivacyPage() {
4343
</div>
4444
</div>
4545

46-
<Card className="border-border bg-background/50">
46+
<Card className="border-border bg-card/50">
4747
<CardHeader>
4848
<CardTitle className="text-xl">
4949
What gets sent when you run an analysis
@@ -68,7 +68,7 @@ export default function PrivacyPage() {
6868
</CardContent>
6969
</Card>
7070

71-
<Card className="border-border bg-background/50">
71+
<Card className="border-border bg-card/50">
7272
<CardHeader>
7373
<CardTitle className="text-xl">
7474
Rate limiting and your IP
@@ -98,7 +98,7 @@ export default function PrivacyPage() {
9898
</CardContent>
9999
</Card>
100100

101-
<Card className="border-border bg-background/50">
101+
<Card className="border-border bg-card/50">
102102
<CardHeader>
103103
<CardTitle className="text-xl">
104104
Third-party services contacted
@@ -123,7 +123,7 @@ export default function PrivacyPage() {
123123
</CardContent>
124124
</Card>
125125

126-
<Card className="border-border bg-background/50">
126+
<Card className="border-border bg-card/50">
127127
<CardHeader>
128128
<CardTitle className="text-xl">
129129
What&apos;s stored locally
@@ -152,7 +152,7 @@ export default function PrivacyPage() {
152152
</CardContent>
153153
</Card>
154154

155-
<Card className="border-border bg-background/50">
155+
<Card className="border-border bg-card/50">
156156
<CardHeader>
157157
<CardTitle className="text-xl">
158158
What the analyzed site can see
@@ -174,7 +174,7 @@ export default function PrivacyPage() {
174174
</CardContent>
175175
</Card>
176176

177-
<Card className="border-border bg-background/50">
177+
<Card className="border-border bg-card/50">
178178
<CardHeader>
179179
<CardTitle className="text-xl">No tracking, by design</CardTitle>
180180
</CardHeader>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "randy-code",
3-
"version": "1.2.0",
3+
"version": "1.2.1",
44
"private": true,
55
"packageManager": "pnpm@10.7.0",
66
"scripts": {

src/components/layout/page-shell.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
ArrowLeft,
66
BookOpen,
77
Building2,
8-
Clock,
98
FlaskConical,
109
Mail,
1110
User,
@@ -20,7 +19,6 @@ const iconMap = {
2019
user: User,
2120
bookOpen: BookOpen,
2221
mail: Mail,
23-
clock: Clock,
2422
} as const;
2523

2624
export type PageIcon = keyof typeof iconMap;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import type { LucideIcon } from "lucide-react";
2+
3+
interface ToolHeaderProps {
4+
icon: LucideIcon;
5+
label: string;
6+
title: string;
7+
tagline: string;
8+
color: string;
9+
}
10+
11+
/**
12+
* Header for tools that don't have InfraLens's bespoke standalone-era hero
13+
* (Cron Builder, and future lightweight tools): icon, category label, title,
14+
* tagline. Static — no entrance animation, matching a utility tool's tone
15+
* and avoiding a transient low-opacity state during automated a11y scans.
16+
*/
17+
export function ToolHeader({
18+
icon: Icon,
19+
label,
20+
title,
21+
tagline,
22+
color,
23+
}: ToolHeaderProps) {
24+
return (
25+
<header className="pt-6 pb-8">
26+
<div className="mb-3 flex items-center gap-2">
27+
<div
28+
className="flex h-8 w-8 items-center justify-center rounded-lg"
29+
style={{ backgroundColor: `${color}18` }}
30+
>
31+
<Icon size={15} style={{ color }} />
32+
</div>
33+
<span
34+
className="text-xs font-medium uppercase tracking-widest"
35+
style={{ color }}
36+
>
37+
{label}
38+
</span>
39+
</div>
40+
<h1 className="text-4xl font-bold tracking-tight text-white md:text-5xl">
41+
{title}
42+
</h1>
43+
<p className="mt-3 max-w-xl text-base text-zinc-400">{tagline}</p>
44+
</header>
45+
);
46+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { ToolBackLink } from "@/components/layout/tool-back-link";
2+
3+
/**
4+
* Shared chrome for every tool under /tools (InfraLens, Cron Builder, ...):
5+
* an opaque background — hides the homepage's decorative grid/glow — and a
6+
* "back to tools" link, both at the tool family's canonical max-w-4xl. Tool
7+
* pages compose their own content as children; this only owns the shell.
8+
*/
9+
export function ToolPageShell({ children }: { children: React.ReactNode }) {
10+
return (
11+
<>
12+
<div className="bg-background px-6 pt-4 sm:px-8 md:px-12">
13+
<div className="mx-auto max-w-4xl">
14+
<ToolBackLink />
15+
</div>
16+
</div>
17+
{children}
18+
</>
19+
);
20+
}

0 commit comments

Comments
 (0)