add blog to project

This commit is contained in:
mahdiarghyani
2025-11-09 13:56:03 +03:30
parent 24a91baaf5
commit c7e5eb0713
26 changed files with 3310 additions and 11 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,241 @@
# Requirements Document
## Introduction
This document specifies the requirements for implementing a fully-featured blog system in the Nuxt 4 portfolio application using Nuxt Content v3. The blog system will support bilingual content (English and Persian with RTL), markdown-based content management, SEO optimization, and seamless integration with the existing portfolio design system.
## Glossary
- **Blog System**: The complete blogging functionality including content management, rendering, listing, and navigation
- **Nuxt Content**: The official Nuxt module (@nuxt/content) for file-based content management with markdown support
- **Content Directory**: The file system location where markdown blog posts are stored (content/ folder)
- **Blog Post**: A single article written in markdown format with frontmatter metadata
- **Frontmatter**: YAML metadata at the top of markdown files containing post information (title, date, tags, etc.)
- **Blog Listing Page**: The main blog index page displaying all published posts
- **Blog Detail Page**: Individual post page rendering the full markdown content
- **Content Query**: Nuxt Content's API for fetching and filtering markdown content
- **MDC Syntax**: Markdown Components syntax for embedding Vue components in markdown
- **SEO Metadata**: Meta tags, Open Graph, and structured data for search engine optimization
- **Reading Time**: Calculated estimate of time required to read a blog post
- **Tag System**: Categorization mechanism using tags/labels for blog posts
- **Draft Mode**: Unpublished posts that are hidden from production but visible in development
## Requirements
### Requirement 1: Nuxt Content Module Integration
**User Story:** As a developer, I want to integrate Nuxt Content v3 into the existing Nuxt 4 application, so that I can manage blog content using markdown files.
#### Acceptance Criteria
1. WHEN the developer installs the @nuxt/content package, THE Blog System SHALL use version 3.x compatible with Nuxt 4
2. WHEN the nuxt.config.ts is updated, THE Blog System SHALL register @nuxt/content in the modules array before other content-dependent modules
3. THE Blog System SHALL create a content/ directory in the project root for storing markdown files
4. THE Blog System SHALL configure Nuxt Content with Shiki syntax highlighter for code blocks
5. THE Blog System SHALL enable markdown.mdc option to support Vue component embedding in markdown
6. WHEN the development server starts, THE Blog System SHALL successfully load and parse all markdown files with hot-reload support
### Requirement 2: Content Directory Structure
**User Story:** As a content creator, I want a well-organized content directory structure, so that I can easily manage bilingual blog posts.
#### Acceptance Criteria
1. THE Blog System SHALL create locale-based subdirectories (content/en/blog/ and content/fa/blog/)
2. WHEN queryContent() is called with a locale parameter, THE Blog System SHALL fetch content from the corresponding locale directory
3. THE Blog System SHALL support nested directories within blog folders for content organization (e.g., content/en/blog/tutorials/)
4. THE Blog System SHALL recognize markdown files with .md extension as valid blog posts
5. WHERE a blog post exists in one language but not another, THE Blog System SHALL display a fallback message with a link to the available language version
6. THE Blog System SHALL use the file name (slug) as the URL path segment for blog posts
### Requirement 3: Blog Post Frontmatter Schema
**User Story:** As a content creator, I want a standardized frontmatter schema for blog posts, so that all posts have consistent metadata.
#### Acceptance Criteria
1. THE Blog System SHALL require the following frontmatter fields: title, description, date, and tags
2. THE Blog System SHALL support optional frontmatter fields: image, author, draft, updatedAt, and head (for custom SEO)
3. THE Blog System SHALL define a TypeScript interface extending ParsedContent for type-safe frontmatter access
4. THE Blog System SHALL parse date field as ISO 8601 date string (YYYY-MM-DD or full ISO format)
5. THE Blog System SHALL accept tags as an array of strings for categorization
6. WHERE draft is set to true, THE Blog System SHALL exclude the post from queryContent results in production using where({ draft: { $ne: true } })
7. THE Blog System SHALL use the image field for Open Graph and Twitter Card meta tags
### Requirement 4: Blog Listing Page Implementation
**User Story:** As a visitor, I want to see a list of all published blog posts, so that I can browse available content.
#### Acceptance Criteria
1. WHEN a visitor navigates to /blog or /fa/blog, THE Blog System SHALL use queryContent() to fetch all published posts for the current locale path
2. THE Blog System SHALL sort blog posts by date field in descending order using .sort({ date: -1 })
3. THE Blog System SHALL display post title, description, formatted date, reading time estimate, and tags for each post card
4. WHEN a visitor clicks on a blog post card, THE Blog System SHALL navigate to the localized post detail page using the _path property
5. WHERE no published posts exist for a locale, THE Blog System SHALL display an empty state message with i18n translation
6. THE Blog System SHALL filter out draft posts using .where({ draft: { $ne: true } }) in production environment
7. THE Blog System SHALL calculate reading time from the body.children word count assuming 200 words per minute
8. THE Blog System SHALL use .only() to fetch only required fields (title, description, date, tags, _path, image) for performance
### Requirement 5: Blog Detail Page Implementation
**User Story:** As a visitor, I want to read the full content of a blog post, so that I can consume the article.
#### Acceptance Criteria
1. WHEN a visitor navigates to /blog/[slug] or /fa/blog/[slug], THE Blog System SHALL use ContentDoc component or queryContent().where({ _path: path }).findOne() to fetch the post
2. THE Blog System SHALL render markdown using ContentRenderer component with GitHub Flavored Markdown support
3. THE Blog System SHALL apply Shiki syntax highlighting to code blocks with theme matching the site's color mode
4. THE Blog System SHALL render post metadata (title, formatted date, reading time, tags) in a header section using Nuxt UI components
5. WHERE the requested slug does not exist, THE Blog System SHALL throw a 404 error using createError({ statusCode: 404 })
6. THE Blog System SHALL support MDC syntax (::component-name) for embedding Vue components within markdown
7. THE Blog System SHALL apply Prose components styling from Nuxt UI for consistent typography (ProseH1, ProseP, ProseCode, etc.)
8. THE Blog System SHALL auto-generate anchor links for all headings for easy section sharing
### Requirement 6: SEO and Meta Tags
**User Story:** As a content creator, I want proper SEO metadata for blog posts, so that they rank well in search engines.
#### Acceptance Criteria
1. THE Blog System SHALL use useContentHead() composable to auto-generate meta tags from frontmatter
2. THE Blog System SHALL use useSeoMeta() to set title in format "[Post Title] | Blog | [Site Name]"
3. THE Blog System SHALL generate Open Graph tags (og:title, og:description, og:image, og:type, og:url) from post frontmatter
4. WHERE an image field is specified in frontmatter, THE Blog System SHALL use it for og:image and twitter:image, otherwise use a default blog cover image
5. THE Blog System SHALL set og:type to "article" and include article:published_time and article:tag properties
6. THE Blog System SHALL generate Twitter Card meta tags with card type "summary_large_image"
7. THE Blog System SHALL allow custom head overrides via the head field in frontmatter for advanced SEO control
8. THE Blog System SHALL generate JSON-LD structured data for BlogPosting schema including author, datePublished, and headline
### Requirement 7: Tag Filtering System
**User Story:** As a visitor, I want to filter blog posts by tags, so that I can find content on specific topics.
#### Acceptance Criteria
1. THE Blog System SHALL extract all unique tags from published posts using a computed property that aggregates tags arrays
2. WHEN a visitor clicks on a tag, THE Blog System SHALL filter posts using queryContent().where({ tags: { $contains: selectedTag } })
3. THE Blog System SHALL update the URL query parameter (?tag=value) using useRoute() and navigateTo() when a tag is selected
4. WHEN a visitor clears the tag filter, THE Blog System SHALL remove the query parameter and display all posts
5. THE Blog System SHALL highlight the active tag using Nuxt UI's UBadge or UButton component with active state styling
6. THE Blog System SHALL read the tag query parameter on page load to maintain filter state on navigation or refresh
### Requirement 8: Responsive Design and Accessibility
**User Story:** As a visitor using any device, I want the blog to be fully responsive and accessible, so that I can read content comfortably.
#### Acceptance Criteria
1. THE Blog System SHALL render blog listing and detail pages responsively across mobile, tablet, and desktop viewports
2. THE Blog System SHALL maintain readability with appropriate font sizes and line heights for body text
3. THE Blog System SHALL ensure sufficient color contrast ratios for text and backgrounds (WCAG AA compliance)
4. THE Blog System SHALL support keyboard navigation for all interactive elements
5. THE Blog System SHALL provide appropriate ARIA labels and semantic HTML for screen readers
6. WHERE images are used in blog posts, THE Blog System SHALL require alt text for accessibility
### Requirement 9: RTL Support for Persian Content
**User Story:** As a Persian-speaking visitor, I want blog content to display correctly in RTL layout, so that I can read naturally.
#### Acceptance Criteria
1. WHEN a visitor views Persian blog content, THE Blog System SHALL apply RTL text direction to all content
2. THE Blog System SHALL mirror layout elements appropriately for RTL (navigation, spacing, alignment)
3. THE Blog System SHALL maintain LTR direction for code blocks and technical content within RTL posts
4. THE Blog System SHALL handle mixed LTR/RTL content gracefully (e.g., English words in Persian text)
5. THE Blog System SHALL apply RTL-appropriate typography and spacing rules
### Requirement 10: Performance Optimization
**User Story:** As a visitor, I want blog pages to load quickly, so that I have a smooth browsing experience.
#### Acceptance Criteria
1. THE Blog System SHALL use NuxtImg component for all images in markdown to enable automatic optimization
2. THE Blog System SHALL configure @nuxt/image to generate responsive srcsets and modern formats (webp, avif)
3. THE Blog System SHALL use .only() and .without() query modifiers to fetch minimal data for listing pages
4. THE Blog System SHALL leverage Nuxt Content's built-in caching for content queries in production
5. THE Blog System SHALL prerender all blog routes during build using nitro.prerender.routes configuration
6. THE Blog System SHALL lazy-load blog components using defineAsyncComponent where appropriate
7. THE Blog System SHALL achieve a Lighthouse performance score of 90+ for blog pages
### Requirement 11: Development Experience
**User Story:** As a developer, I want a smooth development experience when working with blog content, so that I can iterate quickly.
#### Acceptance Criteria
1. WHEN a markdown file is modified, THE Blog System SHALL use Nuxt Content's HMR to hot-reload content without full page refresh
2. THE Blog System SHALL include draft posts in queryContent results during development (process.dev check)
3. WHERE a markdown parsing error occurs, THE Blog System SHALL display the error overlay with file path and line number
4. THE Blog System SHALL define TypeScript interfaces for BlogPost extending ParsedContent for type-safe queries
5. THE Blog System SHALL use Nuxt Content's built-in content:list server endpoint for debugging available content
6. THE Blog System SHALL provide helpful console warnings when required frontmatter fields are missing
### Requirement 12: Table of Contents
**User Story:** As a visitor reading a long blog post, I want to see a table of contents, so that I can quickly navigate to specific sections.
#### Acceptance Criteria
1. THE Blog System SHALL extract table of contents from the body.toc property provided by Nuxt Content
2. WHERE a blog post has 3 or more headings, THE Blog System SHALL display a table of contents sidebar on desktop viewports
3. THE Blog System SHALL render TOC links using the heading id and text from body.toc.links array
4. WHEN a visitor clicks a TOC link, THE Blog System SHALL smooth-scroll to the corresponding heading
5. THE Blog System SHALL highlight the active section in TOC based on scroll position using IntersectionObserver
6. THE Blog System SHALL hide the TOC on mobile viewports and show it as a collapsible section instead
7. THE Blog System SHALL support nested heading levels (h2, h3) in the TOC structure
### Requirement 13: Search Functionality
**User Story:** As a visitor, I want to search through blog posts, so that I can quickly find content on specific topics.
#### Acceptance Criteria
1. THE Blog System SHALL provide a search input field on the blog listing page using UInput component
2. WHEN a visitor types in the search field, THE Blog System SHALL filter posts using queryContent().where({ $or: [{ title: { $icontains: query } }, { description: { $icontains: query } }] })
3. THE Blog System SHALL debounce search input by 300ms to avoid excessive queries
4. THE Blog System SHALL display search results count and clear button when search is active
5. THE Blog System SHALL highlight search terms in the results using text highlighting
6. WHERE no results match the search query, THE Blog System SHALL display a "No posts found" message with suggestions
7. THE Blog System SHALL combine search with tag filtering when both are active
### Requirement 14: RSS Feed Generation
**User Story:** As a visitor, I want to subscribe to the blog via RSS, so that I can receive updates on new posts.
#### Acceptance Criteria
1. THE Blog System SHALL generate an RSS feed at /blog/rss.xml for English posts
2. THE Blog System SHALL generate an RSS feed at /fa/blog/rss.xml for Persian posts
3. THE Blog System SHALL use a Nitro server route to dynamically generate RSS XML from queryContent results
4. THE Blog System SHALL include post title, description, link, pubDate, and guid in each RSS item
5. THE Blog System SHALL set proper Content-Type header (application/rss+xml) for RSS endpoints
6. THE Blog System SHALL include channel metadata (title, description, link, language) in the RSS feed
7. THE Blog System SHALL add a link to the RSS feed in the blog listing page header for discoverability
### Requirement 15: Code Block Enhancements
**User Story:** As a visitor reading technical blog posts, I want enhanced code blocks with copy functionality, so that I can easily use code examples.
#### Acceptance Criteria
1. THE Blog System SHALL display a "Copy" button on all code blocks using a custom ProseCode component
2. WHEN a visitor clicks the copy button, THE Blog System SHALL copy the code to clipboard and show a success feedback
3. THE Blog System SHALL display the programming language label on code blocks when specified in markdown
4. THE Blog System SHALL support line highlighting using Nuxt Content's code highlighting syntax (```js{1,3-5})
5. THE Blog System SHALL apply syntax highlighting theme that matches the current color mode (light/dark)
6. THE Blog System SHALL support filename display for code blocks using custom metadata (```js [filename.js])
### Requirement 16: Navigation and Breadcrumbs
**User Story:** As a visitor, I want clear navigation between blog pages, so that I can easily move around the blog section.
#### Acceptance Criteria
1. THE Blog System SHALL display breadcrumb navigation using UBreadcrumb component on blog detail pages showing Home > Blog > [Post Title]
2. THE Blog System SHALL provide a "Back to Blog" link using localePath() to maintain locale context
3. THE Blog System SHALL use useRoute() to detect blog routes and highlight the blog section in TopNav component
4. WHERE previous/next posts exist chronologically, THE Blog System SHALL query adjacent posts using .sort() and .limit() and display navigation links
5. THE Blog System SHALL use localePath() helper from @nuxtjs/i18n for all blog navigation links to maintain locale context
6. THE Blog System SHALL implement keyboard navigation (arrow keys) for previous/next post navigation
+315
View File
@@ -0,0 +1,315 @@
# Implementation Plan
This implementation plan breaks down the blog system development into discrete, actionable coding tasks. Each task builds incrementally on previous work, with all code integrated and functional at each step.
## Task List
- [x] 1. Install and configure Nuxt Content module
- Install @nuxt/content package via pnpm
- Add @nuxt/content to modules array in nuxt.config.ts (before other modules)
- Configure content options: highlight themes (github-light/github-dark), markdown.mdc: true, toc depth
- Add content-specific route rules for caching (/blog, /fa/blog with swr: 3600)
- Verify installation by starting dev server and checking for content module initialization
- _Requirements: 1.1, 1.2, 1.5, 1.6_
- [ ] 2. Create content directory structure and sample posts
- Create content/en/blog/ and content/fa/blog/ directories
- Create TypeScript interface for BlogPost extending ParsedContent in app/types/blog.ts
- Write 2 sample English blog posts with complete frontmatter (title, description, date, tags, image)
- Write 2 sample Persian blog posts with RTL content
- Include code blocks, headings, lists, and images in sample posts for testing
- Create one draft post to test draft filtering
- _Requirements: 2.1, 2.3, 2.4, 3.1, 3.2, 3.5, 3.6_
- [ ] 3. Implement useBlog composable with utility functions
- Create app/composables/useBlog.ts file
- Implement calculateReadingTime function (200 words/min from body.children)
- Implement formatDate function using Intl.DateTimeFormat with locale support
- Implement extractUniqueTags function to aggregate tags from posts array
- Implement getBlogPath function returning locale-aware path
- Implement filterPostsBySearch function for title/description/tags filtering
- Implement filterPostsByTag function
- Export all functions with proper TypeScript types
- _Requirements: 4.7, 11.6_
- [x] 4. Update i18n translation files with blog keys
- Add blog section to i18n/locales/en.json with all required keys (title, explore, empty, readMore, readingTime, publishedOn, backToBlog, previousPost, nextPost, tableOfContents, searchPlaceholder, filterByTag, allPosts, noResults, copyCode, codeCopied, subscribe)
- Add corresponding Persian translations to i18n/locales/fa.json
- Verify translations are loaded by checking in dev tools
- _Requirements: 4.5, 8.1_
- [x] 5. Implement blog listing page
- [x] 5.1 Update app/pages/blog/index.vue with content fetching
- Replace placeholder content with queryContent implementation
- Use useAsyncData to fetch posts for current locale with .where({ draft: { $ne: true } })
- Apply .sort({ date: -1 }) and .only() for required fields
- Implement computed property for extracting unique tags using useBlog composable
- Add reactive refs for searchQuery and selectedTag
- Implement computed filteredPosts using filterPostsBySearch and filterPostsByTag
- _Requirements: 4.1, 4.2, 4.6, 4.8, 7.1_
- [x] 5.2 Create BlogCard component
- Create app/components/blog/BlogCard.vue
- Accept post prop with BlogPost type
- Use UCard as base component with hover effects
- Display NuxtImg for cover image with lazy loading and fallback
- Display title, description, formatted date, reading time, and tags
- Use UBadge for tags display
- Use localePath for navigation link
- Apply responsive styling
- _Requirements: 4.3, 10.1, 10.2_
- [x] 5.3 Create BlogSearch component
- Create app/components/blog/BlogSearch.vue
- Accept modelValue prop and emit update:modelValue
- Use UInput with search icon and clear button
- Implement debounce using useDebounceFn from VueUse (300ms)
- Add i18n placeholder text
- _Requirements: 13.2, 13.3_
- [x] 5.4 Create BlogTagFilter component
- Create app/components/blog/BlogTagFilter.vue
- Accept tags array and modelValue props
- Display tags as UButton or UBadge with click handlers
- Highlight active tag with primary color
- Add "All posts" option to clear filter
- Update URL query parameter using useRoute and navigateTo
- Read query parameter on mount to restore filter state
- Apply horizontal scroll on mobile
- _Requirements: 7.2, 7.3, 7.4, 7.5, 7.6_
- [x] 5.5 Create BlogEmpty component and integrate all components
- Create app/components/blog/BlogEmpty.vue with empty state message
- Import and use BlogSearch, BlogTagFilter, BlogCard, BlogEmpty in index.vue
- Implement grid layout for blog cards (responsive: 1 col mobile, 2 col tablet, 3 col desktop)
- Add page header with title and description using i18n
- Test search, filter, and empty state scenarios
- _Requirements: 4.4, 4.5, 13.4, 13.6_
- [x] 6. Implement blog detail page
- [x] 6.1 Update app/pages/blog/[...slug].vue with content fetching
- Replace placeholder content with queryContent().findOne() implementation
- Use useAsyncData with slug-based key
- Fetch post using _path matching for current locale
- Throw createError({ statusCode: 404 }) if post not found
- Fetch adjacent posts for prev/next navigation using separate query
- Calculate current post index in sorted posts array
- _Requirements: 5.1, 5.5, 16.4_
- [x] 6.2 Implement SEO meta tags and structured data
- Use useContentHead(post) for automatic meta generation
- Use useSeoMeta for custom title, og tags, twitter cards
- Set og:type to "article" with article:published_time and article:tag
- Use post.image or default cover image for og:image
- Add JSON-LD structured data using useHead with BlogPosting schema
- Include author, datePublished, headline in structured data
- _Requirements: 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.8_
- [ ] 6.3 Create BlogPost metadata component
- Create app/components/blog/BlogPost.vue
- Accept post prop with BlogPost type
- Display post title as h1
- Display formatted date using formatDate from useBlog
- Display reading time using calculateReadingTime from useBlog
- Display author if available
- Display tags as UBadge components
- Display cover image using NuxtImg if available
- Use semantic HTML (article, header, time elements)
- _Requirements: 5.4_
- [ ] 6.4 Implement ContentRenderer with Prose styling
- Use ContentRenderer component to render post.body
- Wrap in article element with proper semantic structure
- Apply dir attribute based on locale (rtl for fa, ltr for en)
- Add CSS to force LTR for code blocks in RTL context
- Verify Shiki syntax highlighting is working
- Test with sample posts containing various markdown elements
- _Requirements: 5.2, 5.3, 5.7, 9.1, 9.2, 9.3_
- [ ] 6.5 Create BlogTableOfContents component
- Create app/components/blog/BlogTableOfContents.vue
- Accept toc prop from post.body.toc
- Render nested heading structure from toc.links
- Implement smooth scroll to heading on link click
- Use IntersectionObserver to track active section
- Highlight active section in TOC
- Make sticky on desktop (position: sticky)
- Make collapsible using UAccordion on mobile
- Only show if post has 3+ headings
- _Requirements: 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7_
- [ ] 6.6 Create BlogNavigation component
- Create app/components/blog/BlogNavigation.vue
- Accept prev and next props (BlogPost | null)
- Display previous post link with title and arrow icon
- Display next post link with title and arrow icon
- Use UButton with icon slots
- Use localePath for navigation links
- Implement keyboard navigation (@keydown for arrow keys)
- Apply flexbox layout with space-between
- _Requirements: 16.4, 16.5, 16.6_
- [ ] 6.7 Create breadcrumb navigation and integrate all components
- Use UBreadcrumb component with links array (Home > Blog > Post Title)
- Use localePath for breadcrumb links
- Import and use BlogPost, ContentRenderer, BlogTableOfContents, BlogNavigation
- Add "Back to Blog" link using localePath
- Implement responsive layout (TOC sidebar on desktop, inline on mobile)
- Test with both English and Persian posts
- Test prev/next navigation
- _Requirements: 16.1, 16.2, 16.3, 16.5_
- [ ] 7. Implement custom Prose components
- [ ] 7.1 Create ProseCode component with copy functionality
- Create app/components/content/ProseCode.vue
- Accept code, language, filename, highlights props
- Display language label if provided
- Display filename if provided
- Add copy button with icon
- Implement copy to clipboard using navigator.clipboard API
- Show success feedback (icon change or toast)
- Apply syntax highlighting theme based on color mode
- Support line highlighting from highlights prop
- _Requirements: 15.1, 15.2, 15.3, 15.4, 15.5, 15.6_
- [ ] 7.2 Create custom MDC components
- Create app/components/content/BlogCallout.vue for callout boxes
- Accept title and type props (info, warning, success)
- Use UCard with colored border based on type
- Create app/components/content/Alert.vue for inline alerts
- Test MDC syntax in sample blog posts (::blog-callout, ::alert)
- _Requirements: 5.6_
- [ ]* 7.3 Customize Prose component styles
- Update app.config.ts with prose customization
- Define styles for ProseH1, ProseH2, ProseH3 (font sizes, spacing, colors)
- Define styles for ProseP (line height, spacing, colors)
- Define styles for ProseCode inline code (background, padding, border-radius)
- Define styles for ProseA links (color, hover effects)
- Define styles for ProseImg (responsive, rounded corners)
- Test with sample posts to verify styling
- _Requirements: 5.7, 8.2_
- [ ] 8. Implement RSS feed generation
- Create server/routes/blog/rss.xml.ts server route
- Use serverQueryContent to fetch published posts for current locale
- Detect locale from URL path (/blog/rss.xml vs /fa/blog/rss.xml)
- Generate RSS 2.0 XML with channel metadata
- Include item elements for each post (title, link, guid, pubDate, description)
- Implement escapeXml helper function for XML safety
- Set Content-Type header to application/rss+xml
- Add RSS link to blog listing page header
- Test RSS feed in browser and RSS reader
- _Requirements: 14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7_
- [ ] 9. Configure prerendering and route rules
- Update nitro.prerender.routes in nuxt.config.ts to include /blog and /fa/blog
- Add dynamic route generation for all blog posts using queryContent
- Verify route rules for caching are applied (/blog/**, /fa/blog/** with swr: 3600)
- Test static generation by running pnpm generate
- Verify all blog routes are prerendered in .output/public
- _Requirements: 10.5_
- [ ] 10. Add blog link to navigation
- Update app/components/common/TopNav.vue to include blog link
- Use localePath('/blog') for navigation
- Highlight blog link when on blog routes using useRoute()
- Add blog icon if desired
- Test navigation in both locales
- _Requirements: 16.3_
- [ ] 11. Create default blog cover image
- Create or add a default cover image to public/img/blog/default-cover.jpg
- Ensure image is optimized (WebP format, appropriate dimensions)
- Use this image as fallback in BlogCard and SEO meta tags
- _Requirements: 6.4_
- [ ]* 12. Performance optimization and testing
- Run Lighthouse audit on blog listing and detail pages
- Verify lazy loading of images below fold
- Check code splitting in network tab (separate chunks for blog components)
- Verify static generation of all routes
- Test hot-reload in development mode
- Measure and optimize Time to First Byte (TTFB)
- Verify Core Web Vitals (LCP, FID, CLS)
- _Requirements: 10.3, 10.4, 10.6, 10.7, 11.1_
- [ ]* 13. Accessibility testing and improvements
- Test keyboard navigation (Tab, Enter, arrow keys)
- Test with screen reader (NVDA or VoiceOver)
- Verify color contrast ratios using browser dev tools
- Ensure all interactive elements have focus indicators
- Add ARIA labels where needed
- Verify semantic HTML structure
- Test with reduced motion preference
- _Requirements: 8.3, 8.4, 8.5, 8.6_
- [ ]* 14. Cross-browser and responsive testing
- Test on Chrome, Firefox, Safari, Edge
- Test on mobile devices (iOS Safari, Chrome Android)
- Test on tablet viewports
- Verify RTL layout on Persian pages
- Test search and filter functionality on all devices
- Verify image optimization and lazy loading
- Test code block copy functionality
- _Requirements: 8.1, 9.1, 9.2, 9.4_
- [ ]* 15. Documentation and sample content
- Create README.md in content/ directory with authoring guidelines
- Document frontmatter schema and required fields
- Provide markdown examples for common elements
- Document MDC component usage
- Add comments in code for complex logic
- Update main README.md with blog feature description
- _Requirements: 11.3, 11.4_