Skip to content

Commit 0996705

Browse files
Brunoclaude
authored andcommitted
Structural redesign: full-bleed layout with persistent rail and two shells
Replace the templated centred-column architecture (nav > main.wrap > hero > tool > stacked sections inside a 900–1080px column) with a modern full-bleed system: **Two shells:** - app: homepage + 50 tool pages. Tool-first workbench — dense header, tool edge-to-edge, then supporting prose in a measured column with margin links. - docs: guides, articles, about/privacy/terms/contact, translated pages. Rail + ~70ch measure + sticky on-page contents (TOC from h2s). **Persistent left rail** (full-height, sticky on desktop, reflows below at 980px): - Organized by tool GROUPS taxonomy (8 categories, 50 tools total) - Current page marked with aria-current - Site nav sections for docs shell (Guides, Reading, Site links) **Dense 46px top bar** with logo, top nav (Tools/Guides/Compare/About), language switcher (Español/Deutsch), and theme toggle. Wraps to two rows on mobile (<720px), unpinned below 720px. **Responsive breakpoints:** - 1200px: hide TOC, full-measure reading - 980px: rail reflows below content via flex order (tool still opens page on phone) - 720px: topbar wraps, nav becomes scrollable (hidden scrollbar) **Styling updates:** - Terminal-inspired monospace type, hard edges (no border-radius on tool) - Spec plate on homepage updated to dot separators (·) on mobile - Updated README § Layout to document both shells and reflow strategy - 4 new tests lock in the architecture (no .wrap or .hero fallback, rail coverage, etc.) All 60 tests pass. Verified at 1440×900, 1024×768, 375×812 (light & dark). Ready for production push. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
1 parent bee8b29 commit 0996705

79 files changed

Lines changed: 9918 additions & 3026 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,31 @@ Edit and rebuild:
5353

5454
- `site.config.mjs` — name, domain, and (optional) analytics/ad IDs.
5555
- `pages.mjs` — the diff tool markup + the long-tail landing pages (one row per
56-
format/language). Add a row, rebuild, done.
56+
format/language). Add a row, **file its slug in `GROUPS`**, rebuild, done. A
57+
slug that isn't in a group fails the test suite, because the navigation rail
58+
renders from `GROUPS` and the page would otherwise vanish from site nav.
5759
- `content.mjs` — home, about, privacy, terms, contact.
5860
- `assets/``style.css` (design tokens + components) and `app.js` (the whole
5961
client-side engine: diff, highlighting, views, share/export).
6062

63+
### Layout
64+
65+
There are two page shells, chosen per page type in `engine/build.mjs` and built
66+
in `engine/template.mjs`. Neither is a centred column — a single 1080px `.wrap`
67+
holding a hero and a stack of sections was the shape of every page here until
68+
July 2026, and it is what made the site read as templated.
69+
70+
| Shell | Used by | Shape |
71+
|---|---|---|
72+
| `app` | homepage + the 50 `diff/` pages | Tool-first workbench: dense header strip, the tool edge-to-edge across the content column, then the supporting prose in a measured column with the contextual links in the margin. |
73+
| `docs` | guides, articles, about/privacy/terms/contact, translated pages | Reading layout: navigation rail, a ~70ch measure, and a sticky on-page contents rail generated from the page's own `<h2>`s. |
74+
75+
Both are full-bleed with a persistent left rail and a 46px top bar. The rail is
76+
site navigation, in the same position on every page; the in-content
77+
`relatedLinks()` window stays curated and contextual. Below 980px the rail
78+
reflows *below* the content via flex `order`, so the tool still opens the page
79+
on a phone.
80+
6181
Everything else — `index.html`, the `diff/` pages, `sitemap.xml`, `robots.txt`,
6282
`llms.txt` — is generated by `engine/build.mjs` from the files above.
6383

about.html

