From 2e0240aca6b1d574f9d6f60735fdd824d74af984 Mon Sep 17 00:00:00 2001 From: Robin van Baalen Date: Mon, 28 Sep 2026 11:38:51 -0400 Subject: [PATCH] fix: end internal links in a slash so crawlers skip the 307 --- CLAUDE.md | 5 +++++ src/components/sections/Download.astro | 2 +- src/components/sections/Footer.astro | 12 ++++++------ src/components/sections/Nav.astro | 6 +++--- src/pages/404.astro | 12 ++++++------ src/pages/about.astro | 2 +- src/pages/alternatives.astro | 2 +- src/pages/guides/index.astro | 2 +- .../span-wallpaper-across-two-monitors-mac.astro | 4 ++-- src/pages/help.astro | 2 +- src/pages/privacy.astro | 2 +- src/pages/terms.astro | 2 +- test/page.test.ts | 15 ++++++++++++++- 13 files changed, 43 insertions(+), 25 deletions(-) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..17a2477 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +# SpreadPaper website + +## Internal links end in a slash + +Pages build to directories (`/help/index.html`), and Cloudflare's `auto-trailing-slash` answers `/help` with a 307 to `/help/`. Every internal link, footer entry, nav item and 404 destination is written as `/help/`, never `/help`. A bare path works in the browser but sends every crawler through a redirect, which Ahrefs reports as "Page has links to redirect". Files keep their extension (`/favicon-32.png`). `npm test` checks every built page and fails on a link that redirects. diff --git a/src/components/sections/Download.astro b/src/components/sections/Download.astro index 96723af..7b55cee 100644 --- a/src/components/sections/Download.astro +++ b/src/components/sections/Download.astro @@ -78,7 +78,7 @@ import Icon from '../Icon.astro'

Apple could not verify SpreadPaper is free of malware

That is the wording macOS uses for any app not signed with a paid Apple Developer ID, and SpreadPaper is not signed with one. Nothing has been found in SpreadPaper, and nothing has been scanned: the check is for a signature, not for malware. You do not have to take that on trust, because the source is public and every release is built from it by GitHub Actions.

-

There are two ways past it, one through System Settings and one in Terminal. Both are written out step by step in how to open SpreadPaper when macOS blocks it. It takes a minute, and only the first time.

+

There are two ways past it, one through System Settings and one in Terminal. Both are written out step by step in how to open SpreadPaper when macOS blocks it. It takes a minute, and only the first time.

diff --git a/src/components/sections/Footer.astro b/src/components/sections/Footer.astro index 5c7c5f1..3fa8d7e 100644 --- a/src/components/sections/Footer.astro +++ b/src/components/sections/Footer.astro @@ -53,12 +53,12 @@ const columns = [ id: 'footer-site', title: 'This site', links: [ - { href: '/help', label: 'Help' }, - { href: '/guides', label: 'Guides' }, - { href: '/about', label: 'About' }, - { href: '/alternatives', label: 'Alternatives' }, - { href: '/privacy', label: 'Privacy Policy' }, - { href: '/terms', label: 'Terms of Service' }, + { href: '/help/', label: 'Help' }, + { href: '/guides/', label: 'Guides' }, + { href: '/about/', label: 'About' }, + { href: '/alternatives/', label: 'Alternatives' }, + { href: '/privacy/', label: 'Privacy Policy' }, + { href: '/terms/', label: 'Terms of Service' }, ], }, { diff --git a/src/components/sections/Nav.astro b/src/components/sections/Nav.astro index 5d9a674..9a9948f 100644 --- a/src/components/sections/Nav.astro +++ b/src/components/sections/Nav.astro @@ -17,9 +17,9 @@ const anchor = (id: string) => (isHome ? `#${id}` : `/#${id}`) // /guides/bezel-compensation/ still marks Guides. const links = [ { href: anchor('types'), label: 'Features', current: isHome }, - { href: '/help', label: 'Help', current: path.startsWith('/help') }, - { href: '/guides', label: 'Guides', current: path.startsWith('/guides') }, - { href: '/about', label: 'About', current: path.startsWith('/about') }, + { href: '/help/', label: 'Help', current: path.startsWith('/help') }, + { href: '/guides/', label: 'Guides', current: path.startsWith('/guides') }, + { href: '/about/', label: 'About', current: path.startsWith('/about') }, ] --- diff --git a/src/pages/404.astro b/src/pages/404.astro index 018178f..4af5182 100644 --- a/src/pages/404.astro +++ b/src/pages/404.astro @@ -21,37 +21,37 @@ const destinations: Destination[] = [ }, { name: 'Help', - path: '/help', + path: '/help/', what: 'Getting past the first launch warning, and what else goes wrong', words: 'install open warning gatekeeper unsigned damaged malware first launch troubleshooting support', }, { name: 'Guides', - path: '/guides', + path: '/guides/', what: 'Spanning two monitors, and how bezel compensation works', words: 'bezel compensation span two monitors gap seam tutorial how to step by step', }, { name: 'About', - path: '/about', + path: '/about/', what: 'Who builds it and everyone who has shaped it', words: 'who robin contributors open source credits curacao project team', }, { name: 'Alternatives', - path: '/alternatives', + path: '/alternatives/', what: 'Which other apps genuinely span a wallpaper', words: 'superpaper spanright multiscape fresco compare comparison free paid competitors', }, { name: 'Privacy Policy', - path: '/privacy', + path: '/privacy/', what: 'The one request the app makes', words: 'data tracking analytics telemetry request github update check gdpr cookies', }, { name: 'Terms of Service', - path: '/terms', + path: '/terms/', what: 'The MIT licence, in short', words: 'licence license mit warranty fork name legal terms conditions', }, diff --git a/src/pages/about.astro b/src/pages/about.astro index 9fc8898..a425df0 100644 --- a/src/pages/about.astro +++ b/src/pages/about.astro @@ -33,7 +33,7 @@ const facts = [ socialDescription={`One wallpaper across every display, built by ${people(credited.length)}.`} breadcrumb={[ { name: 'Home', path: '/' }, - { name: 'About', path: '/about' }, + { name: 'About', path: '/about/' }, ]} >