@aureuma/svelta 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +14 -0
  3. package/.changeset/publish-blogkit.md +5 -0
  4. package/.github/workflows/release.yml +65 -0
  5. package/LICENSE +22 -0
  6. package/README.md +35 -0
  7. package/docs/mintlify-blog-study.md +697 -0
  8. package/package.json +59 -0
  9. package/packages/blogkit/CHANGELOG.md +6 -0
  10. package/packages/blogkit/LICENSE +22 -0
  11. package/packages/blogkit/README.md +93 -0
  12. package/packages/blogkit/dist/components/blog/Avatar.svelte +15 -0
  13. package/packages/blogkit/dist/components/blog/Avatar.svelte.d.ts +22 -0
  14. package/packages/blogkit/dist/components/blog/BackLink.svelte +23 -0
  15. package/packages/blogkit/dist/components/blog/BackLink.svelte.d.ts +21 -0
  16. package/packages/blogkit/dist/components/blog/BlogCard.svelte +37 -0
  17. package/packages/blogkit/dist/components/blog/BlogCard.svelte.d.ts +22 -0
  18. package/packages/blogkit/dist/components/blog/BlogHeroCard.svelte +36 -0
  19. package/packages/blogkit/dist/components/blog/BlogHeroCard.svelte.d.ts +21 -0
  20. package/packages/blogkit/dist/components/blog/Container.svelte +8 -0
  21. package/packages/blogkit/dist/components/blog/Container.svelte.d.ts +29 -0
  22. package/packages/blogkit/dist/components/blog/ImageLightbox.svelte +58 -0
  23. package/packages/blogkit/dist/components/blog/ImageLightbox.svelte.d.ts +24 -0
  24. package/packages/blogkit/dist/components/blog/MorePosts.svelte +15 -0
  25. package/packages/blogkit/dist/components/blog/MorePosts.svelte.d.ts +21 -0
  26. package/packages/blogkit/dist/components/blog/ShareButtons.svelte +113 -0
  27. package/packages/blogkit/dist/components/blog/ShareButtons.svelte.d.ts +23 -0
  28. package/packages/blogkit/dist/components/blog/SummaryCard.svelte +11 -0
  29. package/packages/blogkit/dist/components/blog/SummaryCard.svelte.d.ts +20 -0
  30. package/packages/blogkit/dist/components/blog/TagTabs.svelte +32 -0
  31. package/packages/blogkit/dist/components/blog/TagTabs.svelte.d.ts +23 -0
  32. package/packages/blogkit/dist/index.d.ts +11 -0
  33. package/packages/blogkit/dist/index.js +11 -0
  34. package/packages/blogkit/dist/server/blog.d.ts +39 -0
  35. package/packages/blogkit/dist/server/blog.js +222 -0
  36. package/packages/blogkit/dist/server/index.d.ts +1 -0
  37. package/packages/blogkit/dist/server/index.js +1 -0
  38. package/packages/blogkit/dist/theme/ThemeSwitcher.svelte +34 -0
  39. package/packages/blogkit/dist/theme/ThemeSwitcher.svelte.d.ts +21 -0
  40. package/packages/blogkit/dist/theme/index.d.ts +2 -0
  41. package/packages/blogkit/dist/theme/index.js +2 -0
  42. package/packages/blogkit/dist/theme/store.d.ts +12 -0
  43. package/packages/blogkit/dist/theme/store.js +50 -0
  44. package/packages/blogkit/dist/types/blog.d.ts +31 -0
  45. package/packages/blogkit/dist/types/blog.js +1 -0
  46. package/packages/blogkit/package.json +66 -0
  47. package/packages/blogkit/src/lib/components/blog/Avatar.svelte +15 -0
  48. package/packages/blogkit/src/lib/components/blog/BackLink.svelte +23 -0
  49. package/packages/blogkit/src/lib/components/blog/BlogCard.svelte +37 -0
  50. package/packages/blogkit/src/lib/components/blog/BlogHeroCard.svelte +36 -0
  51. package/packages/blogkit/src/lib/components/blog/Container.svelte +8 -0
  52. package/packages/blogkit/src/lib/components/blog/ImageLightbox.svelte +58 -0
  53. package/packages/blogkit/src/lib/components/blog/MorePosts.svelte +15 -0
  54. package/packages/blogkit/src/lib/components/blog/ShareButtons.svelte +113 -0
  55. package/packages/blogkit/src/lib/components/blog/SummaryCard.svelte +11 -0
  56. package/packages/blogkit/src/lib/components/blog/TagTabs.svelte +32 -0
  57. package/packages/blogkit/src/lib/index.ts +15 -0
  58. package/packages/blogkit/src/lib/server/blog.ts +264 -0
  59. package/packages/blogkit/src/lib/server/index.ts +2 -0
  60. package/packages/blogkit/src/lib/theme/ThemeSwitcher.svelte +34 -0
  61. package/packages/blogkit/src/lib/theme/index.ts +3 -0
  62. package/packages/blogkit/src/lib/theme/store.ts +64 -0
  63. package/packages/blogkit/src/lib/types/blog.ts +36 -0
  64. package/packages/blogkit/svelte.config.js +8 -0
  65. package/packages/blogkit/tsconfig.json +5 -0
  66. package/playwright.config.ts +24 -0
  67. package/postcss.config.cjs +6 -0
  68. package/src/app.css +146 -0
  69. package/src/app.d.ts +13 -0
  70. package/src/app.html +26 -0
  71. package/src/content/blog/ai-summary-cards-with-frontmatter.md +32 -0
  72. package/src/content/blog/announcing-svelta-blog.md +19 -0
  73. package/src/content/blog/best-practices-ship-with-checklists.md +26 -0
  74. package/src/content/blog/building-a-mintlify-inspired-blog.md +49 -0
  75. package/src/content/blog/design-tokens-that-scale.md +47 -0
  76. package/src/content/blog/for-founders-why-speed-matters.md +23 -0
  77. package/src/content/blog/infinite-scroll-with-intersection-observer.md +37 -0
  78. package/src/content/blog/markdown-kitchen-sink.md +101 -0
  79. package/src/content/blog/markdown-pipeline-mdsvex-shiki.md +39 -0
  80. package/src/content/blog/rss-feeds-that-actually-work.md +25 -0
  81. package/src/content/blog/tag-tabs-and-mobile-fade-masks.md +25 -0
  82. package/src/lib/assets/favicon.svg +1 -0
  83. package/src/lib/components/site/SiteFooter.svelte +24 -0
  84. package/src/lib/components/site/SiteHeader.svelte +36 -0
  85. package/src/lib/content/authors.ts +28 -0
  86. package/src/lib/index.ts +1 -0
  87. package/src/lib/server/blog.ts +22 -0
  88. package/src/lib/server/rss.ts +58 -0
  89. package/src/lib/server/seo.ts +31 -0
  90. package/src/lib/stores/theme.ts +10 -0
  91. package/src/lib/types/blog.ts +1 -0
  92. package/src/routes/+layout.svelte +31 -0
  93. package/src/routes/+page.svelte +44 -0
  94. package/src/routes/blog/+page.server.ts +28 -0
  95. package/src/routes/blog/+page.svelte +122 -0
  96. package/src/routes/blog/[slug]/+page.server.ts +39 -0
  97. package/src/routes/blog/[slug]/+page.svelte +118 -0
  98. package/src/routes/blog/posts.json/+server.ts +32 -0
  99. package/src/routes/feed.xml/+server.ts +21 -0
  100. package/static/blog/authors/alex.svg +13 -0
  101. package/static/blog/authors/maria.svg +13 -0
  102. package/static/blog/authors/shawn.svg +13 -0
  103. package/static/blog/covers/ai-summary.svg +38 -0
  104. package/static/blog/covers/design-tokens.svg +37 -0
  105. package/static/blog/covers/infinite-scroll.svg +38 -0
  106. package/static/blog/covers/kitchen-sink.svg +36 -0
  107. package/static/blog/covers/markdown-pipeline.svg +41 -0
  108. package/static/blog/covers/mintlify-style.svg +35 -0
  109. package/static/blog/covers/rss.svg +34 -0
  110. package/static/robots.txt +3 -0
  111. package/svelte.config.js +70 -0
  112. package/tailwind.config.cjs +133 -0
  113. package/tests/blog.spec.ts +63 -0
  114. package/tsconfig.json +21 -0
  115. package/vite.config.ts +14 -0