Lines changed: 70 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<link rel="preconnect" href="https://fonts.googleapis.com">
2222
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
2323
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
24-
<link rel="stylesheet" href="./assets/style.css?v=bc8cedc1">
24+
<link rel="stylesheet" href="./assets/style.css?v=9df46e9d">
2525
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Q907KGWEP4"></script>
2626
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}
2727
gtag('js',new Date());gtag('config','G-Q907KGWEP4');</script>
@@ -36,48 +36,94 @@
3636
</head>
3737
<body>
3838
<a class="skip-link" href="#main">Skip to content</a>
39-
<header>
39+
<header class="topbar">
4040
<a class="logo" href="/">
41-
<svg class="logo-mark" width="22" height="22" viewBox="0 0 22 22" fill="none" aria-hidden="true"><rect x="2" y="3" width="7" height="16" fill="currentColor"/><rect x="13" y="7" width="7" height="12" fill="currentColor" opacity="0.45"/></svg>
41+
<svg class="logo-mark" width="20" height="20" viewBox="0 0 22 22" fill="none" aria-hidden="true"><rect x="2" y="3" width="7" height="16" fill="currentColor"/><rect x="13" y="7" width="7" height="12" fill="currentColor" opacity="0.45"/></svg>
4242
Diffhero
4343
</a>
44-
<button type="button" class="theme-toggle" id="themeToggle" aria-label="Toggle light/dark">
45-
<svg class="icon-sun" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2.5M12 19.5V22M4.2 4.2l1.8 1.8M18 18l1.8 1.8M2 12h2.5M19.5 12H22M4.2 19.8 6 18M18 6l1.8-1.8"/></svg>
46-
<svg class="icon-moon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20.2 14.6A8.5 8.5 0 1 1 9.4 3.8a7 7 0 0 0 10.8 10.8Z"/></svg>
47-
</button>
44+
<nav class="topnav" aria-label="Main">
45+
<a href="/">Tools</a>
46+
<a href="/guides">Guides</a>
47+
<a href="/diffchecker-alternative">Compare</a>
48+
<a href="/about">About</a>
49+
</nav>
50+
<div class="topbar-end">
51+
52+
<span class="topbar-note">no upload · no account</span>
53+
<button type="button" class="theme-toggle" id="themeToggle" aria-label="Toggle light/dark">
54+
<svg class="icon-sun" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2.5M12 19.5V22M4.2 4.2l1.8 1.8M18 18l1.8 1.8M2 12h2.5M19.5 12H22M4.2 19.8 6 18M18 6l1.8-1.8"/></svg>
55+
<svg class="icon-moon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20.2 14.6A8.5 8.5 0 1 1 9.4 3.8a7 7 0 0 0 10.8 10.8Z"/></svg>
56+
</button>
57+
</div>
4858
</header>
49-
<nav class="main-nav chrome-rule" aria-label="Site">
50-
<a href="/guides">Guides</a>
51-
<a href="/diffchecker-alternative">Compare</a>
52-
<a href="/about">About</a>
53-
<a href="/privacy">Privacy</a>
54-
<a href="/terms">Terms</a>
55-
<a href="/contact">Contact</a>
59+
<div class="shell shell--docs has-aside">
60+
<nav class="rail" aria-label="Guides and site">
61+
<div class="rail-in">
62+
<p class="rail-title"><a href="/guides">Guides</a></p>
63+
<section class="rail-group">
64+
<h2 class="rail-head">Reading</h2>
65+
<ul class="rail-list is-here">
66+
<li><a href="/guides/what-is-a-diff">What is a diff? How software compares two versions of a file</a></li>
67+
<li><a href="/guides/how-to-review-a-pull-request">How to review a pull request well</a></li>
68+
<li><a href="/guides/merge-conflicts-explained">Merge conflicts explained, and how to resolve them without losing work</a></li>
69+
<li><a href="/guides/diffing-config-files-safely">How to diff config files without breaking production</a></li>
70+
<li><a href="/guides/line-word-and-semantic-diffs">Line, word and semantic diffs: which comparison you actually need</a></li>
71+
<li><a href="/guides/client-side-tools-and-privacy">Why “nothing leaves your browser” matters for developer tools</a></li>
72+
<li><a href="/guides/comparing-documents-without-track-changes">How to compare two documents when Track Changes wasn't on</a></li>
73+
</ul>
74+
</section>
75+
<section class="rail-group">
76+
<h2 class="rail-head">Site</h2>
77+
<ul class="rail-list is-here">
78+
<li><a href="/diffchecker-alternative">Diffchecker alternative</a></li>
79+
<li><a href="/embed">Embed the diff checker</a></li>
80+
<li><a href="/about" aria-current="page">About</a></li>
81+
<li><a href="/privacy">Privacy</a></li>
82+
<li><a href="/terms">Terms</a></li>
83+
<li><a href="/contact">Contact</a></li>
84+
</ul>
85+
</section>
86+
<section class="rail-group">
87+
<h2 class="rail-head">Tools</h2>
88+
<ul class="rail-list is-here">
89+
<li><a href="/">All 50 diff tools →</a></li>
90+
</ul>
91+
</section>
92+
</div>
5693
</nav>
57-
<main class="wrap" id="main">
94+
<main class="content" id="main">
5895

