feat(blog+categories): Wave 3-5 — blog infrastructure, categories, content, navigation
- Install @astrojs/rss and setup content collections (blog + generators) - Create BlogLayout with BlogPosting schema, article OG tags, prev/next nav - Create blog post pages EN/RU ([slug].astro) with dynamic routing - Create blog index pages EN/RU with post cards and filtering - Create RSS feeds EN/RU with auto-discovery links - Create generator category pages EN/RU (5 categories each) - Add category navigation pills to homepage - Create Breadcrumbs, RelatedGenerators, RelatedPosts components - Add breadcrumbs to GeneratorLayout and BlogLayout - Wire RelatedGenerators into GeneratorLayout - Wire RelatedPosts into blog post pages - Create 8 EN + 8 RU blog post templates with placeholder content - Add blog link to LanguageSwitcher navigation - Add category and blog translation keys
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
Task 11: Install @astrojs/rss and set up content collections config
|
||||
|
||||
- Package installed: @astrojs/rss (added 9 packages, 511 total)
|
||||
- File updated: src/content/config.ts
|
||||
- Imported z from astro:content
|
||||
- Added blog collection with type: "content"
|
||||
- Blog schema fields: title (max 120), description (max 160), pubDate, modDate (optional), draft (default false), lang (en/ru), category (tutorial/guide/news/tips), tags (default []), ogImage (optional, image()), relatedGenerators (optional), relatedPosts (optional)
|
||||
- Preserved existing generators collection (type: "data", schema: generatorSchema)
|
||||
- Directories created: src/content/blog/en/ and src/content/blog/ru/
|
||||
- Build verification: npm run build passed with 64 pages, 0 errors
|
||||
@@ -0,0 +1,38 @@
|
||||
Task 12: BlogLayout.astro with BlogPosting JSON-LD and Article OG Meta Tags
|
||||
|
||||
Verification: npm run build — PASSED (64 pages built)
|
||||
|
||||
File: src/layouts/BlogLayout.astro
|
||||
|
||||
Features implemented:
|
||||
1. Wraps BaseLayout, passing title, description, ogImage.
|
||||
2. Injects BlogPosting JSON-LD schema via slot="head" with:
|
||||
- @type: BlogPosting
|
||||
- headline (from title prop)
|
||||
- author: Organization { name: "Randify" }
|
||||
- publisher: Organization { name: "Randify", logo: ImageObject }
|
||||
- datePublished (ISO 8601)
|
||||
- dateModified (ISO 8601, falls back to datePublished)
|
||||
- url (canonical)
|
||||
- description
|
||||
- inLanguage
|
||||
3. OG type set to "article" via <meta property="og:type" content="article" /> in slot="head".
|
||||
4. Article-specific meta tags added:
|
||||
- article:published_time
|
||||
- article:modified_time
|
||||
5. Styled container: max-w-2xl mx-auto, matching GeneratorLayout spacing.
|
||||
6. Header with title, accent dot, publication date, and conditional "Updated" label.
|
||||
7. Prev/next post navigation with bilingual labels (EN/RU), arrow icons, and focus rings.
|
||||
8. Named slot "related" for RelatedPosts component.
|
||||
|
||||
Props accepted:
|
||||
- title: string
|
||||
- description: string
|
||||
- pubDate: Date | string
|
||||
- modDate?: Date | string
|
||||
- ogImage?: string
|
||||
- lang?: Lang
|
||||
- prevPost?: { slug: string; title: string }
|
||||
- nextPost?: { slug: string; title: string }
|
||||
|
||||
Build output: 64 pages, 0 errors.
|
||||
@@ -0,0 +1,7 @@
|
||||
Task 13: EN blog post page ([slug].astro)
|
||||
- Build: PASS (77 pages)
|
||||
- Generated: dist/blog/test-post/index.html
|
||||
- Verified: post title present in HTML
|
||||
- Verified: BlogPosting JSON-LD schema present
|
||||
- Verified: article:published_time meta tag present
|
||||
- Slug derived from post.id with en/ prefix and .md extension stripped
|
||||
@@ -0,0 +1,16 @@
|
||||
Task 14: Create RU blog post page src/pages/ru/blog/[slug].astro
|
||||
|
||||
Build result: PASS
|
||||
Pages built: 77
|
||||
RU blog post page: compiled successfully (no RU blog posts yet, so no static pages generated)
|
||||
EN blog post page: /blog/test-post/index.html generated
|
||||
|
||||
Files created/modified:
|
||||
- src/pages/ru/blog/[slug].astro (created)
|
||||
- src/layouts/BlogLayout.astro (fixed locale-aware prev/next links)
|
||||
|
||||
Verification:
|
||||
- npm run build exited with code 0
|
||||
- No TypeScript or Astro errors
|
||||
- RU [slug].astro correctly filters getCollection("blog") by lang === "ru"
|
||||
- BlogLayout prev/next navigation updated to use locale-aware paths (/ru/blog/ for RU, /blog/ for EN)
|
||||
@@ -0,0 +1,36 @@
|
||||
Task 15: Blog Index Pages — Evidence
|
||||
======================================
|
||||
|
||||
Build Status: PASS (76 pages, exit code 0)
|
||||
|
||||
Files Created:
|
||||
- src/pages/blog/index.astro
|
||||
- src/pages/ru/blog/index.astro
|
||||
|
||||
Files Modified:
|
||||
- src/i18n/translations.ts (added blogDesc, readMore, noPosts keys for EN + RU)
|
||||
|
||||
Build Output Verification:
|
||||
- dist/blog/index.html (6893 bytes)
|
||||
- dist/ru/blog/index.html (7342 bytes)
|
||||
|
||||
EN Page Features:
|
||||
- Queries getCollection("blog"), filters lang === "en" and draft !== true
|
||||
- Sorts by pubDate descending
|
||||
- Links to /blog/[slug]/
|
||||
- Date formatting: toLocaleDateString("en-US", ...)
|
||||
- JSON-LD Blog schema with blogPost array
|
||||
|
||||
RU Page Features:
|
||||
- Queries getCollection("blog"), filters lang === "ru" and draft !== true
|
||||
- Sorts by pubDate descending
|
||||
- Links to /ru/blog/[slug]/
|
||||
- Date formatting: toLocaleDateString("ru-RU", ...)
|
||||
- JSON-LD Blog schema with blogPost array
|
||||
|
||||
Both pages:
|
||||
- Use BaseLayout with title and description props
|
||||
- Include OG/Twitter Card meta tags (inherited from BaseLayout)
|
||||
- Include canonical + hreflang alternates (inherited from BaseLayout)
|
||||
- Show empty state "No posts yet" / "Пока нет записей." when collection is empty
|
||||
- Display category badge + tag badges per post card
|
||||
@@ -0,0 +1,20 @@
|
||||
Task 16: RSS Feeds
|
||||
|
||||
Files created:
|
||||
- src/pages/rss.xml.ts (EN feed)
|
||||
- src/pages/ru/rss.xml.ts (RU feed)
|
||||
|
||||
File modified:
|
||||
- src/layouts/BaseLayout.astro (added <link rel="alternate" type="application/rss+xml"> for both EN and RU feeds)
|
||||
|
||||
Build: PASS (npm run build exited 0)
|
||||
|
||||
Generated feeds:
|
||||
- dist/rss.xml exists (287 bytes)
|
||||
- dist/ru/rss.xml exists (404 bytes)
|
||||
|
||||
Feed content verified:
|
||||
- EN: title="Randify Blog", language="en", description present, link=https://randify.pro/
|
||||
- RU: title="Блог Randify", language="ru", description present, link=https://randify.pro/
|
||||
|
||||
Note: Feeds are currently empty because no blog posts exist in src/content/blog/ yet. When posts are added with lang="en"/"ru" and draft !== true, they will appear automatically.
|
||||
@@ -0,0 +1,26 @@
|
||||
Task 17: Category Pages for Generators
|
||||
======================================
|
||||
|
||||
Build Result: PASS
|
||||
Pages built: 76
|
||||
|
||||
EN Category Pages Created:
|
||||
- dist/generators/category/gaming/index.html
|
||||
- dist/generators/category/security/index.html
|
||||
- dist/generators/category/decision-making/index.html
|
||||
- dist/generators/category/creative/index.html
|
||||
- dist/generators/category/utility/index.html
|
||||
|
||||
RU Category Pages Created:
|
||||
- dist/ru/generators/category/gaming/index.html
|
||||
- dist/ru/generators/category/security/index.html
|
||||
- dist/ru/generators/category/decision-making/index.html
|
||||
- dist/ru/generators/category/creative/index.html
|
||||
- dist/ru/generators/category/utility/index.html
|
||||
|
||||
Verification:
|
||||
- EN gaming page contains: "Gaming generators for tabletop RPGs" and generator titles (Lottery, Rock Paper Scissors, etc.)
|
||||
- RU gaming page contains: "Игровые генераторы для настольных RPG" and generator titles (Колесо фортуны, Лотерея, etc.)
|
||||
- All 5 categories render correctly with getStaticPaths
|
||||
- Breadcrumb JSON-LD schema included on each page
|
||||
- Generators filtered dynamically by category field from src/data/generators.ts
|
||||
@@ -0,0 +1,16 @@
|
||||
Task 18: Category Navigation Pills on Homepage
|
||||
|
||||
Files modified:
|
||||
- src/pages/index.astro
|
||||
- src/pages/ru/index.astro
|
||||
- src/i18n/translations.ts
|
||||
|
||||
Build result: PASS (85 pages, 0 errors)
|
||||
|
||||
Verification:
|
||||
- dist/index.html contains category navigation pills
|
||||
- dist/ru/index.html contains localized category navigation pills
|
||||
- All 5 categories present: Gaming (6), Security (3), Decision Making (4), Creative (5), Utility (10)
|
||||
- Links point to /generators/category/[category]/ (EN) and /ru/generators/category/[category]/ (RU)
|
||||
- Pills styled with Tailwind: rounded-full, bg-zinc-800/60, border-zinc-700/50, hover:bg-accent/20, hover:text-accent
|
||||
- Responsive flex-wrap layout
|
||||
@@ -0,0 +1,28 @@
|
||||
Task 19: Create Breadcrumbs.astro Component — Evidence
|
||||
=====================================================
|
||||
|
||||
1. File Created
|
||||
---------------
|
||||
Path: src/components/Breadcrumbs.astro
|
||||
|
||||
2. Component Specification
|
||||
--------------------------
|
||||
- Props interface: { items: Array<{ label: string, href?: string }> }
|
||||
- Renders <nav aria-label="Breadcrumb"> containing <ol>
|
||||
- Each item rendered as <li> with "/" separator between items
|
||||
- Last item (no href or end of array): <span aria-current="page"> with text-zinc-400
|
||||
- Items with href: <a> with text-zinc-500 hover:text-accent transition-colors and focus ring
|
||||
- Tailwind styling: text-sm, muted zinc colors, accent hover state
|
||||
|
||||
3. Build Verification
|
||||
---------------------
|
||||
Command: npm run build
|
||||
Result: PASS (64 pages built, 0 errors)
|
||||
|
||||
4. Example Usage
|
||||
----------------
|
||||
<Breadcrumbs items={[
|
||||
{ label: "Home", href: "/" },
|
||||
{ label: "Gaming", href: "/generators/category/gaming/" },
|
||||
{ label: "Dice Roller" }
|
||||
]} />
|
||||
@@ -0,0 +1,19 @@
|
||||
Task 20: RelatedGenerators.astro
|
||||
|
||||
Files changed:
|
||||
- src/components/RelatedGenerators.astro (created)
|
||||
- src/layouts/GeneratorLayout.astro (updated — integrated RelatedGenerators)
|
||||
- src/i18n/translations.ts (updated — added relatedGenerators key EN+RU)
|
||||
|
||||
Build result:
|
||||
- npm run build: PASSED
|
||||
- 76 pages built, 0 errors
|
||||
|
||||
Component behavior:
|
||||
- Accepts props: currentSlug, category, optional lang
|
||||
- Filters generators by category, excludes current slug, limits to 4
|
||||
- Returns null (renders nothing) if no related generators exist
|
||||
- Locale-aware titles and links (EN / RU)
|
||||
- Compact card layout: icon + title in a responsive 2-column grid
|
||||
- Uses Tailwind with existing design tokens (accent color, zinc palette)
|
||||
- Includes focus-visible ring for accessibility
|
||||
@@ -0,0 +1,24 @@
|
||||
Task 21: RelatedPosts Component
|
||||
================================
|
||||
|
||||
Files created:
|
||||
- src/components/RelatedPosts.astro
|
||||
|
||||
Files modified:
|
||||
- src/i18n/translations.ts (added relatedPosts key: en="Related posts", ru="Похожие статьи")
|
||||
- src/pages/blog/[slug].astro (imported RelatedPosts, wired into "related" slot)
|
||||
- src/pages/ru/blog/[slug].astro (imported RelatedPosts, wired into "related" slot)
|
||||
|
||||
Build result: PASS
|
||||
- 83 pages built successfully
|
||||
- No errors or warnings
|
||||
|
||||
Implementation details:
|
||||
- Accepts post: CollectionEntry<"blog">
|
||||
- Uses getCollection to fetch non-draft posts in same language
|
||||
- Scores related posts by tag overlap count
|
||||
- Shows top 3 posts with score > 0
|
||||
- Hides section entirely if no related posts found
|
||||
- Renders title, date, and description snippet for each related post
|
||||
- Links use correct /blog/ or /ru/blog/ base path
|
||||
- Styled with Tailwind matching existing dark theme (zinc palette, accent color)
|
||||
@@ -0,0 +1,25 @@
|
||||
Task 22: Create 8 English blog post templates
|
||||
Date: 2026-05-14
|
||||
Build result: PASS
|
||||
Pages built: 85
|
||||
|
||||
Files created:
|
||||
- src/content/blog/en/what-is-cryptographically-secure-randomness.md
|
||||
- src/content/blog/en/how-to-create-strong-passwords.md
|
||||
- src/content/blog/en/dice-notation-explained.md
|
||||
- src/content/blog/en/psychology-of-randomness.md
|
||||
- src/content/blog/en/rng-in-gaming.md
|
||||
- src/content/blog/en/random-team-picker.md
|
||||
- src/content/blog/en/color-theory-palettes.md
|
||||
- src/content/blog/en/uuid-vs-sequential-ids.md
|
||||
|
||||
Build output confirms all 8 posts were generated alongside the existing test-post:
|
||||
/blog/what-is-cryptographically-secure-randomness/index.html
|
||||
/blog/how-to-create-strong-passwords/index.html
|
||||
/blog/dice-notation-explained/index.html
|
||||
/blog/psychology-of-randomness/index.html
|
||||
/blog/rng-in-gaming/index.html
|
||||
/blog/random-team-picker/index.html
|
||||
/blog/color-theory-palettes/index.html
|
||||
/blog/uuid-vs-sequential-ids/index.html
|
||||
/blog/test-post/index.html
|
||||
@@ -0,0 +1,20 @@
|
||||
Build completed: 93 pages
|
||||
RU blog posts generated (8):
|
||||
- /ru/blog/what-is-cryptographically-secure-randomness/index.html
|
||||
- /ru/blog/how-to-create-strong-passwords/index.html
|
||||
- /ru/blog/dice-notation-guide/index.html
|
||||
- /ru/blog/psychology-of-randomness/index.html
|
||||
- /ru/blog/rng-in-gaming/index.html
|
||||
- /ru/blog/random-team-selection/index.html
|
||||
- /ru/blog/color-theory-guide/index.html
|
||||
- /ru/blog/uuid-vs-sequential-ids/index.html
|
||||
Files created:
|
||||
- src/content/blog/ru/what-is-cryptographically-secure-randomness.md
|
||||
- src/content/blog/ru/how-to-create-strong-passwords.md
|
||||
- src/content/blog/ru/dice-notation-guide.md
|
||||
- src/content/blog/ru/psychology-of-randomness.md
|
||||
- src/content/blog/ru/rng-in-gaming.md
|
||||
- src/content/blog/ru/random-team-selection.md
|
||||
- src/content/blog/ru/color-theory-guide.md
|
||||
- src/content/blog/ru/uuid-vs-sequential-ids.md
|
||||
Build timestamp: 2026-05-14T03:08:00+03:00
|
||||
@@ -0,0 +1,16 @@
|
||||
Task 24 Evidence: Blog Navigation Link
|
||||
=======================================
|
||||
|
||||
Build: PASS
|
||||
- npm run build completed successfully (84 pages built)
|
||||
|
||||
Verification:
|
||||
- EN blog link (/blog/) found in dist/index.html
|
||||
- RU blog link (/ru/blog/) found in 38 RU pages including dist/ru/index.html
|
||||
|
||||
Changes made:
|
||||
- Modified src/components/LanguageSwitcher.astro
|
||||
- Added Blog / Блог link between language toggle and About link
|
||||
- Link points to /blog/ on EN pages and /ru/blog/ on RU pages
|
||||
- Used existing translation keys (blog: "Blog", blog: "Блог") from src/i18n/translations.ts
|
||||
- Styled consistently with existing About/Privacy links
|
||||
@@ -0,0 +1,17 @@
|
||||
Task: Add Breadcrumbs component to generator and blog layouts
|
||||
Date: 2026-05-14
|
||||
|
||||
1. npm run build
|
||||
Result: PASS (93 pages built, exit code 0)
|
||||
|
||||
2. Grep dist/generators/dice/index.html for breadcrumb items:
|
||||
- Found: Home, Gaming, Dice
|
||||
- Command: grep -o 'Home\|Gaming\|Dice' dist/generators/dice/index.html
|
||||
|
||||
3. Grep dist/blog/test-post/index.html for breadcrumb items:
|
||||
- Found: Home, Blog, Test Post
|
||||
- Command: grep -o 'Home\|Blog\|Test Post' dist/blog/test-post/index.html
|
||||
|
||||
Files modified:
|
||||
- src/layouts/GeneratorLayout.astro
|
||||
- src/layouts/BlogLayout.astro
|
||||
Reference in New Issue
Block a user