From 0e7871f395cb06858502eef295fc56164c241e9a Mon Sep 17 00:00:00 2001 From: Compleet Date: Tue, 14 Jul 2026 14:37:44 +0100 Subject: [PATCH] Restructure navigation around What's up / Opine and the reader's utilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Stories gain a required type (report | essay); all 28 classified per the boundary rule now stated in EDITORIAL.md - Nav: What's up · Opine · Podcast · Book · Guides · Forum, each gated on real content (Forum waits on a forumUrl); logo is Home - /whats-up (reports, newest first) and /opine (essays, editorial order) share a StoryArchive component with subject filters - Static /tags/ pages for subjects carried by 2+ stories; tags stay overlapping, never exclusive departments - /corrections: generated from revision history (commits beginning 'Correction:'), so the page cannot under-report - About, RSS, Corrections, Weekly briefing move to the footer Co-Authored-By: Claude Fable 5 --- EDITORIAL.md | 10 ++ src/components/Footer.astro | 6 +- src/components/Header.astro | 9 +- src/components/StoryArchive.astro | 127 ++++++++++++++++++ src/content.config.ts | 1 + ...aar-when-authentication-becomes-rations.md | 1 + .../age-check-becomes-identity-check.md | 1 + ...-transparency-does-not-prevent-mistakes.md | 1 + .../stories/estonia-chip-that-broke-trust.md | 1 + ...-wallet-arrives-before-its-privacy-does.md | 1 + ...raud-and-failure-leave-different-messes.md | 1 + .../identity-is-the-wrong-abstraction.md | 1 + .../stories/money-is-a-memory-system.md | 1 + src/content/stories/name-you-give-a-key.md | 1 + .../network-state-needs-lost-password-desk.md | 1 + .../stories/old-phone-real-identity-test.md | 1 + .../stories/one-score-to-rule-a-life.md | 1 + src/content/stories/repair-is-a-test.md | 1 + ...tation-should-not-follow-you-everywhere.md | 1 + .../stories/safety-number-nobody-checks.md | 1 + ...elective-disclosure-is-not-invisibility.md | 1 + .../stories/small-communities-federate.md | 1 + ...sovereign-individual-favorite-verb-exit.md | 1 + ...te-protects-privacy-and-sees-everything.md | 1 + .../traceability-beats-transparency.md | 1 + .../trust-is-accepted-vulnerability.md | 1 + src/content/stories/trust-on-first-use.md | 1 + .../stories/we-do-not-need-more-trust.md | 1 + src/content/stories/who-sent-this-agent.md | 1 + ...hy-digital-identity-projects-keep-dying.md | 1 + ...why-smart-people-join-high-trust-groups.md | 1 + .../stories/worldcoin-price-of-one-human.md | 1 + .../your-wallet-has-a-government-inside-it.md | 1 + src/lib/git.ts | 26 ++++ src/pages/corrections.astro | 101 ++++++++++++++ src/pages/opine.astro | 17 +++ src/pages/stories/index.astro | 65 ++------- src/pages/tags/[tag].astro | 37 +++++ src/pages/whats-up.astro | 19 +++ src/site.config.ts | 9 +- 40 files changed, 388 insertions(+), 67 deletions(-) create mode 100644 src/components/StoryArchive.astro create mode 100644 src/pages/corrections.astro create mode 100644 src/pages/opine.astro create mode 100644 src/pages/tags/[tag].astro create mode 100644 src/pages/whats-up.astro diff --git a/EDITORIAL.md b/EDITORIAL.md index 9caa897..825721e 100644 --- a/EDITORIAL.md +++ b/EDITORIAL.md @@ -8,6 +8,16 @@ We ask one recurring question with cheerful suspicion: when a system claims to b Stories begin with people and consequences. Technical machinery is explained in plain English. Jargon is defined when it is first used. Outrage is reserved for what the evidence supports. +## Sections + +Stories are typed, and the boundary is a commitment readers can check: a piece pegged to a system or event in the world is a **report** (What's up); an argument that would survive the news cycle is an **essay** (Opine). Reports are expected to age into `historical` status; essays carry review dates that mean something. + +Subjects are overlapping tags, not exclusive departments. A story about the EU wallet may legitimately be identity, privacy, and institutions at once. + +## Corrections page + +The corrections page is generated from revision history: any commit whose message begins with `Correction:` appears there automatically. The page cannot list fewer corrections than the repository contains. + ## Authorship and maintenance An author and a maintainer are different roles. Every published item identifies its author. Maintained material also names the person responsible for review. diff --git a/src/components/Footer.astro b/src/components/Footer.astro index ff7cc87..1b3c68c 100644 --- a/src/components/Footer.astro +++ b/src/components/Footer.astro @@ -12,12 +12,16 @@ import { site } from '../site.config'; RSS feed
Podcast feed
+ Weekly briefing
Public repository
+ About
+ Corrections
Commitments
- Revision history + Revision history
+ {site.contactUrl && Contact}
diff --git a/src/components/Header.astro b/src/components/Header.astro index ce199a1..5b36747 100644 --- a/src/components/Header.astro +++ b/src/components/Header.astro @@ -2,19 +2,19 @@ import { getCollection } from 'astro:content'; import { navigation, site } from '../site.config'; -const [stories, briefings, episodes, guides] = await Promise.all([ +const [stories, episodes, guides] = await Promise.all([ getCollection('stories', ({ data }) => !data.draft), - getCollection('briefings', ({ data }) => !data.draft), getCollection('episodes', ({ data }) => !data.draft), getCollection('guides', ({ data }) => !data.draft), ]); const visibleNavigation = navigation.filter((item) => { - if (item.href === '/stories') return stories.length > 0; - if (item.href === '/briefing') return briefings.length > 0; + if (item.href === '/whats-up') return stories.some(({ data }) => data.type === 'report'); + if (item.href === '/opine') return stories.some(({ data }) => data.type === 'essay'); if (item.href === '/podcast') return episodes.length > 0 || Boolean(site.podcastFeedUrl); if (item.href === '/guides') return guides.length > 0; if (item.href === '/book') return site.book.enabled; + if (item.href === '/forum') return Boolean(site.forumUrl); return true; }); --- @@ -28,7 +28,6 @@ const visibleNavigation = navigation.filter((item) => {
diff --git a/src/components/StoryArchive.astro b/src/components/StoryArchive.astro new file mode 100644 index 0000000..cfdcd93 --- /dev/null +++ b/src/components/StoryArchive.astro @@ -0,0 +1,127 @@ +--- +import type { CollectionEntry } from 'astro:content'; +import StoryCard from './StoryCard.astro'; + +interface Props { + title: string; + count: string; + note?: string; + noteHref?: string; + entries: CollectionEntry<'stories'>[]; + emptyMessage: string; + activeTag?: string; +} + +const { title, count, note, noteHref, entries, emptyMessage, activeTag } = Astro.props; + +const tagCounts = new Map(); +for (const entry of entries) { + for (const tag of entry.data.tags) { + tagCounts.set(tag, (tagCounts.get(tag) ?? 0) + 1); + } +} +// Only subjects carried by 2+ of the listed stories get a filter link +// (which also guarantees the target tag page exists). +const tags = [...tagCounts.entries()] + .filter(([, count]) => count >= 2) + .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])); +--- + +
+

{title}

+

{count}{note && noteHref && {note}}

+
+{tags.length > 1 && ( + +)} +
+ {entries.length > 0 ? entries.map((entry, index) => ) :

{emptyMessage}

} +
+ + diff --git a/src/content.config.ts b/src/content.config.ts index 1e8d5d0..55b9ccb 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -16,6 +16,7 @@ const stories = defineCollection({ loader: glob({ base: './src/content/stories', pattern: '**/*.md' }), schema: z.object({ title: z.string(), + type: z.enum(['report', 'essay']), description: z.string(), published: z.coerce.date(), editorialOrder: z.number().int().positive(), diff --git a/src/content/stories/aadhaar-when-authentication-becomes-rations.md b/src/content/stories/aadhaar-when-authentication-becomes-rations.md index de6384c..94794e9 100644 --- a/src/content/stories/aadhaar-when-authentication-becomes-rations.md +++ b/src/content/stories/aadhaar-when-authentication-becomes-rations.md @@ -1,5 +1,6 @@ --- title: "Aadhaar: when authentication becomes rations" +type: report description: "A biometric match can be highly accurate at national scale and still be the wrong place to put the cost of a failed fingerprint." published: 2026-07-14 editorialOrder: 12 diff --git a/src/content/stories/age-check-becomes-identity-check.md b/src/content/stories/age-check-becomes-identity-check.md index 6685b8c..28fb080 100644 --- a/src/content/stories/age-check-becomes-identity-check.md +++ b/src/content/stories/age-check-becomes-identity-check.md @@ -1,5 +1,6 @@ --- title: "When does an age check become an identity check?" +type: report description: "The EU's age-verification blueprint promises a simple yes-or-no proof. Its success depends on preventing that proof from becoming a reusable tracking handle." published: 2026-07-14 editorialOrder: 9 diff --git a/src/content/stories/certificate-transparency-does-not-prevent-mistakes.md b/src/content/stories/certificate-transparency-does-not-prevent-mistakes.md index 7ae42a3..850110f 100644 --- a/src/content/stories/certificate-transparency-does-not-prevent-mistakes.md +++ b/src/content/stories/certificate-transparency-does-not-prevent-mistakes.md @@ -1,5 +1,6 @@ --- title: "Certificate Transparency does not prevent mistakes" +type: report description: "It makes certificate authorities observable. That narrower promise has done more for trust than pretending misissuance can be designed away." published: 2026-07-14 editorialOrder: 20 diff --git a/src/content/stories/estonia-chip-that-broke-trust.md b/src/content/stories/estonia-chip-that-broke-trust.md index e8921f0..2a4b25e 100644 --- a/src/content/stories/estonia-chip-that-broke-trust.md +++ b/src/content/stories/estonia-chip-that-broke-trust.md @@ -1,5 +1,6 @@ --- title: "Estonia and the chip that broke trust" +type: report description: "The model digital state survived a mass identity-card vulnerability because it had revocation, remote repair, alternatives and an institution willing to act." published: 2026-07-14 editorialOrder: 14 diff --git a/src/content/stories/eu-wallet-arrives-before-its-privacy-does.md b/src/content/stories/eu-wallet-arrives-before-its-privacy-does.md index 6fc00cb..497af20 100644 --- a/src/content/stories/eu-wallet-arrives-before-its-privacy-does.md +++ b/src/content/stories/eu-wallet-arrives-before-its-privacy-does.md @@ -1,5 +1,6 @@ --- title: "The EU wallet arrives before its privacy does" +type: report description: "Europe's identity wallet is real, useful, optional—and racing toward a privacy problem that selective disclosure does not solve." published: 2026-07-14 editorialOrder: 1 diff --git a/src/content/stories/fraud-and-failure-leave-different-messes.md b/src/content/stories/fraud-and-failure-leave-different-messes.md index 5d3a2a2..ad254d3 100644 --- a/src/content/stories/fraud-and-failure-leave-different-messes.md +++ b/src/content/stories/fraud-and-failure-leave-different-messes.md @@ -1,5 +1,6 @@ --- title: "Fraud and failure leave different-shaped messes" +type: essay description: "A fraudulent organisation may coordinate brilliantly around a lie. A genuinely failing one often loses the ability to coordinate at all." published: 2026-07-14 editorialOrder: 26 diff --git a/src/content/stories/identity-is-the-wrong-abstraction.md b/src/content/stories/identity-is-the-wrong-abstraction.md index 5143141..e4c4b11 100644 --- a/src/content/stories/identity-is-the-wrong-abstraction.md +++ b/src/content/stories/identity-is-the-wrong-abstraction.md @@ -1,5 +1,6 @@ --- title: "Identity is the wrong abstraction" +type: essay description: "A library needs to know that you may borrow a book. It usually does not need a universal account of who you are." published: 2026-07-14 editorialOrder: 16 diff --git a/src/content/stories/money-is-a-memory-system.md b/src/content/stories/money-is-a-memory-system.md index c62a669..f55c1c1 100644 --- a/src/content/stories/money-is-a-memory-system.md +++ b/src/content/stories/money-is-a-memory-system.md @@ -1,5 +1,6 @@ --- title: "Money is a memory system" +type: essay description: "A balance remembers past contribution, couples strangers and compresses many kinds of value into one number. That is why monetary failure feels like amnesia." published: 2026-07-14 editorialOrder: 21 diff --git a/src/content/stories/name-you-give-a-key.md b/src/content/stories/name-you-give-a-key.md index c3e5fca..7ad073f 100644 --- a/src/content/stories/name-you-give-a-key.md +++ b/src/content/stories/name-you-give-a-key.md @@ -1,5 +1,6 @@ --- title: "The name you give a key" +type: essay description: "Petnames offer a modest way through the impossible demand that online names be secure, global, decentralised and easy to remember." published: 2026-07-14 editorialOrder: 17 diff --git a/src/content/stories/network-state-needs-lost-password-desk.md b/src/content/stories/network-state-needs-lost-password-desk.md index 82ee8c5..3335cf5 100644 --- a/src/content/stories/network-state-needs-lost-password-desk.md +++ b/src/content/stories/network-state-needs-lost-password-desk.md @@ -1,5 +1,6 @@ --- title: "A network state still needs a lost-password desk" +type: essay description: "Founding a cloud community is dramatic. Handling a dead founder, stolen key, contested vote or stranded member is what makes it political." published: 2026-07-14 editorialOrder: 22 diff --git a/src/content/stories/old-phone-real-identity-test.md b/src/content/stories/old-phone-real-identity-test.md index b574118..b3cbc1f 100644 --- a/src/content/stories/old-phone-real-identity-test.md +++ b/src/content/stories/old-phone-real-identity-test.md @@ -1,5 +1,6 @@ --- title: "Your old phone is the real identity test" +type: essay description: "Login demos happen on new devices. Trust is decided after a theft, a dead battery, a changed number, or a relationship someone needs to escape." published: 2026-07-14 editorialOrder: 2 diff --git a/src/content/stories/one-score-to-rule-a-life.md b/src/content/stories/one-score-to-rule-a-life.md index 64a32cf..6e5343e 100644 --- a/src/content/stories/one-score-to-rule-a-life.md +++ b/src/content/stories/one-score-to-rule-a-life.md @@ -1,5 +1,6 @@ --- title: "One score to rule a life" +type: essay description: "Global trust scores are attractive because they make people easy to compare. That is also the reason not to build one." published: 2026-07-14 editorialOrder: 23 diff --git a/src/content/stories/repair-is-a-test.md b/src/content/stories/repair-is-a-test.md index 84e749b..99a0ec1 100644 --- a/src/content/stories/repair-is-a-test.md +++ b/src/content/stories/repair-is-a-test.md @@ -1,5 +1,6 @@ --- title: "Repair is a test, not a moral duty" +type: essay description: "Trying to fix a system can generate the evidence that the system itself—not one parameter—is wrong." published: 2026-07-14 editorialOrder: 25 diff --git a/src/content/stories/reputation-should-not-follow-you-everywhere.md b/src/content/stories/reputation-should-not-follow-you-everywhere.md index e1b94f0..8128e0d 100644 --- a/src/content/stories/reputation-should-not-follow-you-everywhere.md +++ b/src/content/stories/reputation-should-not-follow-you-everywhere.md @@ -1,5 +1,6 @@ --- title: "Reputation should not follow you everywhere" +type: essay description: "Portable reputation sounds liberating until a rating earned in one room becomes a verdict in every other room." published: 2026-07-14 editorialOrder: 4 diff --git a/src/content/stories/safety-number-nobody-checks.md b/src/content/stories/safety-number-nobody-checks.md index dd5837b..5263347 100644 --- a/src/content/stories/safety-number-nobody-checks.md +++ b/src/content/stories/safety-number-nobody-checks.md @@ -1,5 +1,6 @@ --- title: "The safety number nobody checks" +type: report description: "Signal gives every pair of correspondents a strong way to verify keys. Most people ignore it, and the design remains useful." published: 2026-07-14 editorialOrder: 19 diff --git a/src/content/stories/selective-disclosure-is-not-invisibility.md b/src/content/stories/selective-disclosure-is-not-invisibility.md index 6a6c367..b2f79ea 100644 --- a/src/content/stories/selective-disclosure-is-not-invisibility.md +++ b/src/content/stories/selective-disclosure-is-not-invisibility.md @@ -1,5 +1,6 @@ --- title: "Selective disclosure is not invisibility" +type: essay description: "Showing fewer fields is good privacy. It does not necessarily stop a verifier from recognising you across presentations." published: 2026-07-14 editorialOrder: 10 diff --git a/src/content/stories/small-communities-federate.md b/src/content/stories/small-communities-federate.md index 6a17118..8808a2d 100644 --- a/src/content/stories/small-communities-federate.md +++ b/src/content/stories/small-communities-federate.md @@ -1,5 +1,6 @@ --- title: "Small communities do not scale. They federate." +type: essay description: "The intimacy that makes a neighbourhood, forum or practice group trustworthy is exactly what disappears when it becomes one enormous room." published: 2026-07-14 editorialOrder: 6 diff --git a/src/content/stories/sovereign-individual-favorite-verb-exit.md b/src/content/stories/sovereign-individual-favorite-verb-exit.md index 64eb57b..909eb02 100644 --- a/src/content/stories/sovereign-individual-favorite-verb-exit.md +++ b/src/content/stories/sovereign-individual-favorite-verb-exit.md @@ -1,5 +1,6 @@ --- title: "The Sovereign Individual's favourite verb is exit" +type: essay description: "Digital sovereignty begins as a technical promise and ends as a political question: who can leave, what can they take, and who is left behind?" published: 2026-07-14 editorialOrder: 7 diff --git a/src/content/stories/state-protects-privacy-and-sees-everything.md b/src/content/stories/state-protects-privacy-and-sees-everything.md index 5dd8646..54e2a9b 100644 --- a/src/content/stories/state-protects-privacy-and-sees-everything.md +++ b/src/content/stories/state-protects-privacy-and-sees-everything.md @@ -1,5 +1,6 @@ --- title: "The state can protect your privacy and still see everything" +type: report description: "China's national internet identity service reduces the need to hand civil-ID data to platforms by concentrating authentication in a public system." published: 2026-07-14 editorialOrder: 13 diff --git a/src/content/stories/traceability-beats-transparency.md b/src/content/stories/traceability-beats-transparency.md index 3be4d2d..75bcef2 100644 --- a/src/content/stories/traceability-beats-transparency.md +++ b/src/content/stories/traceability-beats-transparency.md @@ -1,5 +1,6 @@ --- title: "Traceability beats transparency" +type: essay description: "Making everything visible overwhelms the people meant to benefit. Linking decisions to actors and outcomes gives them something usable." published: 2026-07-14 editorialOrder: 28 diff --git a/src/content/stories/trust-is-accepted-vulnerability.md b/src/content/stories/trust-is-accepted-vulnerability.md index 7a16209..3270e59 100644 --- a/src/content/stories/trust-is-accepted-vulnerability.md +++ b/src/content/stories/trust-is-accepted-vulnerability.md @@ -1,5 +1,6 @@ --- title: "Trust is accepted vulnerability" +type: essay description: "If nothing can be lost, betrayed or mishandled, you may have confidence, prediction or control—but you do not yet have trust." published: 2026-07-14 editorialOrder: 8 diff --git a/src/content/stories/trust-on-first-use.md b/src/content/stories/trust-on-first-use.md index 6d90b6e..8286569 100644 --- a/src/content/stories/trust-on-first-use.md +++ b/src/content/stories/trust-on-first-use.md @@ -1,5 +1,6 @@ --- title: "The first connection is the dangerous one" +type: essay description: "SSH does not promise a global oracle for every server. It remembers the key it saw and becomes suspicious when reality changes." published: 2026-07-14 editorialOrder: 18 diff --git a/src/content/stories/we-do-not-need-more-trust.md b/src/content/stories/we-do-not-need-more-trust.md index 4abb445..219f9b2 100644 --- a/src/content/stories/we-do-not-need-more-trust.md +++ b/src/content/stories/we-do-not-need-more-trust.md @@ -1,5 +1,6 @@ --- title: "We do not need more trust" +type: essay description: "Calls to restore trust often ask the public to change its mood while leaving the reasons for distrust untouched." published: 2026-07-14 editorialOrder: 24 diff --git a/src/content/stories/who-sent-this-agent.md b/src/content/stories/who-sent-this-agent.md index a999d45..d98a1f3 100644 --- a/src/content/stories/who-sent-this-agent.md +++ b/src/content/stories/who-sent-this-agent.md @@ -1,5 +1,6 @@ --- title: "Who sent this agent?" +type: report description: "An AI agent can have a name, a key and a polished voice while remaining unable to show who authorised the action it is taking now." published: 2026-07-14 editorialOrder: 3 diff --git a/src/content/stories/why-digital-identity-projects-keep-dying.md b/src/content/stories/why-digital-identity-projects-keep-dying.md index b78dec2..5fe5ab2 100644 --- a/src/content/stories/why-digital-identity-projects-keep-dying.md +++ b/src/content/stories/why-digital-identity-projects-keep-dying.md @@ -1,5 +1,6 @@ --- title: "Why digital identity projects keep dying" +type: report description: "Passport, CardSpace, Persona and Web5 did not all fail for the same reason. Together they show that good identity architecture can still lose to habit." published: 2026-07-14 editorialOrder: 15 diff --git a/src/content/stories/why-smart-people-join-high-trust-groups.md b/src/content/stories/why-smart-people-join-high-trust-groups.md index 42cf4c9..f021aba 100644 --- a/src/content/stories/why-smart-people-join-high-trust-groups.md +++ b/src/content/stories/why-smart-people-join-high-trust-groups.md @@ -1,5 +1,6 @@ --- title: "Why smart people join high-trust groups" +type: essay description: "Belonging, meaning and certainty can be genuine goods while the group quietly makes leaving each one more expensive." published: 2026-07-14 editorialOrder: 27 diff --git a/src/content/stories/worldcoin-price-of-one-human.md b/src/content/stories/worldcoin-price-of-one-human.md index 7780faa..8ee4aed 100644 --- a/src/content/stories/worldcoin-price-of-one-human.md +++ b/src/content/stories/worldcoin-price-of-one-human.md @@ -1,5 +1,6 @@ --- title: "Worldcoin and the price of one human" +type: report description: "Proof of personhood answers a real AI-era problem. The Orb makes the bargain unusually visible: uniqueness in exchange for an irreversible measurement." published: 2026-07-14 editorialOrder: 5 diff --git a/src/content/stories/your-wallet-has-a-government-inside-it.md b/src/content/stories/your-wallet-has-a-government-inside-it.md index 0100a6e..e338271 100644 --- a/src/content/stories/your-wallet-has-a-government-inside-it.md +++ b/src/content/stories/your-wallet-has-a-government-inside-it.md @@ -1,5 +1,6 @@ --- title: "Your wallet has a government inside it" +type: essay description: "The credential can sit on your phone while the rules about valid issuers, revocation and recovery remain thoroughly institutional." published: 2026-07-14 editorialOrder: 11 diff --git a/src/lib/git.ts b/src/lib/git.ts index 4ff1f98..7d774e7 100644 --- a/src/lib/git.ts +++ b/src/lib/git.ts @@ -6,6 +6,32 @@ export interface MaintenanceCommit { subject: string; } +export function correctionCommits(): MaintenanceCommit[] { + try { + const output = execFileSync( + 'git', + [ + 'log', + '--grep=^Correction:', + '--date=short', + '--pretty=format:%h%x09%ad%x09%s', + ], + { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }, + ); + + return output + .trim() + .split('\n') + .filter(Boolean) + .map((line: string) => { + const [hash, date, ...subject] = line.split('\t'); + return { hash, date, subject: subject.join(' ') }; + }); + } catch { + return []; + } +} + export function recentMaintenance(limit = 4): MaintenanceCommit[] { try { const output = execFileSync( diff --git a/src/pages/corrections.astro b/src/pages/corrections.astro new file mode 100644 index 0000000..9925a41 --- /dev/null +++ b/src/pages/corrections.astro @@ -0,0 +1,101 @@ +--- +import BaseLayout from '../layouts/BaseLayout.astro'; +import { correctionCommits } from '../lib/git'; +import { site } from '../site.config'; + +const corrections = correctionCommits(); +--- + + +
+

The record

+

Corrections

+
+

+ When published work turns out to be wrong in a way that matters, the fix is recorded here — drawn + automatically from the publication's revision history, not maintained by hand. A correction is a + commit whose message begins with Correction:; this page cannot show fewer corrections + than the repository contains. +

+

+ Typo fixes and routine maintenance don't qualify. Changed claims, wrong facts, and misattributions do. + The editorial commitments say what + readers may hold us to; the full revision + history shows everything else. +

+
+ {corrections.length > 0 ? ( +
    + {corrections.map((commit) => ( +
  1. + + {commit.subject.replace(/^Correction:\s*/, '')} + {commit.hash} +
  2. + ))} +
+ ) : ( +

+ No substantive corrections have been required yet. That sentence should get harder to keep + writing as the archive grows — if it doesn't, be suspicious. +

+ )} +
+
+ + diff --git a/src/pages/opine.astro b/src/pages/opine.astro new file mode 100644 index 0000000..4d10f1a --- /dev/null +++ b/src/pages/opine.astro @@ -0,0 +1,17 @@ +--- +import { getCollection } from 'astro:content'; +import StoryArchive from '../components/StoryArchive.astro'; +import BaseLayout from '../layouts/BaseLayout.astro'; + +const essays = (await getCollection('stories', ({ data }) => !data.draft && data.type === 'essay')) + .sort((a, b) => a.data.editorialOrder - b.data.editorialOrder); +--- + + + + diff --git a/src/pages/stories/index.astro b/src/pages/stories/index.astro index 12e3023..5541e96 100644 --- a/src/pages/stories/index.astro +++ b/src/pages/stories/index.astro @@ -1,67 +1,18 @@ --- import { getCollection } from 'astro:content'; -import StoryCard from '../../components/StoryCard.astro'; +import StoryArchive from '../../components/StoryArchive.astro'; import BaseLayout from '../../layouts/BaseLayout.astro'; const stories = (await getCollection('stories', ({ data }) => !data.draft)) .sort((a, b) => a.data.editorialOrder - b.data.editorialOrder); +const reportCount = stories.filter(({ data }) => data.type === 'report').length; --- -
-

Stories

-

{stories.length} reports, histories and essays First collection

-
-
- {stories.length > 0 ? stories.map((entry, index) => ) :

The first story is being prepared.

} -
+
- - diff --git a/src/pages/tags/[tag].astro b/src/pages/tags/[tag].astro new file mode 100644 index 0000000..20e3aca --- /dev/null +++ b/src/pages/tags/[tag].astro @@ -0,0 +1,37 @@ +--- +import { getCollection } from 'astro:content'; +import StoryArchive from '../../components/StoryArchive.astro'; +import BaseLayout from '../../layouts/BaseLayout.astro'; + +export async function getStaticPaths() { + const stories = await getCollection('stories', ({ data }) => !data.draft); + const counts = new Map(); + for (const tag of stories.flatMap(({ data }) => data.tags)) { + counts.set(tag, (counts.get(tag) ?? 0) + 1); + } + // A subject earns a page once a second story carries it. + return [...counts.entries()] + .filter(([, count]) => count >= 2) + .map(([tag]) => ({ + params: { tag }, + props: { entries: stories.filter(({ data }) => data.tags.includes(tag)) }, + })); +} + +const { tag } = Astro.params; +const { entries } = Astro.props; +const sorted = entries.sort((a, b) => a.data.editorialOrder - b.data.editorialOrder); +const reportCount = sorted.filter(({ data }) => data.type === 'report').length; +--- + + + + diff --git a/src/pages/whats-up.astro b/src/pages/whats-up.astro new file mode 100644 index 0000000..e5a8365 --- /dev/null +++ b/src/pages/whats-up.astro @@ -0,0 +1,19 @@ +--- +import { getCollection } from 'astro:content'; +import StoryArchive from '../components/StoryArchive.astro'; +import BaseLayout from '../layouts/BaseLayout.astro'; + +const reports = (await getCollection('stories', ({ data }) => !data.draft && data.type === 'report')) + .sort((a, b) => b.data.published.getTime() - a.data.published.getTime()); +--- + + + + diff --git a/src/site.config.ts b/src/site.config.ts index 7e7cc91..6faee8a 100644 --- a/src/site.config.ts +++ b/src/site.config.ts @@ -11,6 +11,7 @@ export const site = { repositoryUrl: 'https://git.frrn.life/ana/trust-issues', newsletterUrl: '', podcastFeedUrl: '/podcast/feed.xml', + forumUrl: '', contactUrl: '', book: { enabled: false, @@ -23,10 +24,10 @@ export const site = { } as const; export const navigation = [ - { href: '/stories', label: 'Stories' }, - { href: '/briefing', label: 'Briefing' }, + { href: '/whats-up', label: "What's up" }, + { href: '/opine', label: 'Opine' }, { href: '/podcast', label: 'Podcast' }, - { href: '/guides', label: 'Guides' }, { href: '/book', label: 'Book' }, - { href: '/about', label: 'About' }, + { href: '/guides', label: 'Guides' }, + { href: '/forum', label: 'Forum' }, ] as const;