5996
<section class="prose">
6097
<h1>About Diffhero</h1>
6198
<p>Diffhero is a small, single-purpose tool: paste two versions of any text or code and instantly see what changed — every added, removed and altered line, with the exact changed words highlighted inline. It's the same idea as the <code>diff</code> command or the review view on a code host, distilled to one page with nothing to install and nothing to sign up for.</p>
6299

63-
<h2>Who makes it</h2>
100+
<h2 id="who-makes-it">Who makes it</h2>
64101
<p>Diffhero is built and maintained independently by a working software developer, not a company or a funded startup — someone who reaches for a diff tool most days and got tired of the ones that wall the useful parts behind a signup or upload your code to a server to do the comparison. It's a focused side project, kept deliberately small. Bug reports and feature requests go straight to the person who maintains it, at <a href="mailto:hello@diffhero.app">hello@diffhero.app</a>.</p>
65102

66-
<h2>How it works</h2>
103+
<h2 id="how-it-works">How it works</h2>
67104
<p>The entire comparison runs in your browser using JavaScript — your text and code are diffed on your own device and never sent anywhere. You can confirm that in your browser's Network tab (you'll see no request carrying your content), and the tool keeps working offline once the page has loaded. That "nothing uploaded" design is the whole point: it means you can safely compare proprietary code, a draft contract, or a config file full of secrets, without handing any of it to a third party. Files you drag in (<code>.txt</code>, <code>.pdf</code>, <code>.docx</code>) are read locally the same way.</p>
68105

69-
<h2>Why it exists</h2>
106+
<h2 id="why-it-exists">Why it exists</h2>
70107
<p>Because the popular diff checkers each fall down somewhere: some upload your input to a server, some cap you after a few uses, some bury word-level highlighting or file support behind a paywall. Diffhero keeps the genuinely useful features — word-level highlighting, split and unified views, syntax awareness, file drag-and-drop, shareable links and <code>.diff</code> export — free and client-side, with per-format guidance on each tool's page (the real gotchas, like why "ignore whitespace" is dangerous for Python or YAML).</p>
71108
<p>It stays free by showing a single, unobtrusive ad, and nothing more — no upsell, no account, no data collection. Found a bug or want a format supported? <a href="/contact">Get in touch</a>.</p>
72109
</section>
73110
</main>
111+
<aside class="toc" aria-label="On this page">
112+
<div class="toc-in">
113+
<p class="toc-title">On this page</p>
114+
<ol>
115+
<li><a href="#who-makes-it">Who makes it</a></li>
116+
<li><a href="#how-it-works">How it works</a></li>
117+
<li><a href="#why-it-exists">Why it exists</a></li>
118+
</ol>
119+
</div>
120+
</aside>
121+
</div>
74122
<footer>
75-
<div class="wrap">
76-
<div class="foot-in">
77-
<div><span class="fb">Diffhero</span> — See exactly what changed. · <a href="/guides">Guides</a> · <a href="/diffchecker-alternative">Compare</a> · <a href="/about">About</a> · <a href="/privacy">Privacy</a> · <a href="/terms">Terms</a> · <a href="/contact">Contact</a> · <a href="mailto:hello@diffhero.app">hello@diffhero.app</a></div>
78-
<div>Free. No signup, no upload — everything runs in your browser.<br>
79-
Built and maintained by <a href="https://brunofk.dev" rel="author noopener" target="_blank">Bruno FK</a>, an independent developer in Edinburgh.</div>
80-
</div>
123+
<div class="foot-in">
124+
<div><span class="fb">Diffhero</span> — See exactly what changed. · <a href="/guides">Guides</a> · <a href="/diffchecker-alternative">Compare</a> · <a href="/about">About</a> · <a href="/privacy">Privacy</a> · <a href="/terms">Terms</a> · <a href="/contact">Contact</a> · <a href="mailto:hello@diffhero.app">hello@diffhero.app</a></div>
125+
<div>Free. No signup, no upload — everything runs in your browser.<br>
126+
Built and maintained by <a href="https://brunofk.dev" rel="author noopener" target="_blank">Bruno FK</a>, an independent developer in Edinburgh.</div>
81127
</div>
82128
</footer>
83129
<script src="./assets/app.js?v=aea90853" defer></script>

0 commit comments

Comments
 (0)