diff --git a/scripts/seed-demo.js b/scripts/seed-demo.js index 9f84a8e..abcf664 100644 --- a/scripts/seed-demo.js +++ b/scripts/seed-demo.js @@ -247,7 +247,9 @@ for (const c of contribs) { const dispatchSeed = [ { kind: 'decision', ageDays: 2, title: 'We are deprioritising public-cloud parity for Q3', - excerpt: 'After three weeks of pilot feedback, the team is locking the platform to on-prem and Hetzner sovereign cloud for the next quarter.', + excerpt: `After three weeks of pilot feedback — the kind of feedback that only happens when people are actually trying to deploy this thing — we are deprioritising public-cloud parity for Q3. + +The signal was unambiguous. Every council member we spoke to in May has the same constraint: the data cannot leave their network. AWS, Azure, GCP are non-starters not because of price but because of jurisdiction. So for Q3 the platform supports two deployment targets only — on-prem inside the customer's own VPC, and our Hetzner sovereign cloud in Helsinki.`, body: `After three weeks of pilot feedback — the kind of feedback that only happens when people are actually trying to deploy this thing — we are deprioritising public-cloud parity for Q3. The signal was unambiguous. Every council member we spoke to in May has the same constraint: the data cannot leave their network. AWS, Azure, GCP are non-starters not because of price but because of jurisdiction. diff --git a/src/components/LatestDispatchBanner.astro b/src/components/LatestDispatchBanner.astro index 227b6c2..949d94a 100644 --- a/src/components/LatestDispatchBanner.astro +++ b/src/components/LatestDispatchBanner.astro @@ -1,147 +1,208 @@ --- -import Avatar from './Avatar.astro'; import { getLatestPublishedDispatches } from '../lib/db'; import { - dispatchSlug, dispatchExcerptParas, relativeTime, - dispatchKindLabel, dispatchKindPigment, + dispatchSlug, dispatchKindLabel, splitExcerpt, relativeTime, } from '../lib/format'; const [latest] = getLatestPublishedDispatches(1); -const excerpt = latest ? dispatchExcerptParas(latest).lead : ''; + +const [p1, p2] = latest + ? splitExcerpt(latest.excerpt || latest.body) + : ['', null]; + +// Mark p2 with an ellipsis when the source extends beyond what we used — +// i.e. the body is longer than excerpt + paragraph break. +const sourceLen = latest ? (latest.excerpt || latest.body).trim().length : 0; +const usedLen = p1.length + (p2 ? p2.length + 2 : 0); +const truncated = sourceLen > usedLen + 4; + +const authorFirstName = latest ? latest.author_name.split(' ')[0] : ''; +const authorInitial = authorFirstName ? authorFirstName[0].toUpperCase() : ''; +const authorRole = latest?.author_title ?? 'team'; --- {latest && ( -
-
- Read dispatch - All dispatches → +

{latest.title}

+ +
+
+

{p1}

+ {p2 && ( +

{p2}{truncated ? '…' : ''}

+ )} +
+ +
+
+
+

{authorFirstName}

+

{authorRole}

+
+
{authorInitial}
+
+ + Read full dispatch → + +
- + +
)} diff --git a/src/components/admin/DispatchesTab.astro b/src/components/admin/DispatchesTab.astro index a0628bd..bd620a7 100644 --- a/src/components/admin/DispatchesTab.astro +++ b/src/components/admin/DispatchesTab.astro @@ -66,8 +66,9 @@ const defaultAuthorId = editing?.author_id ?? currentUserId;
- - + + + Write 2–4 sentences. The first sentence becomes the lead paragraph on the /roadmap dispatch banner; the rest follows in muted text. Use a blank line to control the paragraph break. Falls back to the first ~200 chars of the body if empty.
diff --git a/src/lib/format.ts b/src/lib/format.ts index 0fce83e..2b58881 100644 Binary files a/src/lib/format.ts and b/src/lib/format.ts differ