@@ -0,0 +1,697 @@
1
+ # Mintlify Blog Study (Design + Implementation Notes for svelta)
2
+
3
+ Date: 2026-02-08
4
+
5
+ Scope: Build a SvelteKit + Markdown blogging system inspired by `https://www.mintlify.com/blog` (layout, typography scale, theming, cards, tagging, reading-time, RSS, post structure, share UI, responsive behavior, image framing).
6
+
7
+ Method: I used the Playwright MCP browser to inspect the blog index, multiple post pages, responsive breakpoints (desktop + mobile), and crawled a sample set of **36 posts** (latest + mid + older) to validate patterns across content types.
8
+
9
+ ## Guardrails (Important)
10
+
11
+ - “Inspired by” means we replicate **patterns** (layout rules, component roles, proportions), not Mintlify’s brand assets or content.
12
+ - Do not copy Mintlify’s copy, images, or proprietary CSS. Use our own components/tokens while matching the *system behavior*.
13
+
14
+ ---
15
+
16
+ ## 1) Expansion Of Each Requested Item (What You Mean) + Mintlify Lessons + How We’ll Implement
17
+
18
+ Each section follows:
19
+
20
+ - **What you mean**: clarified requirement
21
+ - **Mintlify lesson (observed)**: what Mintlify does in practice (numbers, placement, behavior)
22
+ - **Implementation notes (SvelteKit)**: concrete code approach (components, routes, data model)
23
+
24
+ ### 1. Element Placement
25
+
26
+ - **What you mean**: the page layout “grid” and where each UI chunk sits (hero, tag bar, cards; or back link, meta, title, author/share, content, more-posts).
27
+ - **Mintlify lesson (observed)**:
28
+ - Blog index: `max-w-5xl mx-auto px-6` container; hero card first; tag bar next; then a 2-col grid of cards.
29
+ - Post page: header stack (back link → category/read-time → title → date), then separator, then 2-col layout: content column + sticky author/share column.
30
+ - Post content column max width is **~628px** within an overall `max-w-4xl` container. The sticky side column is narrow (~150–160px) with a generous horizontal gap.
31
+ - **Implementation notes (SvelteKit)**:
32
+ - Blog index route: `src/routes/blog/+page.svelte`
33
+ - Post route: `src/routes/blog/[slug]/+page.svelte`
34
+ - Shared layout primitives: `src/lib/components/blog/Container.svelte`, `.../BlogHeroCard.svelte`, `.../BlogCard.svelte`, `.../PostLayout.svelte`.
35
+
36
+ ### 2. Design (Overall Visual Language)
37
+
38
+ - **What you mean**: the “feel”: minimal, crisp, high contrast, lots of whitespace, rounded media, small mono metadata.
39
+ - **Mintlify lesson (observed)**:
40
+ - Minimal chrome; strong hierarchy: hero image + title as primary attention.
41
+ - Rounded corners are consistent and token-like (24px for hero, 16px for card thumbnails).
42
+ - Metadata is “quiet” (mono uppercase, small size), while titles are clean and medium weight.
43
+ - **Implementation notes (SvelteKit)**:
44
+ - Tailwind + CSS variables for tokens; keep UI components small and composable.
45
+ - Avoid heavy component libraries; implement the specific widgets we need.
46
+
47
+ ### 3. Theming (Light/Dark/System)
48
+
49
+ - **What you mean**: global theme with correct contrasts across backgrounds, text, borders, code blocks, and cards; ideally includes system preference.
50
+ - **Mintlify lesson (observed)**:
51
+ - Theme switcher exists with **three modes**: system / light / dark.
52
+ - The site toggles by applying an `html` class (`light` or `dark`).
53
+ - Colors are tokenized (classes like `bg-background-soft`, `text-text-sub`, `text-brand`).
54
+ - **Implementation notes (SvelteKit)**:
55
+ - Theme store that applies `document.documentElement.classList` (`light`/`dark`) and supports `system`.
56
+ - A footer (or header) `ThemeSwitcher.svelte` with radio buttons.
57
+ - Code blocks: Shiki dual theme (one-light + github-dark-default) to match Mintlify’s behavior.
58
+
59
+ ### 4. Typeface, Sizes, Proportions
60
+
61
+ - **What you mean**: exact hierarchy for headings/body/meta, line-heights, tracking, and spacing.
62
+ - **Mintlify lesson (observed)**:
63
+ - Sans font: **Inter** (body + titles).
64
+ - Mono font: **Geist Mono** (category/read time/date + “SUMMARY” label + share heading).
65
+ - Post title (`h1`) approx: `font-weight 600`, **40px** size, **44px** line-height, `letter-spacing ~ -0.8px`.
66
+ - Content headings:
67
+ - `h2`: **24px**, `font-weight 500`, `line-height 31.2px`, `letter-spacing -0.24px`, `scroll-mt-20`.
68
+ - `h3`: **20px**, `font-weight 500`, `line-height 26px`, `letter-spacing -0.24px`.
69
+ - Card title: **20px** / 30px, medium weight; excerpt: **14px** / 21px.
70
+ - Meta pills (category/read): mono **12px**, uppercase, tracking **0.6px**.
71
+ - **Implementation notes (SvelteKit)**:
72
+ - Install `@fontsource/inter` and `@fontsource/geist-mono`.
73
+ - Define Tailwind typography scale for `h1/h2/h3/p` inside blog content.
74
+
75
+ ### 5. Tags (Categories) + Filtering
76
+
77
+ - **What you mean**: tagging posts and browsing by tag via a tag bar and tag display on cards/posts.
78
+ - **Mintlify lesson (observed)**:
79
+ - Uses a **category tab bar**: “All articles”, “AI trends”, “Announcements”, “For founders”, “Engineering”, “Design”, “Best practices”.
80
+ - Category is shown above titles as a mono uppercase label (brand color).
81
+ - Category filtering does **not** change URL on Mintlify (client-side tab state).
82
+ - Note: category capitalization varies across older posts (“Best Practices” vs “Best practices”, “For Founders” vs “For founders”).
83
+ - **Implementation notes (SvelteKit)**:
84
+ - Frontmatter fields: `category` (single) + optional `tags` (list).
85
+ - UI: tabs filter the card grid; hero card remains fixed (matches Mintlify).
86
+ - Normalize categories (slugify + canonical casing) to avoid duplicates.
87
+ - We can optionally reflect filter in URL query `?category=` for shareability while keeping UX identical.
88
+
89
+ ### 6. Color Contrasts
90
+
91
+ - **What you mean**: correct AA-level readability, subtle borders, muted text for metadata, brand accent usage.
92
+ - **Mintlify lesson (observed)**:
93
+ - Brand accent used sparingly (category label).
94
+ - Meta text uses reduced opacity (e.g., ~60% for secondary).
95
+ - Borders are extremely subtle (e.g., ~7% opacity frame border on content images).
96
+ - **Implementation notes (SvelteKit)**:
97
+ - Define tokens:
98
+ - `--background-main`, `--background-soft`, `--background-invert`
99
+ - `--text-main`, `--text-sub`, `--muted`
100
+ - `--border-soft`
101
+ - `--brand`
102
+ - Use Tailwind color mapping to CSS vars: `text-text-sub`, `bg-background-soft`, etc.
103
+
104
+ ### 7. View Widgets (Metadata Widgets)
105
+
106
+ - **What you mean**: the small informational UI bits: read time, date, category, maybe views; where they appear.
107
+ - **Mintlify lesson (observed)**:
108
+ - Post header shows: `CATEGORY / N minutes read` (mono uppercase).
109
+ - Post header also shows date (mono uppercase) beneath title.
110
+ - Index hero shows `Date • N min read`.
111
+ - No “view count” in the UI (from what we observed); the “widget” is mostly read time + date + category.
112
+ - **Implementation notes (SvelteKit)**:
113
+ - Compute reading time from markdown word count (server-side).
114
+ - Date formatting helper (e.g., “February 7, 2026”).
115
+ - Optional extension: view counts can be added later via an analytics service; keep UI slot reserved but hidden by default.
116
+
117
+ ### 8. Content Loading (Infinite Scroll / “Recycled Scroll”)
118
+
119
+ - **What you mean**: blog index should progressively load content; ideally efficient rendering as list grows.
120
+ - **Mintlify lesson (observed)**:
121
+ - As you scroll down `/blog`, more post cards appear; there is **no Load More button**.
122
+ - On mobile, the tag bar is horizontally scrollable with fade-mask edges and no scrollbar.
123
+ - **Implementation notes (SvelteKit)**:
124
+ - Server: expose an endpoint `GET /blog/posts.json?offset=&limit=&category=` returning metadata.
125
+ - Client: `IntersectionObserver` sentinel triggers fetch and appends.
126
+ - Keep DOM light:
127
+ - MVP: pagination + append (fast enough for ~100–300 posts).
128
+ - Optional: virtualization later if needed (e.g. `@tanstack/svelte-virtual`).
129
+
130
+ ### 9. Author Profile Avatar
131
+
132
+ - **What you mean**: consistent author identity visuals (avatar image, fallback initials, sizing, rounding).
133
+ - **Mintlify lesson (observed)**:
134
+ - Avatars are circular with `rounded-full`, size **48x48** (`size-12`).
135
+ - Some cards use author image `/blog/authors/*.webp`; fallback initials appear in snapshots for some cases.
136
+ - **Implementation notes (SvelteKit)**:
137
+ - Authors registry (`src/lib/content/authors.ts`) with `id`, `name`, `title`, `avatar`.
138
+ - `Avatar.svelte`:
139
+ - render `<img>` if available
140
+ - fallback to initials with subtle background.
141
+
142
+ ### 10. Author Name + Title Showing
143
+
144
+ - **What you mean**: show author identity both on cards and on post page.
145
+ - **Mintlify lesson (observed)**:
146
+ - Cards show author name + role underneath excerpt.
147
+ - Post page sticky column shows author name + title above share buttons.
148
+ - On mobile, author block moves into header area under title.
149
+ - **Implementation notes (SvelteKit)**:
150
+ - `AuthorChip.svelte` used by cards and post layout.
151
+ - Responsive rendering: `md:hidden` vs `hidden md:flex` blocks.
152
+
153
+ ### 11. Article Formatting (Markdown Typesetting)
154
+
155
+ - **What you mean**: clean rendering for headings, paragraphs, lists, blockquotes, code, tables, and links.
156
+ - **Mintlify lesson (observed)**:
157
+ - Headings have anchor links (each heading is linkable); `scroll-mt-20` offsets the fixed header.
158
+ - Inline code has subtle background, padding, and radius.
159
+ - Blockquotes use a left border and padding-left.
160
+ - Code blocks use **Shiki** (`pre.shiki shiki-themes one-light github-dark-default`), ~14px font, 24px line-height, `border-radius: 6px`, `padding: 12px 16px`.
161
+ - Tables exist in some posts; must be styled.
162
+ - **Implementation notes (SvelteKit)**:
163
+ - Use `mdsvex` + `remark-gfm` + `rehype-slug` + `rehype-autolink-headings`.
164
+ - Use Shiki to highlight fenced code blocks; match Mintlify’s pre styling.
165
+ - Add a small CSS layer for `.blog-prose` to tune margins and colors.
166
+
167
+ ### 12. Content Format + Display
168
+
169
+ - **What you mean**: the pipeline from markdown/frontmatter to rendered post, including excerpt generation and cover images.
170
+ - **Mintlify lesson (observed)**:
171
+ - Every post has a hero image at top (alt equals title), with rounded 24px, object-cover, max height ~360.
172
+ - Most posts have an AI “SUMMARY” card after hero; at least one post (`/blog/mintlify-for-marketers`) does not.
173
+ - **Implementation notes (SvelteKit)**:
174
+ - Frontmatter:
175
+ - required: `title`, `date`, `category`, `author`, `cover`
176
+ - optional: `excerpt`, `summaryAI`, `tags`, `featured`
177
+ - Render hero image from `cover`.
178
+ - Render summary card only when `summaryAI` is present.
179
+
180
+ ### 13. Edges, Margins, Paddings
181
+
182
+ - **What you mean**: exact spacing tokens so the pages feel “Mintlify-tight” and not generic.
183
+ - **Mintlify lesson (observed)**:
184
+ - Index:
185
+ - hero has `my-12`, `p-8`, fixed height `h-[480px]`.
186
+ - grid uses `gap-x-5` and `gap-y-12`, and `pb-32`.
187
+ - Post:
188
+ - container: `mt-[4.5rem]`, `pb-[7.5rem]`, `px-6`, `max-w-4xl`.
189
+ - content + side: `gap-x-16`.
190
+ - “More posts” cards are ~306px wide with thumbnail height ~190.
191
+ - **Implementation notes (SvelteKit)**:
192
+ - Use these as baseline Tailwind classes to match spacing.
193
+ - Avoid adding extra wrappers that break the rhythm.
194
+
195
+ ### 14. Time-To-Read Estimation
196
+
197
+ - **What you mean**: show “N min read / N minutes read” consistently across list and post.
198
+ - **Mintlify lesson (observed)**:
199
+ - Post header: “N minutes read”
200
+ - Index hero: “N min read”
201
+ - **Implementation notes (SvelteKit)**:
202
+ - `readingTimeMinutes = max(1, ceil(words / 200))`
203
+ - Render as:
204
+ - index: `${n} min read`
205
+ - post header: `${n} minutes read`
206
+
207
+ ### 15. RSS Feed + Icon Placement + Functionality
208
+
209
+ - **What you mean**: generate RSS, expose feed URL, add an icon button in the blog header row.
210
+ - **Mintlify lesson (observed)**:
211
+ - RSS lives at `/feed.xml`.
212
+ - The RSS icon sits to the right of the tag bar row; icon is small (~16px).
213
+ - Feed is RSS 2.0 with `atom:link rel="self"` and per-item: title, description, link/guid, pubDate, category, author.
214
+ - **Implementation notes (SvelteKit)**:
215
+ - Implement route `src/routes/feed.xml/+server.ts`.
216
+ - Add RSS icon link next to tag bar.
217
+
218
+ ### 16. Date Display
219
+
220
+ - **What you mean**: consistent formatting and placement.
221
+ - **Mintlify lesson (observed)**:
222
+ - Post page: date is shown below title, mono uppercase, subdued color.
223
+ - Suggested posts (bottom): show date under excerpt.
224
+ - **Implementation notes (SvelteKit)**:
225
+ - Store date as ISO in frontmatter; format via `Intl.DateTimeFormat('en-US', { month:'long', day:'numeric', year:'numeric' })`.
226
+ - For card suggestion: show date only (no author) to reduce clutter.
227
+
228
+ ### 17. Hero Article
229
+
230
+ - **What you mean**: a featured post at top of index, bigger than normal cards.
231
+ - **Mintlify lesson (observed)**:
232
+ - Large image card (full width) with overlay text and author block; height 480.
233
+ - Appears regardless of which tab is selected (filter applies to the grid, not hero).
234
+ - **Implementation notes (SvelteKit)**:
235
+ - Choose hero post: `featured: true` else newest by date.
236
+ - `BlogHeroCard.svelte` overlay gradient + white title.
237
+
238
+ ### 18. Size Of Each Article Thumbnail
239
+
240
+ - **What you mean**: consistent thumbnail aspect, border radius, and sizing for each card type.
241
+ - **Mintlify lesson (observed)**:
242
+ - Index grid cards: thumbnail height **280px**, rounded **16px**, object-cover.
243
+ - Suggested cards: thumbnail height **190px**, rounded **16px**, object-cover.
244
+ - **Implementation notes (SvelteKit)**:
245
+ - `BlogCard` accepts `variant: 'default' | 'suggestion'` and sets fixed heights.
246
+
247
+ ### 19. Picture Frame For Each Image + Corner Radius
248
+
249
+ - **What you mean**: images should have consistent framing; content images should look “mounted”.
250
+ - **Mintlify lesson (observed)**:
251
+ - Hero image: rounded **24px**.
252
+ - Card thumbnails: rounded **16px**.
253
+ - In-content images (non-hero) often have:
254
+ - `border-radius: ~10px`
255
+ - a subtle 1px border (low opacity)
256
+ - `cursor: zoom-in` (image zoom affordance).
257
+ - **Implementation notes (SvelteKit)**:
258
+ - CSS: `.blog-prose img { border-radius: 10px; border: 1px solid var(--border-soft); cursor: zoom-in; }`
259
+ - Lightbox: simple modal that opens on image click; close on escape/click outside.
260
+
261
+ ### 20. Title (Placement + Styling)
262
+
263
+ - **What you mean**: title should be dominant in post header and clear in cards.
264
+ - **Mintlify lesson (observed)**:
265
+ - Post H1: 40px/44, weight 600, negative tracking.
266
+ - Card titles: 20px/30, weight 500.
267
+ - **Implementation notes (SvelteKit)**:
268
+ - Tokenize title styles and reuse.
269
+
270
+ ### 21. Tag Showing Top Of Article
271
+
272
+ - **What you mean**: show category/tag near top of post, above title.
273
+ - **Mintlify lesson (observed)**:
274
+ - Category label appears above title as part of `CATEGORY / N minutes read`.
275
+ - Category itself is brand-colored, mono uppercase.
276
+ - **Implementation notes (SvelteKit)**:
277
+ - Render category as a clickable filter link (optional) or just label.
278
+
279
+ ### 22. URL Paths
280
+
281
+ - **What you mean**: predictable routes for index, posts, and feeds.
282
+ - **Mintlify lesson (observed)**:
283
+ - Index: `/blog`
284
+ - Post: `/blog/<slug>`
285
+ - RSS: `/feed.xml`
286
+ - **Implementation notes (SvelteKit)**:
287
+ - `src/routes/blog/+page.svelte`
288
+ - `src/routes/blog/[slug]/+page.svelte`
289
+ - `src/routes/feed.xml/+server.ts`
290
+
291
+ ### 23. AI Summary At The Top + Placement
292
+
293
+ - **What you mean**: show a short summary block above the body to help scanning and AI/SEO; visual should be distinct but subtle.
294
+ - **Mintlify lesson (observed)**:
295
+ - Summary card (when present) is placed **immediately after the hero image**, before the main body.
296
+ - Card style: `p-4`, `rounded-2xl`, soft background, “SUMMARY” label in mono uppercase.
297
+ - It is **optional** (at least one post lacked it).
298
+ - **Implementation notes (SvelteKit)**:
299
+ - Use frontmatter `summaryAI`.
300
+ - Render `SummaryCard.svelte` only if set.
301
+
302
+ ### 24. “More Posts To Read” + Recommendations
303
+
304
+ - **What you mean**: show a recommended section at end of every post.
305
+ - **Mintlify lesson (observed)**:
306
+ - Heading: “More blog posts to read”
307
+ - Exactly **2** suggested posts shown (in our sample set), using the smaller card variant.
308
+ - **Implementation notes (SvelteKit)**:
309
+ - Recommend by:
310
+ - same category first
311
+ - then tag overlap
312
+ - fallback to most recent excluding current
313
+ - Render 2 cards with `variant='suggestion'`.
314
+
315
+ ### 25. Blog Post Card Widgets (Thumbnail + Author + Title + Excerpt)
316
+
317
+ - **What you mean**: the main discoverability UI on index and in recommendations.
318
+ - **Mintlify lesson (observed)**:
319
+ - Card structure:
320
+ 1) rounded thumbnail
321
+ 2) mono uppercase category label (brand color)
322
+ 3) title
323
+ 4) excerpt (muted)
324
+ 5) author avatar + name + title
325
+ - Suggestion cards omit author and show date instead.
326
+ - **Implementation notes (SvelteKit)**:
327
+ - `BlogCard.svelte` uses composition:
328
+ - `CardMedia`, `CardMeta`, `CardTitle`, `CardExcerpt`, `CardFooter`.
329
+
330
+ ### 26. Tags Bar At Top Of Main Blog Page
331
+
332
+ - **What you mean**: horizontal filter bar with strong active state.
333
+ - **Mintlify lesson (observed)**:
334
+ - Tabs are pill-shaped with `px-3 py-1`, `rounded-full`, height ~31px.
335
+ - Inactive: muted text.
336
+ - Active: background invert + text invert.
337
+ - Mobile: horizontally scrollable, scrollbar hidden, fade mask edges.
338
+ - RSS icon sits to the right of this row.
339
+ - **Implementation notes (SvelteKit)**:
340
+ - `TagTabs.svelte`:
341
+ - uses a scroll container on small screens with a fade mask.
342
+ - uses a simple `activeCategory` state.
343
+
344
+ ### 27. Integration Into The Rest Of The SPA Site
345
+
346
+ - **What you mean**: blog should feel like part of the site (shared header/footer/theme), not a separate theme.
347
+ - **Mintlify lesson (observed)**:
348
+ - Blog uses the same global header navigation and footer as the rest of the Mintlify marketing site.
349
+ - Footer includes theme switcher.
350
+ - **Implementation notes (SvelteKit)**:
351
+ - Root layout provides header/footer; blog pages are just routes beneath.
352
+ - `src/routes/+layout.svelte` should import global CSS and render header/footer around `children`.
353
+
354
+ ### 28. Responsive Design (Index + Post Page)
355
+
356
+ - **What you mean**: layout adapts cleanly to mobile; side column collapses into header; filters become horizontal scroll; cards become 1 column.
357
+ - **Mintlify lesson (observed)**:
358
+ - Index: grid becomes 1 column on mobile.
359
+ - Filters: scrollable pill tabs with fade.
360
+ - Post page:
361
+ - Desktop: author/share is sticky side column.
362
+ - Mobile: author + share appear under title; side column is hidden.
363
+ - **Implementation notes (SvelteKit)**:
364
+ - Tailwind `md:` breakpoints for layout switches.
365
+ - Ensure touch-friendly tap targets for pills and share buttons.
366
+
367
+ ### 29. Thumbnails + Visual Identity
368
+
369
+ - **What you mean**: cards must feel like one system; consistent rounded frames, consistent aspect/height; subtle hover feedback.
370
+ - **Mintlify lesson (observed)**:
371
+ - Cards use rounded thumbnails and subtle overlay gradient on hover/focus (`bg-linear-to-t … opacity-0 group-hover:opacity-70`).
372
+ - **Implementation notes (SvelteKit)**:
373
+ - Add hover/focus overlay gradient layer for thumbnails.
374
+ - Use `focus-visible` outlines for keyboard navigation.
375
+
376
+ ### 30. Back Button (Post → Blog Index)
377
+
378
+ - **What you mean**: clear “return to index” affordance in predictable location.
379
+ - **Mintlify lesson (observed)**:
380
+ - Labeled “All articles” with a left arrow icon.
381
+ - Placed above meta row.
382
+ - **Implementation notes (SvelteKit)**:
383
+ - `BackLink.svelte` in post header, route to `/blog`.
384
+
385
+ ### 31. “Share This Article” Buttons + SVG Icons
386
+
387
+ - **What you mean**: share UI that matches the design system; icons are inline SVG.
388
+ - **Mintlify lesson (observed)**:
389
+ - 4 icon buttons, circular, `size-8` (32px).
390
+ - Background is soft; icons are muted and brighten on hover.
391
+ - Title “Share this article” is mono uppercase 12px.
392
+ - **Implementation notes (SvelteKit)**:
393
+ - Use inline SVG icons (do not depend on remote image URLs).
394
+ - Provide at least: X, LinkedIn, Copy link, Reddit (or Email).
395
+ - Add `aria-label` for accessibility.
396
+
397
+ ### 32. Anything Else Crucial
398
+
399
+ - **What you mean**: missing but important: SEO, OpenGraph, accessibility, performance.
400
+ - **Mintlify lesson (observed/inferred)**:
401
+ - Headings are linkable (good for navigation + sharing).
402
+ - RSS exists (distribution).
403
+ - Strong keyboard focus styles on interactive elements.
404
+ - Posts are highly scannable with summary + strong hierarchy.
405
+ - **Implementation notes (SvelteKit)**:
406
+ - Per-post `<svelte:head>` with `title`, `meta description`, `og:*`, `twitter:*`.
407
+ - `sitemap.xml` can be added later; RSS is required now.
408
+ - Add keyboard focus rings for tabs/buttons.
409
+
410
+ ---
411
+
412
+ ## 2) Consolidated Findings (Categorized)
413
+
414
+ This section reorganizes the above into implementation-ready categories (instead of item order).
415
+
416
+ ### A. Information Architecture + Routing
417
+
418
+ - `/blog`: index with hero + filters + infinite scroll grid.
419
+ - `/blog/[slug]`: post page with header meta, hero image, optional AI summary, markdown body, “More posts” section.
420
+ - `/feed.xml`: RSS feed (RSS 2.0 + atom self link).
421
+
422
+ ### B. Content Model (Frontmatter)
423
+
424
+ Recommended required frontmatter:
425
+
426
+ ```yaml
427
+ title: "..."
428
+ date: "2026-02-07" # ISO
429
+ category: "Best Practices"
430
+ author: "peri" # author id
431
+ cover: "/images/blog/real-llms.png"
432
+ excerpt: "..." # optional, else derive
433
+ summaryAI: "..." # optional
434
+ tags: ["llms.txt", "SEO"] # optional
435
+ featured: false # optional
436
+ draft: false # optional
437
+ ```
438
+
439
+ ### C. Global Tokens (Theme + Typography)
440
+
441
+ - Fonts:
442
+ - Sans: Inter
443
+ - Mono: Geist Mono
444
+ - Theme modes: `system`, `light`, `dark`
445
+ - Key sizes:
446
+ - Post H1: 40/44, 600, tracking -0.8
447
+ - H2: 24/31.2, 500, tracking -0.24
448
+ - H3: 20/26, 500
449
+ - Body: 16 with generous line-height (Mintlify often uses ~28px for paragraphs)
450
+ - Meta: mono 12 uppercase tracking 0.6
451
+
452
+ ### D. Components (UI System)
453
+
454
+ - Blog index:
455
+ - `BlogHeroCard`
456
+ - `TagTabs` (scrollable on mobile)
457
+ - `BlogCard` (default variant)
458
+ - `RssIconLink`
459
+ - `InfiniteScrollSentinel`
460
+ - Post page:
461
+ - `BackLink`
462
+ - `PostMetaRow` (category / read-time)
463
+ - `PostDate`
464
+ - `PostHeroImage`
465
+ - `SummaryCard` (optional)
466
+ - `ShareButtons` (desktop sticky + mobile header)
467
+ - `AuthorBlock`
468
+ - `MorePosts` (2 suggestion cards)
469
+ - `ImageLightbox` (for zoomable content images)
470
+
471
+ ### E. Media Styling Rules
472
+
473
+ - Hero image: `rounded-3xl` (24px), object-cover, max height ~360.
474
+ - Card thumbnail: `rounded-2xl` (16px), fixed height 280 (default) / 190 (suggestion).
475
+ - In-content images:
476
+ - radius ~10px
477
+ - subtle border
478
+ - zoom cursor + lightbox.
479
+
480
+ ### F. Performance + Loading
481
+
482
+ - Index uses infinite scroll; fetch next pages via JSON endpoint.
483
+ - Keep SSR fast: load only metadata for index; load full markdown only on post page.
484
+
485
+ ### G. SEO + Syndication
486
+
487
+ - RSS at `/feed.xml`.
488
+ - Per-post meta tags + canonical.
489
+
490
+ ---
491
+
492
+ ## 3) Fully Detailed Implementation Plan (Workstreams)
493
+
494
+ Workstreams are ordered to keep momentum and reduce rework.
495
+
496
+ ### Workstream 1: Project + Tooling Baseline
497
+
498
+ 1. Add Tailwind + typography plugin; set up `src/app.css` tokens for light/dark.
499
+ 2. Add Inter + Geist Mono fonts (self-hosted via `@fontsource/*`).
500
+ 3. Add global layout with header/footer and theme switcher.
501
+
502
+ Deliverables:
503
+ - `tailwind.config.cjs`, `postcss.config.cjs`, `src/app.css`
504
+ - `src/lib/components/ThemeSwitcher.svelte`
505
+ - `src/lib/stores/theme.svelte.ts` (or similar)
506
+
507
+ ### Workstream 2: Content Pipeline (Markdown + Frontmatter)
508
+
509
+ 1. Add `mdsvex` to compile `.md` to Svelte components.
510
+ 2. Add remark/rehype:
511
+ - `remark-gfm` (tables, task lists)
512
+ - `rehype-slug` + `rehype-autolink-headings` (heading permalinks)
513
+ 3. Add Shiki highlighting to match Mintlify’s dual theme approach.
514
+ - Note: in this repo we intentionally **disable mdsvex’s metadata script injection** by setting `mdsvexConfig.frontmatter.parse` to return `undefined`, and we parse frontmatter with `gray-matter` in `src/lib/server/blog.ts`. This avoids `script_duplicate` errors when combining mdsvex frontmatter exports with `@shikijs/rehype`.
515
+ 4. Implement server utilities:
516
+ - load all posts via `import.meta.glob`
517
+ - parse frontmatter (gray-matter)
518
+ - compute `readingTimeMinutes`, `excerpt`, `date` formatting
519
+ - expose `getAllPosts()`, `getPostBySlug()`
520
+ 5. Author registry and lookup.
521
+
522
+ Deliverables:
523
+ - `svelte.config.js` updated for mdsvex
524
+ - `src/lib/server/blog.ts` (loader + model)
525
+ - `src/lib/content/authors.ts`
526
+ - sample posts in `src/content/blog/*.md`
527
+
528
+ ### Workstream 3: Blog Index UI + Infinite Scroll
529
+
530
+ 1. `/blog` SSR loads:
531
+ - hero post
532
+ - initial page of card posts
533
+ - category list
534
+ 2. Implement tag tabs:
535
+ - active state pill styling
536
+ - mobile scroll + fade mask
537
+ 3. Implement card grid:
538
+ - default card variant matches Mintlify structure
539
+ 4. Implement JSON pagination endpoint to load more.
540
+
541
+ Deliverables:
542
+ - `src/routes/blog/+page.server.ts`
543
+ - `src/routes/blog/+page.svelte`
544
+ - `src/routes/blog/posts.json/+server.ts` (or similar)
545
+ - `src/lib/components/blog/TagTabs.svelte`, `BlogCard.svelte`, `BlogHeroCard.svelte`
546
+
547
+ ### Workstream 4: Post Page UI (Layout + Summary + Share + More Posts)
548
+
549
+ 1. `/blog/[slug]` loads post component + metadata + recommended posts.
550
+ 2. Render header:
551
+ - back link
552
+ - category/read-time row
553
+ - title + date
554
+ 3. Render body layout:
555
+ - hero image
556
+ - optional AI summary card
557
+ - markdown content
558
+ 4. Render “More posts to read” (2 suggestion cards).
559
+ 5. Share UI:
560
+ - desktop: sticky side panel
561
+ - mobile: header block under title
562
+ - implement share links + copy-to-clipboard
563
+
564
+ Deliverables:
565
+ - `src/routes/blog/[slug]/+page.server.ts`
566
+ - `src/routes/blog/[slug]/+page.svelte`
567
+ - `src/lib/components/blog/PostHeader.svelte`, `SummaryCard.svelte`, `ShareButtons.svelte`, `MorePosts.svelte`
568
+
569
+ ### Workstream 5: Media UX (Image Framing + Lightbox)
570
+
571
+ 1. Apply CSS for in-content images (frame + radius + zoom cursor).
572
+ 2. Add a lightweight `ImageLightbox`:
573
+ - opens when clicking content images
574
+ - supports escape key, backdrop close
575
+ - supports scroll locking
576
+
577
+ Deliverables:
578
+ - `src/lib/components/blog/ImageLightbox.svelte`
579
+ - a small enhancement script in post page that binds click handlers to `.blog-prose img`.
580
+
581
+ ### Workstream 6: RSS Feed
582
+
583
+ 1. Generate RSS 2.0 XML at `/feed.xml`.
584
+ 2. Ensure item fields match Mintlify:
585
+ - title, description, link/guid, pubDate, category, author
586
+ - atom:link self
587
+ 3. Add RSS icon link to blog index header row.
588
+
589
+ Deliverables:
590
+ - `src/routes/feed.xml/+server.ts`
591
+ - `src/lib/server/rss.ts`
592
+
593
+ ### Workstream 7: Polish (A11y + SEO + QA)
594
+
595
+ 1. Ensure focus-visible rings on tabs/buttons.
596
+ 2. Add per-post meta tags for SEO and social.
597
+ 3. Validate:
598
+ - RSS validates
599
+ - dark mode readability for prose + code blocks
600
+ - mobile layout matches fold behavior
601
+
602
+ Deliverables:
603
+ - `src/lib/server/seo.ts` helpers
604
+ - updates in blog routes for `<svelte:head>`
605
+
606
+ ---
607
+
608
+ ## Acceptance Checklist (Mintlify-Consistency Targets)
609
+
610
+ - Blog index:
611
+ - hero card (480px height, rounded 24, overlay text)
612
+ - tag tabs with pill active state; scrollable on mobile with fade mask
613
+ - 2-col grid on desktop, 1-col on mobile
614
+ - infinite scroll loads more posts
615
+ - RSS icon links to `/feed.xml`
616
+ - Post page:
617
+ - back link (“All articles”) at top
618
+ - meta row: `CATEGORY / N minutes read` (mono uppercase)
619
+ - title (40px) + date (mono uppercase)
620
+ - hero image (rounded 24, max height ~360)
621
+ - optional AI summary card (rounded 16, soft background)
622
+ - markdown rendering with heading anchors, shiki code blocks, styled tables/quotes
623
+ - sticky author/share column on desktop; folded into header on mobile
624
+ - “More blog posts to read” with 2 suggestion cards
625
+
626
+ ---
627
+
628
+ ## 4) Plan Status (As Of 2026-02-09)
629
+
630
+ ### Workstream 1: Foundations (SvelteKit + Theme)
631
+
632
+ Status: Done
633
+
634
+ Implementation notes:
635
+ - Theme-aware light/dark/system is implemented via an early script in `src/app.html` plus a runtime store in `src/lib/stores/theme.ts`.
636
+ - Global tokens live in `src/app.css` and are applied via `html.light` / `html.dark`.
637
+
638
+ ### Workstream 2: Content Pipeline (Markdown + Frontmatter)
639
+
640
+ Status: Done
641
+
642
+ Implementation notes:
643
+ - `.md` is compiled via mdsvex in `svelte.config.js` and server-rendered to HTML strings for the post route.
644
+ - Frontmatter is parsed with `gray-matter` in `src/lib/server/blog.ts` (not mdsvex metadata exports) to avoid `script_duplicate` issues with Shiki.
645
+
646
+ ### Workstream 3: Blog Index UI + Infinite Scroll
647
+
648
+ Status: Done
649
+
650
+ Implementation notes:
651
+ - `/blog` uses SSR for hero + initial list and a paginated JSON endpoint for additional loads.
652
+ - Category pills are scrollable on mobile with edge fade masking (`fade-mask-x` in `src/app.css`).
653
+
654
+ ### Workstream 4: Post Page UI (Layout + Summary + Share + More Posts)
655
+
656
+ Status: Done
657
+
658
+ Implementation notes:
659
+ - Desktop: sticky author/share rail; Mobile: author + share fold into the main column.
660
+ - AI summary is conditional on `summaryAI` in frontmatter.
661
+
662
+ ### Workstream 5: Media UX (Image Framing + Lightbox)
663
+
664
+ Status: Done
665
+
666
+ Implementation notes:
667
+ - In-content images are framed via typography + `.blog-prose` tweaks and open a simple lightbox on click.
668
+
669
+ ### Workstream 6: RSS Feed
670
+
671
+ Status: Done
672
+
673
+ Implementation notes:
674
+ - RSS lives at `src/routes/feed.xml/+server.ts`.
675
+ - Auto-discovery is provided via `<link rel="alternate">` in `src/routes/+layout.svelte`.
676
+ - RSS XML generation is factored into `src/lib/server/rss.ts`.
677
+
678
+ ### Workstream 7: Polish (A11y + SEO + QA)
679
+
680
+ Status: Done (with ongoing content-driven tweaks as new post types are added)
681
+
682
+ Implementation notes:
683
+ - Per-post SEO meta tags are set in `src/routes/blog/[slug]/+page.svelte` using `src/lib/server/seo.ts`.
684
+ - E2E coverage is added via Playwright in `tests/blog.spec.ts` and includes theme toggling, RSS, and mobile folding checks.
685
+ - Markdown edge cases are validated via `src/content/blog/markdown-kitchen-sink.md` and table/URL hardening in `src/app.css`.
686
+
687
+ ### Workstream 8: Library Packaging (Reuse Across Repos)
688
+
689
+ Status: Done
690
+
691
+ Implementation notes:
692
+ - Reusable blog components + content loader helpers are packaged as a local workspace library: `packages/blogkit` (`@aureuma/blogkit`).
693
+ - The demo app consumes the library via thin glue modules:
694
+ - `src/lib/server/blog.ts` wraps `createBlog()` from `@aureuma/blogkit/server`
695
+ - `src/lib/stores/theme.ts` wraps `createThemeController()` from `@aureuma/blogkit/theme`
696
+ - `src/lib/types/blog.ts` re-exports library types
697
+ - See `packages/blogkit/README.md` for integration guidance.