feat(docs): update docs ui and examples#159
Conversation
- Use docs-kit V2 layout, sidebar, slug strip, and TOC components - Import upstream docs-kit brutalist and prose styles - Add Lucide section icons for docs navigation
- Use the upstream docs-kit examples shell and BrutIndexV2 index - Drive example cards from the sitemap manifest and page metadata - Update the examples sitemap lastmod
- Generate demo manifests for example source snippets - Move demo components into the upstream demos/Default.svelte shape - Wire CodeReferenceV2 copy panels into individual example pages - Ignore generated docs manifest files
- Restyle the basic cache demo with the V2 example chrome - Add miss-state telemetry and focused side-rail notes
- Restyle the statistics demo with the V2 example chrome - Keep the event log scroll-contained inside the demo panel
- Restyle the LRU demo with the V2 example chrome - Keep eviction history scroll-contained inside the demo panel
- Restyle the TTL demo with the V2 example chrome - Add a spring-driven svelte-motion TTL meter - Keep expiring entries scroll-contained inside the demo panel
- Update docs-kit to the split demo manifest release - Load example code panels from virtual demo modules - Add local virtual module typing for lazy code samples
Bring the homepage masthead in line with the upstream brutalist hero while keeping the existing feature and code sections in place.
Set the stored theme class before generated CSS reaches the page and mirror upstream chunking for motion and mode-watcher client code.
Fetch live npm package stats through docs-kit and surface the version, tarball size, runtime deps, and API facts in the homepage masthead area.
📝 WalkthroughWalkthroughDocumentation site migrated to docs-kit v2 with component upgrades (Header/Footer/layouts), Vite-integrated sitemap/demo manifest generation, dark-mode theme initialization, modular interactive demo restructuring, and a redesigned landing page integrating a live MemoryCache telemetry demo. ChangesDocs Kit V2 Migration and Landing Page Redesign
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
docs/src/routes/examples/+page.ts (1)
3-6: ⚡ Quick winUse
interfacefor theExampleEntryobject shape.♻️ Proposed change
-type ExampleEntry = { - title: string - description: string -} +interface ExampleEntry { + title: string + description: string +}As per coding guidelines: "Prefer interface for defining object shapes in TypeScript".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/src/routes/examples/`+page.ts around lines 3 - 6, The type alias ExampleEntry should be converted to an interface to follow the project's TypeScript guideline; replace the type declaration named ExampleEntry with an interface declaration (interface ExampleEntry { title: string; description: string }) and update any usages if needed to ensure they still accept the same shape.docs/src/routes/examples/+page.svelte (1)
6-9: ⚡ Quick winUse
interfacefor theExampleDataobject shape.♻️ Proposed change
- type ExampleData = { - title: string - description: string - } + interface ExampleData { + title: string + description: string + }Note this duplicates
ExampleEntryin+page.ts— consider sharing a single type if convenient. As per coding guidelines: "Prefer interface for defining object shapes in TypeScript".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/src/routes/examples/`+page.svelte around lines 6 - 9, Replace the type alias ExampleData with an interface declaration (i.e., declare interface ExampleData { title: string; description: string }) to follow the guideline preferring interfaces for object shapes; also consider consolidating or re-exporting the shape used by ExampleEntry in +page.ts so both components share the same interface rather than duplicating the definition.docs/src/routes/+page.svelte (2)
77-81: ⚡ Quick winUse
constfor these derived values (ESLintprefer-consterrors).
$derivedworks withconstin Svelte 5; none of these are reassigned, so the lint errors here will fail the build.♻️ Proposed fix
- let demoRequests = $derived(demoHits + demoMisses) - let demoHitRate = $derived(demoRequests > 0 ? Math.round((demoHits / demoRequests) * 100) : 100) - let demoLruKey = $derived(demoEntries[0]?.key ?? 'none') - let demoMruKey = $derived(demoEntries.at(-1)?.key ?? 'none') - let demoStatus = $derived(demoLastOp === 'miss' ? 'miss' : 'ready') + const demoRequests = $derived(demoHits + demoMisses) + const demoHitRate = $derived(demoRequests > 0 ? Math.round((demoHits / demoRequests) * 100) : 100) + const demoLruKey = $derived(demoEntries[0]?.key ?? 'none') + const demoMruKey = $derived(demoEntries.at(-1)?.key ?? 'none') + const demoStatus = $derived(demoLastOp === 'miss' ? 'miss' : 'ready')🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/src/routes/`+page.svelte around lines 77 - 81, Change the four derived bindings from let to const since they are never reassigned; update demoRequests, demoHitRate, demoLruKey, demoMruKey, and demoStatus to be declared with const and continue using $derived (Svelte 5 supports const for derived stores) so ESLint prefer-const errors are resolved.
41-45: ⚡ Quick winPrefer
interfacefor theDemoEntryobject shape.
StatItemalready usesinterface; alignDemoEntryfor consistency.As per coding guidelines: "Prefer interface for defining object shapes in TypeScript".♻️ Proposed fix
- type DemoEntry = { - key: string - value: string - rank: number - } + interface DemoEntry { + key: string + value: string + rank: number + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/src/routes/`+page.svelte around lines 41 - 45, Replace the object-style type alias for DemoEntry with an interface to match StatItem: change the declaration "type DemoEntry = { key: string; value: string; rank: number }" to "interface DemoEntry { key: string; value: string; rank: number }" (keeping the same property names and types) so the shape is defined consistently across the module.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/src/routes/docs/`+layout.svelte:
- Around line 54-72: The inline JSON-LD built by the template uses
JSON.stringify(...) inside the returned script tag and may contain "</script>"
in title/description which would terminate the script; fix by post-processing
the JSON string before interpolation — capture the JSON.stringify(...) output
and replace occurrences of "</script>" (or all "<" characters) with their
escaped form (e.g., "\u003C/script>" or "\u003C") so the serialized payload
cannot break out of the <script> tag; update the template return in
+layout.svelte to use the escaped JSON string instead of the raw JSON.stringify
result.
In `@docs/svelte.config.js`:
- Around line 45-49: The CSP in the svelte config sets mode: 'hash' but still
includes 'unsafe-inline' in the directives.script-src array; remove
'unsafe-inline' from the 'script-src' entry in the config (inside the directives
object) so inline scripts are only allowed via hashes/nonces, and ensure any
required script hashes or nonces are added to the CSP instead of using
'unsafe-inline'.
---
Nitpick comments:
In `@docs/src/routes/`+page.svelte:
- Around line 77-81: Change the four derived bindings from let to const since
they are never reassigned; update demoRequests, demoHitRate, demoLruKey,
demoMruKey, and demoStatus to be declared with const and continue using $derived
(Svelte 5 supports const for derived stores) so ESLint prefer-const errors are
resolved.
- Around line 41-45: Replace the object-style type alias for DemoEntry with an
interface to match StatItem: change the declaration "type DemoEntry = { key:
string; value: string; rank: number }" to "interface DemoEntry { key: string;
value: string; rank: number }" (keeping the same property names and types) so
the shape is defined consistently across the module.
In `@docs/src/routes/examples/`+page.svelte:
- Around line 6-9: Replace the type alias ExampleData with an interface
declaration (i.e., declare interface ExampleData { title: string; description:
string }) to follow the guideline preferring interfaces for object shapes; also
consider consolidating or re-exporting the shape used by ExampleEntry in
+page.ts so both components share the same interface rather than duplicating the
definition.
In `@docs/src/routes/examples/`+page.ts:
- Around line 3-6: The type alias ExampleEntry should be converted to an
interface to follow the project's TypeScript guideline; replace the type
declaration named ExampleEntry with an interface declaration (interface
ExampleEntry { title: string; description: string }) and update any usages if
needed to ensure they still accept the same shape.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: ecc2e239-f9b0-4e33-bf96-103a07862c5b
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml,!pnpm-lock.yaml
📒 Files selected for processing (34)
.github/workflows/cloudflare-deploy.yml.gitignoredocs/.gitignoredocs/package.jsondocs/scripts/generate-sitemap-manifest.mjsdocs/src/app.cssdocs/src/app.htmldocs/src/lib/components/general/Footer.sveltedocs/src/lib/components/general/Header.sveltedocs/src/lib/docsNav.tsdocs/src/lib/examples/BasicCache.sveltedocs/src/lib/examples/CacheStatistics.sveltedocs/src/lib/examples/LruEviction.sveltedocs/src/lib/examples/TtlExpiration.sveltedocs/src/lib/examples/basic-cache/demos/Default.sveltedocs/src/lib/examples/cache-statistics/demos/Default.sveltedocs/src/lib/examples/lru-eviction/demos/Default.sveltedocs/src/lib/examples/ttl-expiration/demos/Default.sveltedocs/src/lib/sitemap-manifest.jsondocs/src/routes/+layout.sveltedocs/src/routes/+page.server.tsdocs/src/routes/+page.sveltedocs/src/routes/+page.tsdocs/src/routes/docs/+layout.sveltedocs/src/routes/docs/TableOfContents.sveltedocs/src/routes/examples/+layout.sveltedocs/src/routes/examples/+page.sveltedocs/src/routes/examples/+page.tsdocs/src/routes/examples/basic-cache/+page.sveltedocs/src/routes/examples/cache-statistics/+page.sveltedocs/src/routes/examples/lru-eviction/+page.sveltedocs/src/routes/examples/ttl-expiration/+page.sveltedocs/svelte.config.jsdocs/vite.config.ts
💤 Files with no reviewable changes (7)
- docs/src/lib/examples/LruEviction.svelte
- docs/src/lib/sitemap-manifest.json
- docs/src/lib/examples/TtlExpiration.svelte
- docs/src/routes/docs/TableOfContents.svelte
- docs/src/lib/examples/CacheStatistics.svelte
- docs/src/lib/examples/BasicCache.svelte
- docs/scripts/generate-sitemap-manifest.mjs
| return `<${'script'} type="application/ld+json">${JSON.stringify({ | ||
| '@context': 'https://schema.org', | ||
| '@type': 'TechArticle', | ||
| headline: title, | ||
| description: description || title, | ||
| url: `${BASE_URL}${pathname}`, | ||
| dateModified: lastmod, | ||
| author: { | ||
| '@type': 'Organization', | ||
| name: 'Humanspeak', | ||
| url: 'https://humanspeak.com' | ||
| }, | ||
| publisher: { | ||
| '@type': 'Organization', | ||
| name: 'Humanspeak', | ||
| url: 'https://humanspeak.com' | ||
| }, | ||
| proficiencyLevel: 'Beginner' | ||
| })}</${'script'}>` |
There was a problem hiding this comment.
Escape < in the JSON-LD payload to prevent early </script> termination.
JSON.stringify won't escape </script> inside title/description, so any such sequence would close the inline script tag and inject markup. The <${'script'}> split only protects the literal tags, not the serialized content.
🛡️ Proposed fix
- })}</${'script'}>`
+ }).replace(/</g, '\\u003c')}</${'script'}>`📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| return `<${'script'} type="application/ld+json">${JSON.stringify({ | |
| '@context': 'https://schema.org', | |
| '@type': 'TechArticle', | |
| headline: title, | |
| description: description || title, | |
| url: `${BASE_URL}${pathname}`, | |
| dateModified: lastmod, | |
| author: { | |
| '@type': 'Organization', | |
| name: 'Humanspeak', | |
| url: 'https://humanspeak.com' | |
| }, | |
| publisher: { | |
| '@type': 'Organization', | |
| name: 'Humanspeak', | |
| url: 'https://humanspeak.com' | |
| }, | |
| proficiencyLevel: 'Beginner' | |
| })}</${'script'}>` | |
| return `<${'script'} type="application/ld+json">${JSON.stringify({ | |
| '`@context`': 'https://schema.org', | |
| '`@type`': 'TechArticle', | |
| headline: title, | |
| description: description || title, | |
| url: `${BASE_URL}${pathname}`, | |
| dateModified: lastmod, | |
| author: { | |
| '`@type`': 'Organization', | |
| name: 'Humanspeak', | |
| url: 'https://humanspeak.com' | |
| }, | |
| publisher: { | |
| '`@type`': 'Organization', | |
| name: 'Humanspeak', | |
| url: 'https://humanspeak.com' | |
| }, | |
| proficiencyLevel: 'Beginner' | |
| }).replace(/</g, '\\u003c')}</${'script'}>` |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/src/routes/docs/`+layout.svelte around lines 54 - 72, The inline JSON-LD
built by the template uses JSON.stringify(...) inside the returned script tag
and may contain "</script>" in title/description which would terminate the
script; fix by post-processing the JSON string before interpolation — capture
the JSON.stringify(...) output and replace occurrences of "</script>" (or all
"<" characters) with their escaped form (e.g., "\u003C/script>" or "\u003C") so
the serialized payload cannot break out of the <script> tag; update the template
return in +layout.svelte to use the escaped JSON string instead of the raw
JSON.stringify result.
| mode: 'hash', | ||
| directives: { | ||
| 'default-src': ['self'], | ||
| 'script-src': ['self', 'https://analytics.ahrefs.com'], | ||
| 'script-src': ['self', 'https://analytics.ahrefs.com', 'unsafe-inline'], | ||
| 'style-src': ['self', 'unsafe-inline'], |
There was a problem hiding this comment.
Remove 'unsafe-inline' from script-src in hash CSP mode.
Line 48 weakens CSP significantly; with hash mode, inline scripts should be allowed via hashes/nonces instead of a blanket inline allowance.
Suggested fix
csp: {
mode: 'hash',
directives: {
'default-src': ['self'],
- 'script-src': ['self', 'https://analytics.ahrefs.com', 'unsafe-inline'],
+ 'script-src': ['self', 'https://analytics.ahrefs.com'],
'style-src': ['self', 'unsafe-inline'],📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| mode: 'hash', | |
| directives: { | |
| 'default-src': ['self'], | |
| 'script-src': ['self', 'https://analytics.ahrefs.com'], | |
| 'script-src': ['self', 'https://analytics.ahrefs.com', 'unsafe-inline'], | |
| 'style-src': ['self', 'unsafe-inline'], | |
| mode: 'hash', | |
| directives: { | |
| 'default-src': ['self'], | |
| 'script-src': ['self', 'https://analytics.ahrefs.com'], | |
| 'style-src': ['self', 'unsafe-inline'], |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/svelte.config.js` around lines 45 - 49, The CSP in the svelte config
sets mode: 'hash' but still includes 'unsafe-inline' in the
directives.script-src array; remove 'unsafe-inline' from the 'script-src' entry
in the config (inside the directives object) so inline scripts are only allowed
via hashes/nonces, and ensure any required script hashes or nonces are added to
the CSP instead of using 'unsafe-inline'.
|
⏭️ NPM publishing was skipped due to the |
Summary
This PR updates the docs site to the upstream brutalist V2 design system and moves generated docs artifacts into the Vite build. It refreshes the homepage, docs pages, and examples so the site feels consistent with the newer Humanspeak docs while keeping Memory Cache-specific content, examples, and API data.
Changes
✨ New features
🔧 Refactoring/improvements
🐛 Bug fixes
📦 Build changes
🧪 Testing
Commits
05da058feat(docs): add upstream install footerca18c3afeat(docs): add homepage llm sectionbeedd67feat(docs): match upstream why section123a250fix(docs): use hash csp for inline scriptsa404d5ffeat(docs): add homepage cache telemetry demob371663fix(docs): allow nonce scripts in csp8107af2build(docs): update docs-kit demo type generation274d9fbperf: use generated demo code loaders36a09f0docs: add homepage package stats row0a1eb75fix: improve docs first paint theme1ece9ecdocs: update homepage hero9023db9perf: lazy load example code samples234553edocs: add spring capacity meter to lru exampleb6d9c9cdocs: update ttl expiration example shell72f107adocs: update lru eviction example shellb1782fbdocs: update cache statistics example shell5ff9389docs: update basic cache example shell1ce1611docs: add code panels to examples3530dbedocs: update examples index to V2 layoute5cae17docs: update docs pages to V2 layoutd865b11docs: use updated docs header and footerbe96386docs: generate sitemap manifest in Vite