From 9fcef5ffcc027cee312cebd4bc7df8ebb4cb05fc Mon Sep 17 00:00:00 2001 From: Harlan Wilton Date: Wed, 14 Oct 2026 00:46:50 +1100 Subject: [PATCH] fix(pages): reduce payloads and preserve source controls --- app/assets/css/main.css | 51 +++++++ app/components/WeeklyEmailPreview.vue | 12 +- app/pages/index.vue | 2 + layers/identity/server/api/digest/demo.get.ts | 21 ++- .../identity/server/utils/weekly-template.ts | 10 +- .../components/FrameworkSkillsDirectory.vue | 6 +- .../marketing/app/pages/frameworks/react.vue | 5 +- .../app/utils/framework-directory.ts | 22 +++ .../registry/app/components/SkillDetail.vue | 129 +++++++++++++----- .../app/utils/skill-detail-payload.ts | 25 ++++ .../server/utils/skill-md-render.spec.ts | 5 +- shared/highlight.ts | 16 +-- test/unit/highlight-code-body.test.ts | 3 +- test/unit/pnpm-package-panel.nuxt.test.ts | 2 +- ...tail-duplicate-canonical-path.nuxt.test.ts | 4 +- .../skill-detail-howto-schema.nuxt.test.ts | 4 +- test/unit/skill-detail-payload.test.ts | 32 +++++ test/unit/weekly-template.test.ts | 15 +- 18 files changed, 289 insertions(+), 75 deletions(-) create mode 100644 layers/marketing/app/utils/framework-directory.ts create mode 100644 layers/registry/app/utils/skill-detail-payload.ts create mode 100644 test/unit/skill-detail-payload.test.ts diff --git a/app/assets/css/main.css b/app/assets/css/main.css index b40b36ee..78947b6f 100644 --- a/app/assets/css/main.css +++ b/app/assets/css/main.css @@ -875,6 +875,25 @@ content: none; } +/* Shared GitHub token palette. Persisted inline colours remain supported. */ +.shj-kwd { color: #cf222e; --shiki-dark: #ff7b72; } +.shj-oper { color: #cf222e; --shiki-dark: #ff7b72; } +.shj-err { color: #82071e; --shiki-dark: #ffa198; } +.shj-deleted { color: #82071e; --shiki-dark: #ffa198; } +.shj-class { color: #953800; --shiki-dark: #ffa657; } +.shj-cmnt { color: #6e7781; --shiki-dark: #8b949e; } +.shj-bracket { color: #57606a; --shiki-dark: #8b949e; } +.shj-num { color: #0550ae; --shiki-dark: #79c0ff; } +.shj-bool { color: #0550ae; --shiki-dark: #79c0ff; } +.shj-type { color: #0550ae; --shiki-dark: #79c0ff; } +.shj-section { color: #0550ae; --shiki-dark: #79c0ff; } +.shj-var { color: #0550ae; --shiki-dark: #79c0ff; } +.shj-str { color: #0a3069; --shiki-dark: #a5d6ff; } +.shj-func { color: #8250df; --shiki-dark: #d2a8ff; } +.shj-insert { color: #116329; --shiki-dark: #7ee787; } +.shj-esc { color: #1f2328; --shiki-dark: #e6edf3; } +.dark :is(.shj-esc, .shj-kwd, .shj-oper, .shj-err, .shj-deleted, .shj-class, .shj-cmnt, .shj-bracket, .shj-num, .shj-bool, .shj-type, .shj-section, .shj-var, .shj-str, .shj-func, .shj-insert) { color: var(--shiki-dark); } + /* Highlighted code (rangi). The light colour is inlined on each token and the dark one rides along as `--shiki-dark`, so dark mode has to win over an inline style. */ @@ -1235,3 +1254,35 @@ opacity: 0.28; pointer-events: none; } + + +/* The email preview shares one card across both colour modes. */ +.weekly-preview { + --email-page: #f5f4f2; + --email-surface: #ffffff; + --email-border: #e7e5e4; + --email-borderStrong: #d6d3d1; + --email-text: #1c1917; + --email-body: #44403c; + --email-muted: #6b625c; + --email-faint: #6b625c; + --email-accent: #be123c; + --email-onAccent: #ffffff; + --email-quote: #fafaf9; + --email-mark: #fb7185; +} + +.dark .weekly-preview { + --email-page: #14110d; + --email-surface: #1c1917; + --email-border: #3a342c; + --email-borderStrong: #4d453b; + --email-text: #ede9e4; + --email-body: #cdc6bd; + --email-muted: #9c9389; + --email-faint: #7a726a; + --email-accent: #fb7185; + --email-onAccent: #1c1917; + --email-quote: #211d18; + --email-mark: #fb7185; +} diff --git a/app/components/WeeklyEmailPreview.vue b/app/components/WeeklyEmailPreview.vue index 44674816..50d186fa 100644 --- a/app/components/WeeklyEmailPreview.vue +++ b/app/components/WeeklyEmailPreview.vue @@ -11,20 +11,16 @@ import type { DigestDemoResponse } from '#layers/identity/server/api/digest/demo // Only the card and its row count reach the payload. The answer also carries // the whole email as `html`, which this preview never renders. const { data: demo } = await useFetch('/api/digest/demo', { - key: 'home-digest-demo-v1', + key: 'home-digest-demo-v2', transform: ({ card, rowCount }: DigestDemoResponse) => ({ card, rowCount }), }) const hasDemo = computed(() => !!demo.value?.card && (demo.value?.rowCount ?? 0) > 0) /** - * The preview follows the page's colour mode. Both cards ship in the payload, - * so switching themes costs no request. + * CSS changes the card's palette. Switching themes costs no request. */ -const colorMode = useColorMode() -const card = computed(() => - colorMode.value === 'dark' ? demo.value?.card.dark : demo.value?.card.light, -) +const card = computed(() => demo.value?.card)