From 713bb839817f196e9b4bf36d3b0374bc8e8332a8 Mon Sep 17 00:00:00 2001 From: mahdiarghyani Date: Mon, 10 Nov 2025 18:09:18 +0330 Subject: [PATCH] implement ssg config for blog posts in project , --- .kiro/specs/blog-ssg-optimization/design.md | 394 ++++ .../blog-ssg-optimization/requirements.md | 83 + .kiro/specs/blog-ssg-optimization/tasks.md | 78 + .kiro/specs/i18n-routing-fixes/design.md | 595 +++++ .../specs/i18n-routing-fixes/requirements.md | 113 + .kiro/specs/i18n-routing-fixes/tasks.md | 101 + .kiro/specs/layout-refactoring/design.md | 226 ++ .../specs/layout-refactoring/requirements.md | 60 + .kiro/specs/layout-refactoring/tasks.md | 40 + .kiro/specs/page-transitions-ux/design.md | 410 ++++ .../specs/page-transitions-ux/requirements.md | 72 + .kiro/specs/page-transitions-ux/tasks.md | 97 + README.md | 31 +- SSG-TEST-GUIDE.md | 149 ++ app/app.vue | 14 +- app/assets/css/main.css | 1 + app/assets/css/transitions.css | 195 ++ app/components/LanguageSwitcher.vue | 49 +- app/components/blog/BlogCard.vue | 4 +- app/components/blog/BlogNavigation.vue | 16 +- app/components/common/FooterCopyright.vue | 13 +- app/components/common/TopNav.vue | 220 +- app/components/content/ProseCode.vue | 156 +- app/composables/useViewTransition.ts | 80 + app/layouts/default.vue | 14 +- app/pages/blog/[...slug].vue | 52 +- app/pages/blog/index.vue | 2 +- i18n/locales/en.json | 3 +- i18n/locales/fa.json | 3 +- nuxt-diagnostic-report.json | 26 + nuxt-ssg-diagnostic.cjs | 313 +++ nuxt.config.ts | 48 +- package.json | 3 + pnpm-lock.yaml | 2056 +++++++++++++++-- server/plugins/prerender.ts | 37 + test-ssg.md | 40 + vercel.json | 8 + 37 files changed, 5505 insertions(+), 297 deletions(-) create mode 100644 .kiro/specs/blog-ssg-optimization/design.md create mode 100644 .kiro/specs/blog-ssg-optimization/requirements.md create mode 100644 .kiro/specs/blog-ssg-optimization/tasks.md create mode 100644 .kiro/specs/i18n-routing-fixes/design.md create mode 100644 .kiro/specs/i18n-routing-fixes/requirements.md create mode 100644 .kiro/specs/i18n-routing-fixes/tasks.md create mode 100644 .kiro/specs/layout-refactoring/design.md create mode 100644 .kiro/specs/layout-refactoring/requirements.md create mode 100644 .kiro/specs/layout-refactoring/tasks.md create mode 100644 .kiro/specs/page-transitions-ux/design.md create mode 100644 .kiro/specs/page-transitions-ux/requirements.md create mode 100644 .kiro/specs/page-transitions-ux/tasks.md create mode 100644 SSG-TEST-GUIDE.md create mode 100644 app/assets/css/transitions.css create mode 100644 app/composables/useViewTransition.ts create mode 100644 nuxt-diagnostic-report.json create mode 100644 nuxt-ssg-diagnostic.cjs create mode 100644 server/plugins/prerender.ts create mode 100644 test-ssg.md diff --git a/.kiro/specs/blog-ssg-optimization/design.md b/.kiro/specs/blog-ssg-optimization/design.md new file mode 100644 index 0000000..b2959aa --- /dev/null +++ b/.kiro/specs/blog-ssg-optimization/design.md @@ -0,0 +1,394 @@ +# Design Document: Blog SSG Optimization + +## Overview + +این طراحی یک سیستم کامل Static Site Generation برای بلاگ را پیاده‌سازی می‌کند که تمام صفحات بلاگ را در زمان build به صورت استاتیک تولید می‌کند. این رویکرد performance، SEO و قابلیت استقرار را بهبود می‌دهد. + +## Architecture + +### High-Level Architecture + +``` +Build Time: +┌─────────────────────────────────────────────────────────┐ +│ Nuxt Build Process │ +│ │ +│ ┌──────────────┐ ┌─────────────────┐ │ +│ │ Content │─────▶│ Route │ │ +│ │ Discovery │ │ Generator │ │ +│ └──────────────┘ └─────────────────┘ │ +│ │ │ │ +│ │ ▼ │ +│ │ ┌─────────────────┐ │ +│ │ │ Pre-renderer │ │ +│ │ └─────────────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌──────────────┐ ┌─────────────────┐ │ +│ │ Sitemap │ │ Static HTML │ │ +│ │ Generator │ │ Files │ │ +│ └──────────────┘ └─────────────────┘ │ +└─────────────────────────────────────────────────────────┘ + │ + ▼ + ┌──────────────────┐ + │ .output/public │ + │ (Static Files) │ + └──────────────────┘ +``` + +### Runtime Architecture + +``` +User Request ──▶ CDN/Static Host ──▶ Pre-rendered HTML + (No Server Required) +``` + +## Components and Interfaces + +### 1. Nitro Prerender Configuration + +**Purpose:** پیکربندی Nitro برای pre-rendering خودکار تمام مسیرهای بلاگ + +**Location:** `nuxt.config.ts` + +**Configuration:** +```typescript +nitro: { + prerender: { + crawlLinks: true, + routes: [ + '/', + '/blog', + '/fa/blog' + ] + } +} +``` + +**Key Features:** +- `crawlLinks: true` - خزیدن خودکار لینک‌ها برای کشف مسیرها +- مسیرهای seed برای شروع crawling +- پشتیبانی از چند زبانه (en/fa) + +### 2. Dynamic Route Generator Hook + +**Purpose:** تولید خودکار لیست تمام مسیرهای بلاگ برای pre-rendering + +**Location:** `nuxt.config.ts` یا `server/plugins/prerender.ts` + +**Implementation Strategy:** + + +از Nitro hook `prerender:routes` برای اضافه کردن مسیرهای دینامیک: + +```typescript +// server/plugins/prerender.ts +export default defineNitroPlugin((nitroApp) => { + nitroApp.hooks.hook('prerender:routes', async (ctx) => { + // Fetch all blog posts + const posts = await queryCollection('blog') + .where('draft', '<>', true) + .all() + + // Generate routes for each post + for (const post of posts) { + ctx.routes.add(post.path) + } + }) +}) +``` + +**Benefits:** +- تشخیص خودکار تمام پست‌های بلاگ +- عدم نیاز به لیست دستی مسیرها +- پشتیبانی از draft posts (حذف از pre-render) + +### 3. Sitemap Module Integration + +**Purpose:** تولید خودکار sitemap.xml برای SEO + +**Module:** `@nuxtjs/sitemap` یا `nuxt-simple-sitemap` + +**Configuration:** +```typescript +// nuxt.config.ts +modules: [ + '@nuxtjs/sitemap' +], + +sitemap: { + hostname: 'https://aliarghyani.vercel.app', + gzip: true, + routes: async () => { + const posts = await queryCollection('blog') + .where('draft', '<>', true) + .all() + + return posts.map(post => ({ + url: post.path, + lastmod: post.updatedAt || post.date, + changefreq: 'monthly', + priority: 0.8 + })) + } +} +``` + +**Output:** +- `/sitemap.xml` - sitemap اصلی +- شامل تمام پست‌های منتشر شده +- تاریخ آخرین تغییر برای هر URL + +### 4. Build Script Optimization + +**Purpose:** بهینه‌سازی فرآیند build برای SSG + +**Location:** `package.json` + +**Scripts:** +```json +{ + "scripts": { + "build": "nuxt build", + "generate": "nuxt generate", + "preview": "nuxt preview" + } +} +``` + +**Command Usage:** +- `pnpm generate` - تولید فایل‌های استاتیک کامل +- خروجی در `.output/public` + +## Data Models + +### Blog Post Route Structure + +```typescript +interface BlogRoute { + path: string // e.g., "/blog/post-slug" or "/fa/blog/post-slug" + locale: 'en' | 'fa' + slug: string + lastmod: string // ISO 8601 date + priority: number // 0.0 to 1.0 +} +``` + +### Prerender Context + +```typescript +interface PrerenderContext { + routes: Set // مجموعه مسیرهای برای pre-render +} +``` + +## Error Handling + +### 1. Missing Content Files + +**Scenario:** فایل markdown وجود ندارد + +**Handling:** +- در زمان build، خطا نمایش داده شود +- Build process متوقف شود +- پیام خطای واضح برای developer + +### 2. Invalid Frontmatter + +**Scenario:** frontmatter پست بلاگ نامعتبر است + +**Handling:** +- Validation در زمان build +- خطای واضح با نام فایل +- پیشنهاد فرمت صحیح + +### 3. Broken Internal Links + +**Scenario:** لینک داخلی به صفحه‌ای اشاره می‌کند که وجود ندارد + +**Handling:** +- Warning در build logs +- ادامه build process +- لیست لینک‌های شکسته در انتهای build + +### 4. Build Timeout + +**Scenario:** pre-rendering زمان زیادی می‌برد + +**Handling:** +- تنظیم timeout مناسب در Nitro config +- نمایش progress در console +- امکان افزایش timeout برای بلاگ‌های بزرگ + +## Testing Strategy + +### 1. Build Testing + +**Objective:** اطمینان از موفقیت build process + +**Tests:** +- اجرای `pnpm generate` و بررسی exit code +- بررسی وجود فایل‌های HTML در `.output/public` +- بررسی تعداد فایل‌های تولید شده + +**Example:** +```bash +pnpm generate +# Check exit code +echo $? # Should be 0 + +# Check generated files +ls -la .output/public/blog/ +ls -la .output/public/fa/blog/ +``` + +### 2. Route Coverage Testing + +**Objective:** اطمینان از pre-render تمام مسیرها + +**Tests:** +- بررسی وجود HTML برای هر پست بلاگ +- بررسی صفحات index +- بررسی هر دو locale + +**Example:** +```bash +# Check English blog posts +test -f .output/public/blog/index.html +test -f .output/public/blog/post-slug/index.html + +# Check Persian blog posts +test -f .output/public/fa/blog/index.html +test -f .output/public/fa/blog/post-slug/index.html +``` + +### 3. Sitemap Validation + +**Objective:** اطمینان از صحت sitemap + +**Tests:** +- بررسی وجود `/sitemap.xml` +- Validation XML syntax +- بررسی تعداد URLها +- بررسی فرمت تاریخ‌ها + +**Example:** +```bash +# Check sitemap exists +test -f .output/public/sitemap.xml + +# Validate XML +xmllint --noout .output/public/sitemap.xml +``` + +### 4. Content Integrity Testing + +**Objective:** اطمینان از صحت محتوای pre-rendered + +**Tests:** +- بررسی وجود meta tags در HTML +- بررسی وجود محتوای کامل +- بررسی structured data (JSON-LD) + +**Example:** +```bash +# Check meta tags +grep -q "og:title" .output/public/blog/post-slug/index.html +grep -q "application/ld+json" .output/public/blog/post-slug/index.html +``` + +### 5. Performance Testing + +**Objective:** اندازه‌گیری بهبود performance + +**Metrics:** +- زمان بارگذاری صفحه +- First Contentful Paint (FCP) +- Largest Contentful Paint (LCP) +- Time to Interactive (TTI) + +**Tools:** +- Lighthouse CI +- WebPageTest +- Chrome DevTools + +## Implementation Phases + +### Phase 1: Basic SSG Setup +- پیکربندی Nitro prerender +- تست با چند پست نمونه + +### Phase 2: Dynamic Route Generation +- پیاده‌سازی prerender hook +- تشخیص خودکار تمام پست‌ها + +### Phase 3: Sitemap Integration +- نصب و پیکربندی sitemap module +- تولید sitemap با تمام مسیرها + +### Phase 4: Optimization & Testing +- بهینه‌سازی build process +- تست کامل و validation + +## Deployment Considerations + +### Static Hosting Options + +**Recommended Platforms:** +1. **Vercel** - بهترین گزینه برای Nuxt +2. **Netlify** - پشتیبانی عالی از SSG +3. **Cloudflare Pages** - سریع و رایگان +4. **GitHub Pages** - رایگان برای پروژه‌های عمومی + +### Build Command + +```bash +pnpm generate +``` + +### Output Directory + +``` +.output/public +``` + +### Environment Variables + +```env +NUXT_PUBLIC_SITE_URL=https://aliarghyani.vercel.app +``` + +## Performance Expectations + +### Before SSG (SSR) +- TTFB: 200-500ms +- FCP: 800-1200ms +- LCP: 1500-2500ms + +### After SSG +- TTFB: 50-100ms (از CDN) +- FCP: 300-600ms +- LCP: 600-1200ms + +**Expected Improvement:** 50-70% بهبود در زمان بارگذاری + +## Maintenance + +### Adding New Posts + +1. اضافه کردن فایل markdown به `content/` +2. اجرای `pnpm generate` +3. Deploy فایل‌های جدید + +### Updating Existing Posts + +1. ویرایش فایل markdown +2. اجرای `pnpm generate` +3. Deploy مجدد + +### No Server Maintenance Required + +- نیازی به نگهداری سرور Node.js نیست +- فقط فایل‌های استاتیک +- کاهش هزینه‌های infrastructure diff --git a/.kiro/specs/blog-ssg-optimization/requirements.md b/.kiro/specs/blog-ssg-optimization/requirements.md new file mode 100644 index 0000000..b7f0351 --- /dev/null +++ b/.kiro/specs/blog-ssg-optimization/requirements.md @@ -0,0 +1,83 @@ +# Requirements Document + +## Introduction + +این سند نیازمندی‌های پیاده‌سازی کامل Static Site Generation (SSG) برای بلاگ را مشخص می‌کند. هدف اصلی بهبود performance، SEO و کاهش هزینه‌های هاستینگ از طریق pre-rendering تمام صفحات بلاگ در زمان build است. + +## Glossary + +- **Blog_System**: سیستم مدیریت و نمایش محتوای بلاگ در اپلیکیشن Nuxt +- **SSG (Static Site Generation)**: فرآیند تولید فایل‌های HTML استاتیک در زمان build +- **Pre-rendering**: تولید HTML از قبل برای صفحات در زمان build +- **Nuxt_Content**: ماژول Nuxt برای مدیریت محتوای markdown +- **Sitemap**: فایل XML حاوی لیست تمام URLهای سایت برای موتورهای جستجو +- **Build_Process**: فرآیند تبدیل کد منبع به فایل‌های قابل استقرار + +## Requirements + +### Requirement 1 + +**User Story:** به عنوان یک کاربر، می‌خواهم صفحات بلاگ با سرعت بالا بارگذاری شوند تا تجربه کاربری بهتری داشته باشم + +#### Acceptance Criteria + +1. WHEN a user navigates to any blog post, THE Blog_System SHALL serve a pre-rendered HTML file +2. WHEN a user navigates to the blog index page, THE Blog_System SHALL serve a pre-rendered HTML file +3. THE Blog_System SHALL generate all blog routes during the Build_Process +4. THE Blog_System SHALL include both English and Persian blog routes in pre-rendering + +### Requirement 2 + +**User Story:** به عنوان یک توسعه‌دهنده، می‌خواهم تمام مسیرهای بلاگ به صورت خودکار شناسایی و pre-render شوند تا نیازی به مدیریت دستی نباشد + +#### Acceptance Criteria + +1. THE Blog_System SHALL automatically discover all markdown files in the content directory during Build_Process +2. THE Blog_System SHALL generate routes for all discovered blog posts in both locales +3. WHEN new blog posts are added to the content directory, THE Blog_System SHALL include them in the next Build_Process +4. THE Blog_System SHALL exclude draft posts from pre-rendering + +### Requirement 3 + +**User Story:** به عنوان یک مدیر سایت، می‌خواهم sitemap خودکار تولید شود تا SEO بهتری داشته باشم + +#### Acceptance Criteria + +1. THE Blog_System SHALL generate an XML sitemap during Build_Process +2. THE Blog_System SHALL include all published blog posts in the sitemap +3. THE Blog_System SHALL include both English and Persian URLs in the sitemap +4. THE Blog_System SHALL include lastmod dates for each URL in the sitemap +5. THE Blog_System SHALL exclude draft posts from the sitemap + +### Requirement 4 + +**User Story:** به عنوان یک توسعه‌دهنده، می‌خواهم فرآیند build بهینه باشد تا زمان deployment کاهش یابد + +#### Acceptance Criteria + +1. THE Blog_System SHALL use efficient crawling strategies to discover routes +2. THE Blog_System SHALL cache unchanged pages during Build_Process where possible +3. THE Blog_System SHALL provide clear build logs showing pre-rendered routes +4. WHEN the Build_Process completes, THE Blog_System SHALL output all generated static files to the dist directory + +### Requirement 5 + +**User Story:** به عنوان یک کاربر، می‌خواهم محتوای بلاگ برای موتورهای جستجو قابل دسترسی باشد تا بتوانم مطالب را از طریق جستجو پیدا کنم + +#### Acceptance Criteria + +1. THE Blog_System SHALL include complete HTML content in pre-rendered pages +2. THE Blog_System SHALL include proper meta tags in pre-rendered pages +3. THE Blog_System SHALL include structured data (JSON-LD) in pre-rendered pages +4. THE Blog_System SHALL ensure all internal links are functional in static output + +### Requirement 6 + +**User Story:** به عنوان یک توسعه‌دهنده، می‌خواهم بتوانم سایت را روی هر CDN یا static hosting استقرار دهم + +#### Acceptance Criteria + +1. THE Blog_System SHALL generate a fully static output compatible with static hosting services +2. THE Blog_System SHALL not require a Node.js server for serving blog pages +3. THE Blog_System SHALL include all necessary assets in the static output +4. THE Blog_System SHALL generate proper fallback pages for 404 errors diff --git a/.kiro/specs/blog-ssg-optimization/tasks.md b/.kiro/specs/blog-ssg-optimization/tasks.md new file mode 100644 index 0000000..b9a22cd --- /dev/null +++ b/.kiro/specs/blog-ssg-optimization/tasks.md @@ -0,0 +1,78 @@ +# Implementation Plan + +- [x] 1. Install and configure sitemap module + + + + - Install `nuxt-simple-sitemap` package + - Add module to `nuxt.config.ts` + - Configure basic sitemap settings with site URL + - _Requirements: 3.1, 3.2, 3.3_ + +- [x] 2. Create dynamic route generator for blog posts + + + - Create `server/plugins/prerender.ts` file + - Implement Nitro hook to discover all blog posts + - Add all non-draft blog post routes to prerender context + - Handle both English and Persian locales + - _Requirements: 2.1, 2.2, 2.3, 2.4_ + + + +- [ ] 3. Configure Nitro prerender settings + - Update `nitro.prerender` configuration in `nuxt.config.ts` + - Enable `crawlLinks` for automatic link discovery + - Add seed routes for blog index pages (`/blog`, `/fa/blog`) + - Configure prerender to exclude draft posts + + + - _Requirements: 1.3, 1.4, 4.1_ + +- [ ] 4. Implement sitemap dynamic routes + - Configure sitemap module to fetch blog posts dynamically + - Map blog posts to sitemap entries with proper metadata + + + - Include `lastmod`, `changefreq`, and `priority` for each entry + - Ensure draft posts are excluded from sitemap + - _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5_ + + +- [ ] 5. Update build configuration + - Verify `nuxt generate` command in `package.json` + - Add environment variable for site URL if needed + - Document build process in README or comments + - _Requirements: 4.4, 6.1, 6.3_ + +- [x] 6. Test SSG build process + + + - Run `pnpm generate` command + - Verify all blog post HTML files are generated in `.output/public` + - Check both English and Persian blog routes + - Verify sitemap.xml is generated + - _Requirements: 1.1, 1.2, 4.3, 4.4_ + +- [ ]* 7. Validate generated output + - Check meta tags in generated HTML files + - Verify structured data (JSON-LD) is present + - Test internal links functionality + - Validate sitemap XML syntax + - _Requirements: 5.1, 5.2, 5.3, 5.4_ + +- [ ]* 8. Performance testing + - Measure page load times before and after SSG + - Run Lighthouse audit on generated pages + - Document performance improvements + - _Requirements: 1.1, 1.2_ + +- [x] 9. Update deployment documentation + + + + - Document the `pnpm generate` command for deployment + - Specify output directory (`.output/public`) + - List compatible static hosting platforms + - Add environment variables needed for production + - _Requirements: 6.1, 6.2, 6.4_ diff --git a/.kiro/specs/i18n-routing-fixes/design.md b/.kiro/specs/i18n-routing-fixes/design.md new file mode 100644 index 0000000..5b02a80 --- /dev/null +++ b/.kiro/specs/i18n-routing-fixes/design.md @@ -0,0 +1,595 @@ +# i18n Routing Fixes Design Document + +## Overview + +This document outlines the technical design for fixing i18n routing and hydration issues in the Nuxt 4 portfolio application. The issues include Vue Router warnings during language switching, hydration mismatches in the Footer component, and accessibility warnings in the language switcher. + +### Current Issues + +1. **Vue Router Warnings**: When switching languages, Vue Router cannot find blog post routes with language prefixes +2. **Hydration Mismatch**: Footer component causes hydration errors due to colorMode access during SSR +3. **ARIA Warning**: Language switcher has aria-hidden on focusable elements +4. **Route Resolution**: Blog routes with `/en/` or `/fa/` prefixes are not properly resolved + +### Design Goals + +1. **Fix Route Resolution**: Ensure all blog routes work correctly with language prefixes +2. **Eliminate Hydration Errors**: Make Footer component SSR-safe +3. **Improve Accessibility**: Fix ARIA warnings in language switcher +4. **Maintain User Experience**: Keep smooth language switching without breaking functionality + +## Architecture + +### Current i18n Configuration + +```typescript +// nuxt.config.ts +i18n: { + defaultLocale: 'en', + strategy: 'prefix_except_default', // ← This is the issue! + locales: [ + { code: 'en', language: 'en-US', name: 'English', dir: 'ltr', file: 'en.json' }, + { code: 'fa', language: 'fa-IR', name: 'فارسی', dir: 'rtl', file: 'fa.json' }, + ], + // ... +} +``` + +**Problem**: The `prefix_except_default` strategy means: +- English routes: `/blog/post-slug` (no prefix) +- Persian routes: `/fa/blog/post-slug` (with prefix) + +This causes issues because: +1. Content is organized as `content/en/blog/` and `content/fa/blog/` +2. When switching languages, the router looks for `/en/blog/` routes that don't exist +3. Blog navigation uses `localePath()` which generates inconsistent paths + +### Root Cause Analysis + +#### Issue 1: Route Strategy Mismatch + +**Current Behavior**: +- Content structure: `content/{locale}/blog/` +- Route strategy: `prefix_except_default` (English has no prefix) +- Blog queries: `queryContent('${locale}/blog')` + +**Problem**: When on `/blog/post` (English) and switching to Persian, the app tries to navigate to `/fa/blog/post`, but the content query still uses the old locale path. + +**Solution**: Change strategy to `prefix` so all routes have locale prefixes consistently. + +#### Issue 2: Hydration Mismatch in Footer + +**Current Code**: +```vue + +``` + +**Problem**: +- Server renders with `colorMode.unknown = true` (default) +- Client hydrates with actual colorMode from localStorage +- HTML mismatch causes hydration error + +**Solution**: Use `ClientOnly` for colorMode-dependent content or defer rendering until mounted. + +#### Issue 3: ARIA Warning in Language Switcher + +**Current Code**: +```vue + +``` + +**Problem**: The `sr-only` class likely adds `aria-hidden="true"` to focusable elements, which is invalid. + +**Solution**: Remove `sr-only` from focusable elements and use proper ARIA labels instead. + +## Components and Interfaces + +### 1. i18n Configuration Update + +**File**: `nuxt.config.ts` + +**Changes**: +```typescript +i18n: { + defaultLocale: 'en', + strategy: 'prefix', // ← Change from 'prefix_except_default' + locales: [ + { code: 'en', language: 'en-US', name: 'English', dir: 'ltr', file: 'en.json' }, + { code: 'fa', language: 'fa-IR', name: 'فارسی', dir: 'rtl', file: 'fa.json' }, + ], + langDir: 'locales', + detectBrowserLanguage: { + useCookie: true, + cookieKey: 'i18n_redirected', + alwaysRedirect: false, + redirectOn: 'root' + }, + vueI18n: '~/i18n.config.ts' +} +``` + +**Impact**: +- All routes will have locale prefix: `/en/`, `/fa/` +- Root `/` will redirect to `/en/` (default locale) +- Consistent URL structure across all pages +- Blog routes: `/en/blog/post` and `/fa/blog/post` + +**Migration Notes**: +- Update all internal links to use `localePath()` +- Update sitemap generation +- Update prerender routes +- Test all navigation flows + +### 2. Footer Component Fix + +**File**: `app/components/common/FooterCopyright.vue` + +**Current Implementation**: +```vue + + + +``` + +**Solution 1: Use ClientOnly (Recommended)**: +```vue + + + +``` + +**Solution 2: Use onMounted (Alternative)**: +```vue + + + +``` + +**Recommendation**: Use Solution 1 (ClientOnly) as it's more explicit and follows Nuxt best practices. + +### 3. Language Switcher Fix + +**File**: `app/components/LanguageSwitcher.vue` + +**Current Issues**: +1. `sr-only` class on value might cause ARIA conflicts +2. No proper route switching logic +3. Missing proper ARIA announcements + +**Updated Implementation**: +```vue + + + +``` + +**Key Changes**: +1. Removed `sr-only` from UI config +2. Use `switchLocalePath()` to get the correct route for the new locale +3. Navigate using `router.push()` before setting locale +4. Added proper ARIA label using i18n +5. Changed item labels to full language names for better UX + +### 4. Blog Navigation Updates + +**Files to Update**: +- `app/pages/blog/index.vue` +- `app/pages/blog/[...slug].vue` +- `app/components/blog/BlogCard.vue` +- `app/components/blog/BlogNavigation.vue` + +**Pattern to Follow**: +```vue + +``` + +**Important**: All blog links must use `localePath()` to ensure correct locale prefix. + +## Data Models + +### Route Structure + +**Before (prefix_except_default)**: +``` +/ → English home +/blog → English blog +/blog/post-slug → English post +/fa → Persian home +/fa/blog → Persian blog +/fa/blog/post-slug → Persian post +``` + +**After (prefix)**: +``` +/ → Redirect to /en +/en → English home +/en/blog → English blog +/en/blog/post-slug → English post +/fa → Persian home +/fa/blog → Persian blog +/fa/blog/post-slug → Persian post +``` + +### Content Query Pattern + +**Current**: +```typescript +queryContent(`${locale.value}/blog`) +``` + +**This remains the same** because content structure matches locale codes. + +## Error Handling + +### 404 Handling for Missing Translations + +When a blog post exists in one language but not another: + +```vue + +``` + +### Redirect Handling + +**Root Path Redirect**: +```typescript +// middleware/redirect-root.global.ts +export default defineNuxtRouteMiddleware((to) => { + if (to.path === '/') { + return navigateTo('/en', { redirectCode: 301 }) + } +}) +``` + +## Testing Strategy + +### Manual Testing Checklist + +**i18n Routing**: +- [ ] Navigate to `/` → should redirect to `/en` +- [ ] Navigate to `/en` → should show English home +- [ ] Navigate to `/fa` → should show Persian home +- [ ] Navigate to `/en/blog` → should show English blog listing +- [ ] Navigate to `/fa/blog` → should show Persian blog listing +- [ ] Navigate to `/en/blog/post-slug` → should show English post +- [ ] Navigate to `/fa/blog/post-slug` → should show Persian post + +**Language Switching**: +- [ ] On home page, switch from English to Persian → should navigate to `/fa` +- [ ] On home page, switch from Persian to English → should navigate to `/en` +- [ ] On blog listing, switch languages → should navigate to equivalent blog page +- [ ] On blog post, switch languages → should navigate to equivalent post (if exists) +- [ ] On blog post (only in one language), switch languages → should show fallback message + +**Hydration**: +- [ ] Load page in light mode → no hydration errors in console +- [ ] Load page in dark mode → no hydration errors in console +- [ ] Switch color mode → logo updates correctly +- [ ] Check Footer logo on initial load → no flashing or mismatch + +**Accessibility**: +- [ ] Language switcher is keyboard navigable (Tab, Enter, Arrow keys) +- [ ] Language switcher has proper ARIA labels +- [ ] No ARIA warnings in console +- [ ] Screen reader announces language changes + +**Vue Router**: +- [ ] No Vue Router warnings in console during navigation +- [ ] No Vue Router warnings when switching languages +- [ ] Browser back/forward buttons work correctly +- [ ] URL updates correctly on language switch + +### Browser Console Checks + +**Before Fixes**: +``` +❌ [Vue Router warn]: No match found for location with path "/en/blog/post-slug" +❌ Hydration mismatch in +❌ [ARIA] aria-hidden should not be used on focusable elements +``` + +**After Fixes**: +``` +✅ No Vue Router warnings +✅ No hydration warnings +✅ No ARIA warnings +``` + +## Performance Considerations + +### Impact of Strategy Change + +**Before (prefix_except_default)**: +- English routes: shorter URLs (no prefix) +- Persian routes: longer URLs (with prefix) + +**After (prefix)**: +- All routes: consistent length (with prefix) +- Slightly longer URLs for English (adds 3 characters: `/en`) + +**SEO Impact**: +- Minimal impact (3 characters) +- Better for international SEO (explicit language in URL) +- Easier for search engines to understand language variants + +### Caching Strategy + +Route rules remain the same: +```typescript +routeRules: { + '/en/blog': { swr: 3600 }, + '/fa/blog': { swr: 3600 }, + '/en/blog/**': { swr: 3600 }, + '/fa/blog/**': { swr: 3600 } +} +``` + +## Migration Plan + +### Step 1: Update i18n Configuration +- Change strategy from `prefix_except_default` to `prefix` +- Update prerender routes to include `/en` prefix + +### Step 2: Fix Footer Component +- Wrap colorMode-dependent content in `ClientOnly` +- Add fallback for SSR + +### Step 3: Fix Language Switcher +- Remove `sr-only` from UI config +- Implement proper route switching with `switchLocalePath()` +- Add proper ARIA labels + +### Step 4: Update Blog Components +- Verify all blog links use `localePath()` +- Test blog navigation with new route structure + +### Step 5: Add Redirect Middleware +- Create middleware to redirect `/` to `/en` +- Test redirect behavior + +### Step 6: Update Route Rules +- Update route rules to use `/en` prefix +- Update sitemap generation + +### Step 7: Testing +- Run manual testing checklist +- Verify no console errors +- Test all navigation flows + +## Rollback Plan + +If issues arise: +1. Revert `strategy` to `prefix_except_default` in `nuxt.config.ts` +2. Revert Footer component changes +3. Revert Language Switcher changes +4. Clear browser cache and cookies +5. Restart dev server + +## Summary + +This design addresses all three main issues: + +1. **Vue Router Warnings**: Fixed by changing i18n strategy to `prefix` for consistent route structure +2. **Hydration Mismatch**: Fixed by wrapping colorMode-dependent content in `ClientOnly` +3. **ARIA Warning**: Fixed by removing `sr-only` from focusable elements and using proper ARIA labels + +The changes are minimal, focused, and maintain backward compatibility with the content structure. All blog functionality will continue to work with the new route structure. diff --git a/.kiro/specs/i18n-routing-fixes/requirements.md b/.kiro/specs/i18n-routing-fixes/requirements.md new file mode 100644 index 0000000..746630b --- /dev/null +++ b/.kiro/specs/i18n-routing-fixes/requirements.md @@ -0,0 +1,113 @@ +# Requirements Document + +## Introduction + +This document specifies the requirements for fixing i18n routing and hydration issues in the Nuxt 4 portfolio application. The issues include Vue Router warnings when switching languages, hydration mismatches in the Footer component, and accessibility warnings in the language switcher. + +## Glossary + +- **i18n System**: The internationalization system using @nuxtjs/i18n module for bilingual support (English and Persian) +- **Hydration Mismatch**: A Vue.js error that occurs when server-rendered HTML doesn't match client-side rendered content +- **Vue Router**: The official router for Vue.js applications, integrated with Nuxt +- **Language Switcher**: The UI component that allows users to switch between English and Persian languages +- **Route Prefix**: The language code prefix in URLs (e.g., /en/blog or /fa/blog) +- **localePath**: A helper function from @nuxtjs/i18n that generates locale-aware paths +- **ColorMode**: The dark/light theme system using @nuxtjs/color-mode module +- **ARIA**: Accessible Rich Internet Applications attributes for accessibility + +## Requirements + +### Requirement 1: Fix Vue Router Warnings for Blog Routes + +**User Story:** As a visitor switching languages, I want the blog routes to work correctly, so that I don't encounter navigation errors. + +#### Acceptance Criteria + +1. WHEN a visitor switches from English to Persian, THE i18n System SHALL correctly resolve blog post routes with /fa/ prefix +2. WHEN a visitor switches from Persian to English, THE i18n System SHALL correctly resolve blog post routes with /en/ prefix +3. THE i18n System SHALL use localePath() helper for all blog navigation links to maintain locale context +4. WHERE a blog post exists in the current language, THE i18n System SHALL navigate to the localized version +5. WHERE a blog post does not exist in the target language, THE i18n System SHALL display a fallback message or redirect to the available version +6. THE i18n System SHALL not generate Vue Router warnings in the browser console during language switching +7. THE i18n System SHALL maintain the current page context when switching languages (e.g., stay on blog listing when switching from /blog to /fa/blog) + +### Requirement 2: Fix Hydration Mismatch in Footer Component + +**User Story:** As a visitor loading the page, I want the Footer to render without hydration errors, so that I have a smooth initial page load experience. + +#### Acceptance Criteria + +1. WHEN the page initially loads, THE Footer Component SHALL render identical HTML on server and client +2. THE Footer Component SHALL handle colorMode state without causing hydration mismatches +3. WHERE colorMode is accessed during SSR, THE Footer Component SHALL use a consistent default value +4. THE Footer Component SHALL update colorMode-dependent content only after hydration is complete +5. THE Footer Component SHALL not generate hydration mismatch warnings in the browser console +6. THE Footer Component SHALL display correctly in both light and dark modes after hydration + +### Requirement 3: Fix ARIA Accessibility Warning in Language Switcher + +**User Story:** As a visitor using assistive technology, I want the language switcher to be properly accessible, so that I can switch languages without accessibility issues. + +#### Acceptance Criteria + +1. THE Language Switcher SHALL not use aria-hidden on focusable or interactive elements +2. WHERE aria-hidden is used, THE Language Switcher SHALL ensure the element is not focusable +3. THE Language Switcher SHALL provide appropriate ARIA labels for screen readers +4. THE Language Switcher SHALL use semantic HTML for language selection +5. THE Language Switcher SHALL be keyboard navigable (Tab, Enter, Space keys) +6. THE Language Switcher SHALL announce language changes to screen readers +7. THE Language Switcher SHALL not generate ARIA-related warnings in the browser console + +### Requirement 4: Improve i18n Route Configuration + +**User Story:** As a developer, I want the i18n routing configuration to be correct, so that all routes work properly with language prefixes. + +#### Acceptance Criteria + +1. THE i18n System SHALL configure route prefixes correctly in nuxt.config.ts +2. THE i18n System SHALL use strategy: 'prefix' or 'prefix_except_default' for consistent URL structure +3. THE i18n System SHALL define all routes with proper locale prefixes +4. THE i18n System SHALL handle dynamic routes (like blog slugs) with locale awareness +5. THE i18n System SHALL provide fallback routes when content is not available in a locale +6. THE i18n System SHALL generate correct sitemap with all localized routes + +### Requirement 5: Ensure Consistent Client-Server Rendering + +**User Story:** As a visitor, I want the page to load without visual flashes or content shifts, so that I have a smooth browsing experience. + +#### Acceptance Criteria + +1. WHEN the page loads, THE Application SHALL render identical content on server and client +2. THE Application SHALL defer client-only content until after hydration using ClientOnly component +3. WHERE dynamic content depends on browser APIs, THE Application SHALL use onMounted lifecycle hook +4. THE Application SHALL not cause layout shifts during hydration +5. THE Application SHALL handle localStorage and cookies consistently between server and client +6. THE Application SHALL not generate Suspense-related warnings during hydration + +### Requirement 6: Fix Language Switcher Implementation + +**User Story:** As a visitor, I want to switch languages smoothly, so that I can view content in my preferred language. + +#### Acceptance Criteria + +1. WHEN a visitor clicks the language switcher, THE Application SHALL navigate to the equivalent page in the target language +2. THE Language Switcher SHALL use switchLocalePath() helper from @nuxtjs/i18n +3. THE Language Switcher SHALL maintain the current route context (e.g., /blog/post-slug becomes /fa/blog/post-slug) +4. WHERE the current page doesn't exist in the target language, THE Language Switcher SHALL navigate to the home page of that locale +5. THE Language Switcher SHALL update the HTML lang attribute +6. THE Language Switcher SHALL update the document direction (ltr/rtl) for Persian +7. THE Language Switcher SHALL provide visual feedback during language switching + +### Requirement 7: Testing and Validation + +**User Story:** As a developer, I want to verify that all i18n and routing issues are resolved, so that I can ensure a quality user experience. + +#### Acceptance Criteria + +1. THE Application SHALL pass manual testing for language switching on all pages +2. THE Application SHALL not generate any hydration warnings in the browser console +3. THE Application SHALL not generate any Vue Router warnings in the browser console +4. THE Application SHALL not generate any ARIA accessibility warnings in the browser console +5. THE Application SHALL maintain proper URL structure with locale prefixes +6. THE Application SHALL handle browser back/forward navigation correctly with localized routes +7. THE Application SHALL work correctly in both development and production builds diff --git a/.kiro/specs/i18n-routing-fixes/tasks.md b/.kiro/specs/i18n-routing-fixes/tasks.md new file mode 100644 index 0000000..d9aa8d2 --- /dev/null +++ b/.kiro/specs/i18n-routing-fixes/tasks.md @@ -0,0 +1,101 @@ +# Implementation Plan + +This implementation plan breaks down the i18n routing and hydration fixes 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. Update i18n configuration to use prefix strategy + + + - Change strategy from 'prefix_except_default' to 'prefix' in nuxt.config.ts + - Update prerender routes to include /en prefix (/en/blog instead of /blog) + - Update route rules to use /en prefix for caching + - Verify configuration by checking generated routes in dev mode + - _Requirements: 1.1, 1.2, 1.3, 4.1, 4.2, 4.3_ + +- [x] 2. Create redirect middleware for root path + + + + - Create middleware/redirect-root.global.ts file + - Implement redirect from / to /en with 301 status code + - Test redirect behavior in browser + - _Requirements: 4.5_ + +- [x] 3. Fix Footer component hydration mismatch + + + - Wrap NuxtImg with colorMode-dependent src in ClientOnly component + - Add fallback template with default logo for SSR + - Remove colorMode.unknown check (no longer needed) + - Test in both light and dark modes + - Verify no hydration warnings in console + - _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 5.1, 5.2_ + + + +- [ ] 4. Fix Language Switcher ARIA and routing issues + - Remove 'sr-only' from :ui config in LanguageSwitcher.vue + - Add proper aria-label using i18n translation key + - Import and use switchLocalePath() composable + - Update watch logic to use switchLocalePath() for route generation + - Navigate to new path using router.push() before setLocale() + - Change item labels from 'en'/'fa' to 'English'/'فارسی' for better UX + - Test language switching on all pages (home, blog listing, blog post) + - Verify no ARIA warnings in console + + + - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7_ + +- [ ] 5. Update TopNav component for new route structure + - Verify all navigation links use localePath() helper + - Update blog link to use localePath('/blog') + + + - Update home navigation to use localePath('/') + - Test navigation from all sections + - _Requirements: 1.3, 4.4_ + +- [ ] 6. Verify blog components use localePath correctly + - Check BlogCard.vue uses localePath for post links + + + - Check BlogNavigation.vue uses localePath for prev/next links + - Check blog/index.vue uses localePath for navigation + - Check blog/[...slug].vue uses localePath for breadcrumbs and back link + + + + - Fix any hardcoded paths to use localePath() + - _Requirements: 1.3, 1.4, 6.3_ + +- [ ] 7. Add i18n translation key for language selector + - Add 'nav.languageSelector' key to i18n/locales/en.json + - Add 'nav.languageSelector' key to i18n/locales/fa.json + - _Requirements: 3.3_ + +- [ ] 8. Test and verify all fixes + - Test root path redirect (/ → /en) + - Test language switching on home page + - Test language switching on blog listing page + - Test language switching on blog post page + - Test browser back/forward navigation + - Verify no hydration warnings in console + - Verify no Vue Router warnings in console + - Verify no ARIA warnings in console + - Test in both light and dark modes + - Test keyboard navigation for language switcher + - _Requirements: 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7_ + +- [ ]* 9. Add fallback handling for missing translations + - In blog/[...slug].vue, add logic to check if post exists in other locale + - Display message when post is only available in other language + - Provide link to switch to the language where post exists + - Test with posts that exist in only one language + - _Requirements: 1.5, 4.5_ + +- [ ]* 10. Update sitemap generation for new route structure + - Update sitemap configuration to include /en prefix + - Verify all routes are included in sitemap + - Test sitemap generation in build + - _Requirements: 4.6_ diff --git a/.kiro/specs/layout-refactoring/design.md b/.kiro/specs/layout-refactoring/design.md new file mode 100644 index 0000000..394e16d --- /dev/null +++ b/.kiro/specs/layout-refactoring/design.md @@ -0,0 +1,226 @@ +# Design Document: Layout Refactoring + +## Overview + +این طراحی یک refactoring ساده ولی مهم برای جابجایی کامپوننت‌های مشترک UI از `app.vue` به `default.vue` layout است. هدف اصلی پیروی از معماری استاندارد Nuxt و جداسازی concerns است. + +### Current Architecture Problems + +1. **Mixing Concerns**: `app.vue` هم global configuration و هم specific UI components دارد +2. **Poor Reusability**: اگر بخواهیم صفحه‌ای بدون TopNav داشته باشیم، امکان‌پذیر نیست +3. **Not Following Nuxt Conventions**: Nuxt layout system برای همین موارد طراحی شده ولی استفاده نمی‌شود + +### Proposed Solution + +جابجایی TopNav و FooterCopyright به `default.vue` layout و تمیز کردن `app.vue` به یک wrapper خالص. + +## Architecture + +### File Structure + +``` +app/ +├── app.vue # Global wrapper (cleaned) +├── layouts/ +│ ├── default.vue # Main layout with TopNav + Footer (updated) +│ └── marketing.vue # Preserved for future use +├── components/ +│ └── common/ +│ ├── TopNav.vue # No changes needed +│ └── FooterCopyright.vue # No changes needed +└── pages/ + ├── index.vue # Uses default layout automatically + └── blog/ + ├── index.vue # Uses default layout automatically + └── [...slug].vue # Uses default layout automatically +``` + +### Component Hierarchy + +**Before:** +``` +UApp (app.vue) +├── NuxtLoadingIndicator +├── TopNav +├── NuxtPage +│ └── Page Content +└── FooterCopyright +``` + +**After:** +``` +UApp (app.vue) +├── NuxtLoadingIndicator +└── NuxtLayout (default) + ├── TopNav + ├── NuxtPage + │ └── Page Content + └── FooterCopyright +``` + +## Components and Interfaces + +### 1. app.vue (Refactored) + +**Purpose**: Global application wrapper با configuration و global components + +**Structure**: +```vue + +``` + +**Responsibilities**: +- Global app configuration (UApp, toaster) +- Loading indicator +- Head management (fonts, meta tags) +- Language and direction attributes +- Layout wrapper + +**What to Remove**: +- TopNav component import and usage +- FooterCopyright component import and usage +- FloatingActions unused import + +### 2. layouts/default.vue (Updated) + +**Purpose**: Main layout برای صفحات اصلی و بلاگ + +**Structure**: +```vue + +``` + +**Responsibilities**: +- Render TopNav +- Provide slot for page content +- Render FooterCopyright +- Maintain proper spacing and structure + +**Styling Considerations**: +- باید مطمئن شویم که spacing بین TopNav و content حفظ می‌شود +- TopNav از قبل `fixed` positioning دارد، پس نیازی به تغییر نیست +- ممکن است نیاز به `padding-top` برای content باشد تا زیر TopNav نرود + +### 3. TopNav.vue (No Changes) + +این کامپوننت تغییری نمی‌کند چون: +- خودش `fixed positioning` دارد +- مستقل از parent خودش کار می‌کند +- هیچ dependency به app.vue ندارد + +### 4. FooterCopyright.vue (No Changes) + +این کامپوننت هم تغییری نمی‌کند. + +## Data Models + +هیچ data model جدیدی نیاز نیست. این یک refactoring ساختاری است. + +## Error Handling + +### Potential Issues + +1. **Layout Not Applied**: اگر Nuxt به درستی default layout را تشخیص ندهد + - **Solution**: اضافه کردن explicit layout declaration در nuxt.config.ts یا pages + +2. **Styling Breaks**: ممکن است spacing یا positioning مشکل پیدا کند + - **Solution**: بررسی دقیق visual regression و اضافه کردن padding/margin در صورت نیاز + +3. **Client-Side Hydration Mismatch**: اگر TopNav در layout و app.vue تفاوت داشته باشد + - **Solution**: حذف کامل TopNav از app.vue قبل از اضافه کردن به layout + +## Migration Strategy + +### Step-by-Step Approach + +1. **Update default.vue layout** + - Import TopNav و FooterCopyright + - Add components to template + - Test visual appearance + +2. **Update app.vue** + - Remove TopNav و FooterCopyright imports + - Remove components from template + - Add NuxtLayout wrapper + - Keep all head management and global config + +3. **Verify pages work correctly** + - Test homepage + - Test blog index + - Test blog post pages + - Check navigation between pages + +4. **Clean up unused code** + - Remove FloatingActions unused import + - Remove isLocaleSwitching unused variable + +## Testing Strategy + +### Manual Testing Checklist + +1. **Visual Regression** + - [ ] Homepage looks identical + - [ ] Blog index looks identical + - [ ] Blog post pages look identical + - [ ] TopNav positioning is correct + - [ ] Footer positioning is correct + +2. **Functionality** + - [ ] TopNav navigation works (hero, skills, work, projects) + - [ ] Blog link works + - [ ] Language switcher works + - [ ] Theme switcher works + - [ ] Responsive behavior works on mobile + +3. **Navigation** + - [ ] Navigate from home to blog + - [ ] Navigate from blog to home + - [ ] Navigate between blog posts + - [ ] TopNav and Footer persist correctly + +4. **Performance** + - [ ] No hydration errors in console + - [ ] No layout shift (CLS) + - [ ] Loading indicator works + +### Browser Testing + +- Chrome/Edge (desktop & mobile) +- Firefox +- Safari (if available) + +## Performance Considerations + +این refactoring نباید تأثیر منفی روی performance داشته باشد: + +- **Bundle Size**: تغییری نمی‌کند (فقط جابجایی کد) +- **Rendering**: ممکن است کمی بهتر شود چون Nuxt layout caching دارد +- **Hydration**: باید مشابه قبل باشد + +## Future Enhancements + +بعد از این refactoring، می‌توانیم: + +1. **Create Blog-Specific Layout**: اگر بخواهیم blog layout متفاوتی داشته باشیم +2. **Create Clean Layout**: برای صفحاتی که نیاز به TopNav ندارند (مثل login, 404) +3. **Add Layout Transitions**: انیمیشن بین layout های مختلف +4. **Conditional Footer**: نمایش footer های متفاوت بر اساس صفحه + +## References + +- [Nuxt Layouts Documentation](https://nuxt.com/docs/guide/directory-structure/layouts) +- [Nuxt app.vue Documentation](https://nuxt.com/docs/guide/directory-structure/app) +- [Vue Slot Documentation](https://vuejs.org/guide/components/slots.html) diff --git a/.kiro/specs/layout-refactoring/requirements.md b/.kiro/specs/layout-refactoring/requirements.md new file mode 100644 index 0000000..15a13a9 --- /dev/null +++ b/.kiro/specs/layout-refactoring/requirements.md @@ -0,0 +1,60 @@ +# Requirements Document + +## Introduction + +این سند الزامات refactoring ساختار layout در پروژه Nuxt را مشخص می‌کند. هدف اصلی جابجایی کامپوننت‌های مشترک (TopNav و Footer) از `app.vue` به layout مناسب است تا از best practices Nuxt پیروی شود و قابلیت نگهداری و توسعه‌پذیری بهبود یابد. + +## Glossary + +- **Layout System**: سیستم مدیریت قالب‌های صفحه در Nuxt که امکان تعریف ساختارهای مشترک برای صفحات مختلف را فراهم می‌کند +- **TopNav**: کامپوننت نوار ناوبری بالای صفحه که در تمام صفحات نمایش داده می‌شود +- **FooterCopyright**: کامپوننت فوتر که اطلاعات کپی‌رایت را نمایش می‌دهد +- **app.vue**: فایل اصلی اپلیکیشن Nuxt که wrapper کلی برنامه است +- **Default Layout**: قالب پیش‌فرض که برای صفحات اصلی و بلاگ استفاده می‌شود + +## Requirements + +### Requirement 1 + +**User Story:** به عنوان توسعه‌دهنده، می‌خواهم ساختار layout پروژه را بر اساس best practices Nuxt سازماندهی کنم تا نگهداری و توسعه آینده آسان‌تر شود + +#### Acceptance Criteria + +1. THE Layout System SHALL move TopNav component from app.vue to default layout +2. THE Layout System SHALL move FooterCopyright component from app.vue to default layout +3. THE app.vue SHALL contain only global wrappers and configuration without specific UI components +4. THE Default Layout SHALL include TopNav, page content slot, and FooterCopyright in correct order +5. WHEN a page uses default layout, THE Layout System SHALL render TopNav and Footer automatically + +### Requirement 2 + +**User Story:** به عنوان توسعه‌دهنده، می‌خواهم صفحات موجود به صورت خودکار از layout جدید استفاده کنند بدون اینکه نیاز به تغییرات دستی در هر صفحه باشد + +#### Acceptance Criteria + +1. THE Layout System SHALL set default layout as the fallback layout for all pages +2. THE Layout System SHALL ensure homepage uses default layout without explicit declaration +3. THE Layout System SHALL ensure blog pages use default layout without explicit declaration +4. WHEN no layout is specified in a page, THE Layout System SHALL apply default layout automatically + +### Requirement 3 + +**User Story:** به عنوان توسعه‌دهنده، می‌خواهم layout های موجود (marketing) را حفظ کنم برای استفاده‌های آینده + +#### Acceptance Criteria + +1. THE Layout System SHALL preserve existing marketing layout without modifications +2. THE Layout System SHALL keep marketing layout available for future use +3. THE Layout System SHALL not break any existing layout functionality + +### Requirement 4 + +**User Story:** به عنوان کاربر، می‌خواهم تجربه کاربری من بعد از refactoring دقیقاً مانند قبل باشد + +#### Acceptance Criteria + +1. THE Layout System SHALL maintain identical visual appearance after refactoring +2. THE Layout System SHALL preserve all navigation functionality +3. THE Layout System SHALL maintain all responsive behaviors +4. THE Layout System SHALL keep all animations and transitions working +5. WHEN user navigates between pages, THE Layout System SHALL display TopNav and Footer consistently diff --git a/.kiro/specs/layout-refactoring/tasks.md b/.kiro/specs/layout-refactoring/tasks.md new file mode 100644 index 0000000..a485adf --- /dev/null +++ b/.kiro/specs/layout-refactoring/tasks.md @@ -0,0 +1,40 @@ +# Implementation Plan + +- [x] 1. Update default.vue layout with TopNav and Footer + + + - Import TopNav and FooterCopyright components + - Add TopNav before the slot + - Add FooterCopyright after the slot + - Add appropriate wrapper div with proper spacing + - _Requirements: 1.1, 1.4_ + + + +- [x] 2. Refactor app.vue to use layout system + + + - Remove TopNav component import and usage + - Remove FooterCopyright component import and usage + - Remove unused FloatingActions import + - Remove unused isLocaleSwitching variable + - Wrap NuxtPage with NuxtLayout component + - Keep all head management and global configuration + + + + - _Requirements: 1.1, 1.2, 1.3_ + + +- [x] 3. Verify visual appearance and functionality + + + - Check homepage renders correctly with TopNav and Footer + - Check blog index page renders correctly + - Check blog post pages render correctly + - Verify TopNav navigation works (hero, skills, work, projects, blog) + - Verify language switcher functionality + - Verify theme switcher functionality + - Check responsive behavior on different screen sizes + - Verify no console errors or hydration warnings + - _Requirements: 2.1, 2.2, 2.3, 4.1, 4.2, 4.3, 4.4, 4.5_ diff --git a/.kiro/specs/page-transitions-ux/design.md b/.kiro/specs/page-transitions-ux/design.md new file mode 100644 index 0000000..71973a3 --- /dev/null +++ b/.kiro/specs/page-transitions-ux/design.md @@ -0,0 +1,410 @@ +# Design Document: Page Transitions & UX Enhancement + +## Overview + +This design implements smooth page transitions, loading states, and component animations using Nuxt 4 best practices. The solution leverages Nuxt's built-in transition system, Vue's Transition component, and modern CSS animations to create a polished user experience while maintaining performance and accessibility. + +## Architecture + +### Transition Layers + +The implementation consists of three distinct layers: + +1. **Page-Level Transitions**: Global transitions applied to all route changes via `app.vue` +2. **Layout Transitions**: Smooth transitions when switching between layouts +3. **Component-Level Animations**: Micro-interactions for individual components + +### Technology Stack + +- **Nuxt 4 Page Transitions**: Built-in `` transition prop with enhanced performance +- **Vue 3 Transition Component**: For component-level animations +- **CSS Transforms & Opacity**: Hardware-accelerated animations +- **View Transitions API**: Native browser API for smooth page transitions (Chrome 111+) +- **NuxtLoadingIndicator**: Already implemented, will be enhanced +- **Tailwind CSS 4**: Utility classes for transition effects + +## Components and Interfaces + +### 1. Global Page Transitions + +**Location**: `app/app.vue` + +**Implementation Strategy**: +- Add `pageTransition` prop to `` component +- Define CSS transition classes in global styles +- Use fade + slight vertical movement for elegance +- Duration: 250-300ms for optimal perceived performance + +**Transition Modes**: +- `out-in`: Wait for old page to leave before entering new page (prevents overlap) +- Prevents layout shift during navigation + +### 2. Layout Transitions + +**Location**: `app/layouts/default.vue` + +**Implementation Strategy**: +- Add `layoutTransition` configuration in `nuxt.config.ts` +- Apply crossfade effect for layout changes +- Maintain scroll position where appropriate + +### 3. Loading States Enhancement + +**Current State**: `NuxtLoadingIndicator` already exists in `app.vue` + +**Enhancements**: +- Add custom loading spinner for long operations +- Implement skeleton screens for blog post loading +- Add loading state to blog card components during navigation + +### 4. Component Animations + +**Target Components**: + +a) **BlogCard** (`app/components/blog/BlogCard.vue`) +- Hover state: Subtle lift effect with shadow +- Entry animation: Staggered fade-in when list renders + +b) **BlogNavigation** (`app/components/blog/BlogNavigation.vue`) +- Smooth hover states on prev/next buttons +- Icon animations on hover + +c) **LanguageSwitcher** (`app/components/LanguageSwitcher.vue`) +- Dropdown animation with scale + fade +- Smooth active state transitions + +d) **TopNav** (`app/components/common/TopNav.vue`) +- Smooth scroll-based appearance/disappearance +- Mobile menu slide-in animation + +### 5. View Transitions API Integration (Native Browser API) + +**Progressive Enhancement**: +- Use native View Transitions API for supported browsers (Chrome 111+, Edge 111+) +- Provides smooth, native transitions between pages +- Automatic fallback to CSS transitions for unsupported browsers + +**Implementation via Nuxt 4**: +Nuxt 4 has built-in support for View Transitions API through the `experimental.viewTransition` flag: + +```typescript +// nuxt.config.ts +export default defineNuxtConfig({ + experimental: { + viewTransition: true + } +}) +``` + +This enables automatic View Transitions for: +- Page navigation +- Route changes +- Dynamic content updates + +**Manual Control** (when needed): +```typescript +// Composable: useViewTransition +const router = useRouter() + +const navigateWithTransition = async (to: string) => { + if (document.startViewTransition) { + await document.startViewTransition(async () => { + await router.push(to) + }).finished + } else { + await router.push(to) + } +} +``` + +## Data Models + +### Transition Configuration + +```typescript +// types/transitions.ts +export interface TransitionConfig { + name: string + mode: 'in-out' | 'out-in' | 'default' + duration: number + appear?: boolean +} + +export interface AnimationPreferences { + reducedMotion: boolean + enableViewTransitions: boolean +} +``` + +### CSS Custom Properties + +```css +:root { + --transition-duration-fast: 150ms; + --transition-duration-base: 250ms; + --transition-duration-slow: 350ms; + --transition-timing: cubic-bezier(0.4, 0, 0.2, 1); + --transition-timing-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55); +} +``` + +## Implementation Details + +### 1. Page Transition Classes + +**CSS Structure**: +```css +/* Enter transitions */ +.page-enter-active, +.page-leave-active { + transition: all var(--transition-duration-base) var(--transition-timing); +} + +.page-enter-from { + opacity: 0; + transform: translateY(10px); +} + +.page-leave-to { + opacity: 0; + transform: translateY(-10px); +} +``` + +### 2. Reduced Motion Support + +**Media Query**: +```css +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} +``` + +### 3. Staggered List Animations + +**For Blog Cards**: +```css +.blog-card { + animation: fadeInUp var(--transition-duration-base) var(--transition-timing) backwards; +} + +.blog-card:nth-child(1) { animation-delay: 0ms; } +.blog-card:nth-child(2) { animation-delay: 50ms; } +.blog-card:nth-child(3) { animation-delay: 100ms; } +/* ... */ + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} +``` + +### 4. Language Switch Transition + +**Special Handling**: +- Preserve scroll position using `scrollBehavior` in router +- Apply crossfade to prevent jarring content swap +- Maintain route structure during language change + +```typescript +// Composable enhancement +const switchLanguageWithTransition = async (newLocale: string) => { + const scrollY = window.scrollY + + await switchLocalePath(newLocale) + + // Restore scroll after transition + nextTick(() => { + window.scrollTo(0, scrollY) + }) +} +``` + +## Error Handling + +### Transition Failures + +1. **CSS Not Loaded**: Fallback to instant transitions +2. **JavaScript Errors**: Graceful degradation to no transitions +3. **Performance Issues**: Detect slow devices and reduce animation complexity + +### Browser Compatibility + +- **Modern Browsers**: Full transition support with View Transition API +- **Older Browsers**: CSS-only transitions +- **No JavaScript**: Basic CSS transitions still work + +## Testing Strategy + +### Visual Testing + +1. **Manual Testing**: + - Navigate between all major routes + - Test language switching + - Verify mobile menu animations + - Check hover states on all interactive elements + +2. **Browser Testing**: + - Chrome/Edge (View Transition API support) + - Firefox (CSS transitions only) + - Safari (CSS transitions only) + - Mobile browsers (iOS Safari, Chrome Mobile) + +### Performance Testing + +1. **Metrics to Monitor**: + - First Contentful Paint (FCP) + - Largest Contentful Paint (LCP) + - Cumulative Layout Shift (CLS) + - Time to Interactive (TTI) + +2. **Animation Performance**: + - Use Chrome DevTools Performance tab + - Ensure 60fps during transitions + - Monitor paint and composite operations + +### Accessibility Testing + +1. **Reduced Motion**: + - Test with `prefers-reduced-motion: reduce` + - Verify animations are disabled or minimal + +2. **Keyboard Navigation**: + - Ensure focus states are visible during transitions + - Test tab order during animations + +3. **Screen Readers**: + - Verify ARIA live regions announce page changes + - Test with NVDA/JAWS/VoiceOver + +## Configuration Changes + +### nuxt.config.ts + +```typescript +export default defineNuxtConfig({ + // Enable View Transitions API (Nuxt 4 feature) + experimental: { + viewTransition: true + }, + + app: { + pageTransition: { + name: 'page', + mode: 'out-in' + }, + layoutTransition: { + name: 'layout', + mode: 'out-in' + } + }, + + // Existing config... +}) +``` + +**Note**: The `experimental.viewTransition` flag in Nuxt 4 automatically: +- Adds `` to the head +- Enables View Transitions API for navigation +- Provides fallback for unsupported browsers + +### CSS Organization + +**New File**: `app/assets/css/transitions.css` +- Contains all transition and animation definitions +- Imported in `app/assets/css/main.css` + +## Performance Considerations + +### Optimization Strategies + +1. **Use CSS Transforms**: Hardware-accelerated (GPU) +2. **Avoid Layout Thrashing**: Only animate `transform` and `opacity` +3. **Will-Change Property**: Apply sparingly to animated elements +4. **Reduce Animation Complexity**: Simpler animations on mobile devices + +### Bundle Size Impact + +- **CSS**: ~2-3KB additional (minified + gzipped) +- **JavaScript**: ~1KB for View Transition API detection +- **Total Impact**: Minimal (<5KB) + +## Migration Path + +### Phase 1: Core Page Transitions +- Implement global page transitions +- Add transition CSS classes +- Test across routes + +### Phase 2: Component Animations +- Add hover states to interactive elements +- Implement staggered list animations +- Enhance loading states + +### Phase 3: Advanced Features +- Integrate View Transition API +- Add custom transitions for specific routes +- Optimize performance + +## Design Decisions & Rationale + +### Why `out-in` Mode? +- Prevents content overlap during transitions +- Cleaner visual experience +- Slightly slower but more polished + +### Why 250-300ms Duration? +- Research shows this is the sweet spot for perceived performance +- Fast enough to feel responsive +- Slow enough to be noticeable and polished + +### Why CSS Over JavaScript? +- Better performance (GPU acceleration) +- Simpler to maintain +- Works without JavaScript +- Respects `prefers-reduced-motion` automatically + +### Why View Transition API? +- Native browser support for smooth transitions +- Better performance than CSS alone +- Progressive enhancement approach +- Future-proof solution + +## Nuxt 4 Specific Features + +### Built-in View Transitions Support + +Nuxt 4 provides first-class support for the View Transitions API: + +1. **Automatic Setup**: Just enable `experimental.viewTransition` +2. **SSR Compatible**: Works with server-side rendering +3. **Progressive Enhancement**: Automatic fallback for older browsers +4. **Zero Configuration**: No additional setup needed for basic transitions + +### Performance Improvements in Nuxt 4 + +- **Faster Hydration**: Improved client-side hydration performance +- **Better Code Splitting**: Automatic optimization for route-based code splitting +- **Enhanced Prefetching**: Smarter link prefetching for faster navigation + +## References + +- [Nuxt 4 Documentation](https://nuxt.com/docs) +- [Nuxt 4 View Transitions](https://nuxt.com/docs/getting-started/transitions#view-transitions-api-experimental) +- [Vue 3 Transition Component](https://vuejs.org/guide/built-ins/transition.html) +- [View Transitions API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API) +- [Chrome View Transitions Guide](https://developer.chrome.com/docs/web-platform/view-transitions/) +- [Web Animations Performance](https://web.dev/articles/animations-guide) +- [Reduced Motion Media Query](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) diff --git a/.kiro/specs/page-transitions-ux/requirements.md b/.kiro/specs/page-transitions-ux/requirements.md new file mode 100644 index 0000000..c0c2a60 --- /dev/null +++ b/.kiro/specs/page-transitions-ux/requirements.md @@ -0,0 +1,72 @@ +# Requirements Document + +## Introduction + +This feature aims to enhance the user experience of the Nuxt application by implementing smooth page transitions, component animations, and loading states following Nuxt best practices. The current implementation lacks visual feedback during navigation and state changes, resulting in an abrupt and less engaging user experience. + +## Glossary + +- **Application**: The Nuxt-based web application +- **Page Transition**: Visual animation that occurs when navigating between routes +- **Layout Transition**: Visual animation when switching between different layouts +- **Loading State**: Visual feedback shown during asynchronous operations +- **View Transition API**: Browser native API for smooth transitions between DOM states +- **Nuxt Transition**: Built-in Nuxt feature for handling page and layout transitions + +## Requirements + +### Requirement 1 + +**User Story:** As a user, I want to see smooth transitions when navigating between pages, so that the experience feels polished and professional + +#### Acceptance Criteria + +1. WHEN a user navigates to a different route, THE Application SHALL display a fade transition with appropriate timing +2. WHEN a page transition occurs, THE Application SHALL prevent layout shift during the animation +3. WHEN navigating between blog posts, THE Application SHALL apply consistent transition effects +4. THE Application SHALL complete page transitions within 300 milliseconds to maintain responsiveness + +### Requirement 2 + +**User Story:** As a user, I want to see visual feedback during content loading, so that I know the application is responding to my actions + +#### Acceptance Criteria + +1. WHEN content is being fetched asynchronously, THE Application SHALL display a loading indicator +2. WHEN navigation occurs, THE Application SHALL show a progress bar at the top of the viewport +3. IF a page load exceeds 500 milliseconds, THEN THE Application SHALL display the loading indicator +4. WHEN loading completes, THE Application SHALL smoothly fade out the loading indicator + +### Requirement 3 + +**User Story:** As a user, I want smooth animations when components appear or disappear, so that the interface feels responsive and intentional + +#### Acceptance Criteria + +1. WHEN a modal or overlay opens, THE Application SHALL animate its entrance with fade and scale effects +2. WHEN list items are rendered, THE Application SHALL stagger their appearance for visual interest +3. WHEN interactive elements receive focus or hover, THE Application SHALL provide smooth visual feedback +4. THE Application SHALL use CSS transforms for animations to ensure hardware acceleration + +### Requirement 4 + +**User Story:** As a user, I want the language switcher to transition smoothly, so that changing languages feels seamless + +#### Acceptance Criteria + +1. WHEN the user switches language, THE Application SHALL maintain scroll position during the transition +2. WHEN language changes, THE Application SHALL apply a crossfade transition to content +3. THE Application SHALL preserve the current route path when switching languages +4. WHEN language transition occurs, THE Application SHALL complete within 400 milliseconds + +### Requirement 5 + +**User Story:** As a developer, I want to use Nuxt best practices for transitions, so that the implementation is maintainable and performant + +#### Acceptance Criteria + +1. THE Application SHALL use Nuxt's built-in transition system for page transitions +2. THE Application SHALL leverage Vue's Transition component for component-level animations +3. THE Application SHALL use CSS-based animations rather than JavaScript animations where possible +4. THE Application SHALL implement transitions that respect user's reduced motion preferences +5. WHERE the browser supports View Transition API, THE Application SHALL utilize it for enhanced transitions diff --git a/.kiro/specs/page-transitions-ux/tasks.md b/.kiro/specs/page-transitions-ux/tasks.md new file mode 100644 index 0000000..1c6127e --- /dev/null +++ b/.kiro/specs/page-transitions-ux/tasks.md @@ -0,0 +1,97 @@ +# Implementation Plan + +- [x] 1. Enable Nuxt 4 View Transitions and configure global page transitions + + + - Enable `experimental.viewTransition` flag in `nuxt.config.ts` + - Configure `pageTransition` and `layoutTransition` settings + - Add View Transitions API polyfill detection + - _Requirements: 1.1, 1.2, 1.3, 1.4, 5.5_ + + + +- [ ] 2. Create global transition CSS styles + - Create `app/assets/css/transitions.css` file + - Define CSS custom properties for transition timing and durations + - Implement page transition classes (`.page-enter-active`, `.page-leave-active`, etc.) + - Add layout transition classes + - Implement `prefers-reduced-motion` media query support + + - Import transitions.css in `app/assets/css/main.css` + - _Requirements: 1.1, 1.2, 1.4, 5.3, 5.4_ + +- [x] 3. Enhance NuxtLoadingIndicator and add loading states + + - Review current `NuxtLoadingIndicator` configuration in `app.vue` + - Add custom loading spinner component for long operations + - Create skeleton loader component for blog posts + - Add loading state transitions with fade effects + - _Requirements: 2.1, 2.2, 2.3, 2.4_ + +- [x] 4. Add component-level animations to BlogCard + + + - Add hover state with lift effect and shadow to `app/components/blog/BlogCard.vue` + - Implement staggered fade-in animation for blog card list + - Use CSS transforms for hardware acceleration + - Add transition classes using Tailwind CSS 4 utilities + - _Requirements: 3.1, 3.2, 3.3, 3.4_ + + + +- [ ] 5. Enhance BlogNavigation with smooth animations + - Add smooth hover states to prev/next buttons in `app/components/blog/BlogNavigation.vue` + - Implement icon animations on hover + - Add transition effects for button states + + + - _Requirements: 3.1, 3.3_ + +- [ ] 6. Improve LanguageSwitcher transitions + - Add dropdown animation with scale and fade to `app/components/LanguageSwitcher.vue` + - Implement smooth active state transitions + + + - Preserve scroll position during language switch + - Add crossfade transition for content + - _Requirements: 4.1, 4.2, 4.3, 4.4_ + + + +- [ ] 7. Add TopNav scroll-based animations + - Implement smooth scroll-based appearance/disappearance in `app/components/common/TopNav.vue` + - Add mobile menu slide-in animation + - Use CSS transforms for smooth transitions + - _Requirements: 3.1, 3.3, 3.4_ + + + + +- [ ] 8. Create View Transitions API composable + - Create `app/composables/useViewTransition.ts` + - Implement browser support detection + - Add manual transition control function + - Provide fallback for unsupported browsers + - _Requirements: 5.1, 5.2, 5.5_ + +- [ ] 9. Add View Transitions API custom animations + - Define custom view transition names for specific elements + - Add CSS for view transition animations + - Implement cross-fade effects for content areas + - Add slide animations for navigation elements + - _Requirements: 5.5_ + +- [ ]* 10. Test transitions across browsers and devices + - Test on Chrome/Edge (with View Transitions API) + - Test on Firefox and Safari (CSS fallback) + - Test on mobile browsers (iOS Safari, Chrome Mobile) + - Verify reduced motion preferences are respected + - Test keyboard navigation during transitions + - _Requirements: 5.4_ + +- [ ]* 11. Performance testing and optimization + - Measure FCP, LCP, CLS, and TTI metrics + - Use Chrome DevTools Performance tab to verify 60fps + - Monitor paint and composite operations + - Optimize animation complexity for mobile devices + - _Requirements: 3.4, 5.3_ diff --git a/README.md b/README.md index 579740d..551bf20 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,21 @@ i18n/ # Internationalization ## 🚀 Deployment +### Static Site Generation (SSG) + +This project is configured for full Static Site Generation with automatic blog post pre-rendering: + +```bash +# Generate static files with pre-rendered blog posts +pnpm generate +``` + +The build process will: +- Pre-render all blog posts (English & Persian) +- Generate sitemap.xml automatically +- Create RSS feeds for both languages +- Output static files to `.output/public` + ### Vercel (Recommended) ```bash # Install Vercel CLI @@ -106,16 +121,20 @@ vercel Or connect your GitHub repository to Vercel for automatic deployments. -### Static Hosting -```bash -# Generate static files -pnpm generate +### Other Static Hosting Platforms -# Deploy .output/public to any static host -``` +Compatible with any static hosting service: +- **Netlify**: Deploy `.output/public` directory +- **Cloudflare Pages**: Connect GitHub repo or upload `.output/public` +- **GitHub Pages**: Deploy `.output/public` contents +- **AWS S3 + CloudFront**: Upload `.output/public` to S3 bucket + +**Build Command**: `pnpm generate` +**Output Directory**: `.output/public` ### Environment Variables - `NUXT_PUBLIC_LOAD_PLAUSIBLE` - Enable/disable Plausible analytics (optional) +- `NUXT_PUBLIC_SITE_URL` - Site URL for sitemap and RSS (default: https://aliarghyani.vercel.app) ## 🧪 Testing the Structure diff --git a/SSG-TEST-GUIDE.md b/SSG-TEST-GUIDE.md new file mode 100644 index 0000000..5b94b8f --- /dev/null +++ b/SSG-TEST-GUIDE.md @@ -0,0 +1,149 @@ +# راهنمای تست SSG (Static Site Generation) + +## چطور بفهمیم SSG درست کار می‌کنه؟ + +### 1. بررسی فایل‌های تولید شده + +اول بررسی کن که فایل‌های HTML واقعاً تولید شدن: + +```bash +# بررسی ساختار فایل‌ها +ls .output/public/blog +ls .output/public/fa/blog + +# باید این فایل‌ها رو ببینی: +# - index.html (صفحه لیست بلاگ) +# - getting-started-with-nuxt-content/index.html +# - nuxt-ui-components/index.html +# - typescript-best-practices/index.html +``` + +### 2. اجرای Preview Server + +```bash +pnpm preview +``` + +این command یک static file server ساده راه‌اندازی می‌کنه که فقط فایل‌های HTML رو serve می‌کنه (بدون Node.js server). + +### 3. تست‌های اصلی برای تأیید SSG + +#### ✅ تست 1: بررسی HTML Source + +1. مرورگر رو باز کن و برو به: `http://localhost:3000/blog` +2. کلیک راست کن و "View Page Source" یا `Ctrl+U` بزن +3. **چیزی که باید ببینی:** + - تمام محتوای HTML از قبل موجود هست (نه فقط `
`) + - تگ‌های `` برای SEO + - محتوای کامل پست‌های بلاگ در HTML + - **اگه فقط یک div خالی دیدی = SSG کار نکرده ❌** + - **اگه محتوای کامل دیدی = SSG موفق ✅** + +#### ✅ تست 2: بررسی Network با اینترنت قطع + +1. مرورگر رو باز کن +2. DevTools رو باز کن (`F12`) +3. به تب Network برو +4. صفحه رو Refresh کن +5. **چیزی که باید ببینی:** + - فقط یک request برای `index.html` (نه API call برای fetch کردن پست‌ها) + - فایل HTML حجم زیادی داره (چون محتوا توش هست) + - **اگه API call دیدی = SSR یا CSR هست، نه SSG ❌** + - **اگه فقط HTML دیدی = SSG موفق ✅** + +#### ✅ تست 3: Disable JavaScript + +1. DevTools رو باز کن (`F12`) +2. `Ctrl+Shift+P` بزن (Command Palette) +3. تایپ کن: "Disable JavaScript" +4. صفحه رو Refresh کن +5. **چیزی که باید ببینی:** + - محتوای بلاگ همچنان نمایش داده میشه + - فقط interactive features کار نمی‌کنن (مثل navigation) + - **اگه صفحه خالی شد = SSG نیست ❌** + - **اگه محتوا نمایش داده شد = SSG موفق ✅** + +#### ✅ تست 4: بررسی سرعت بارگذاری + +1. DevTools > Network > Throttling رو روی "Fast 3G" بذار +2. صفحه رو Refresh کن +3. **چیزی که باید ببینی:** + - محتوا خیلی سریع نمایش داده میشه (حتی با اینترنت کند) + - Time to First Contentful Paint (FCP) کمتر از 1 ثانیه + - **SSG = محتوا فوری نمایش داده میشه ✅** + - **SSR/CSR = باید منتظر بمونی تا محتوا load بشه ❌** + +#### ✅ تست 5: بررسی Sitemap + +```bash +# بررسی sitemap +curl http://localhost:3000/sitemap_index.xml +# یا در مرورگر: +# http://localhost:3000/sitemap_index.xml +``` + +باید لیست تمام URLهای بلاگ رو ببینی. + +### 4. مقایسه SSG با SSR/CSR + +| ویژگی | SSG (Static) | SSR (Server) | CSR (Client) | +|-------|-------------|--------------|--------------| +| HTML در source | ✅ کامل | ✅ کامل | ❌ خالی | +| نیاز به Node.js | ❌ نه | ✅ بله | ❌ نه | +| API Calls | ❌ نه | ✅ بله | ✅ بله | +| سرعت | ⚡ خیلی سریع | 🚀 سریع | 🐌 کند | +| SEO | ✅ عالی | ✅ عالی | ⚠️ ضعیف | +| هزینه Hosting | 💰 ارزان | 💰💰 گران | 💰 ارزان | + +### 5. تست با curl (بدون مرورگر) + +```bash +# دریافت HTML خام +curl http://localhost:3000/blog/getting-started-with-nuxt-content + +# اگه محتوای کامل HTML رو دیدی = SSG موفق ✅ +# اگه فقط یک div خالی دیدی = SSG کار نکرده ❌ +``` + +### 6. بررسی فایل HTML مستقیماً + +```bash +# باز کردن فایل HTML در مرورگر +start .output/public/blog/getting-started-with-nuxt-content/index.html + +# یا در VSCode: +code .output/public/blog/getting-started-with-nuxt-content/index.html +``` + +باید تمام محتوای پست رو در HTML ببینی. + +## 🎯 نتیجه‌گیری + +**SSG موفق است اگر:** +- ✅ فایل‌های HTML با محتوای کامل تولید شدن +- ✅ View Source محتوای کامل رو نشون میده +- ✅ بدون JavaScript هم محتوا نمایش داده میشه +- ✅ هیچ API call برای fetch کردن محتوا نیست +- ✅ سرعت بارگذاری خیلی سریعه +- ✅ Sitemap تولید شده + +**SSG کار نکرده اگر:** +- ❌ View Source فقط یک div خالی نشون میده +- ❌ API call برای fetch کردن پست‌ها وجود داره +- ❌ بدون JavaScript صفحه خالی میشه +- ❌ محتوا با تأخیر load میشه + +## 🚀 Deploy + +وقتی مطمئن شدی SSG درست کار می‌کنه، می‌تونی deploy کنی: + +```bash +# فولدر .output/public رو به هر static hosting آپلود کن: +# - Vercel +# - Netlify +# - Cloudflare Pages +# - GitHub Pages +# - AWS S3 + CloudFront +``` + +هیچ Node.js server لازم نیست! فقط فایل‌های استاتیک. diff --git a/app/app.vue b/app/app.vue index c6a546a..2338e95 100644 --- a/app/app.vue +++ b/app/app.vue @@ -1,23 +1,17 @@ diff --git a/app/components/blog/BlogCard.vue b/app/components/blog/BlogCard.vue index fb38c50..e194104 100644 --- a/app/components/blog/BlogCard.vue +++ b/app/components/blog/BlogCard.vue @@ -59,7 +59,7 @@ const handleImageError = () => { // Convert collection path to route path (remove locale prefix) const getRoutePath = (path: string) => { - // Remove locale prefix from path: /en/blog/... -> /blog/... - return path.replace(`/${locale.value}`, '') + // Remove any locale prefix from path: /en/blog/... or /fa/blog/... -> /blog/... + return path.replace(/^\/(en|fa)/, '') } diff --git a/app/components/blog/BlogNavigation.vue b/app/components/blog/BlogNavigation.vue index 6a48bdc..bb4b288 100644 --- a/app/components/blog/BlogNavigation.vue +++ b/app/components/blog/BlogNavigation.vue @@ -12,8 +12,8 @@ const router = useRouter() // Convert collection path to route path (remove locale prefix) const getRoutePath = (path: string) => { - // Remove locale prefix from path: /en/blog/... -> /blog/... - return path.replace(`/${locale.value}`, '') + // Remove any locale prefix from path: /en/blog/... or /fa/blog/... -> /blog/... + return path.replace(/^\/(en|fa)/, '') } // Keyboard navigation @@ -39,9 +39,11 @@ onUnmounted(() => {
- +
@@ -59,7 +61,8 @@ onUnmounted(() => {
- +
{{ t('blog.nextPost') }} @@ -70,7 +73,8 @@ onUnmounted(() => {
diff --git a/app/components/common/FooterCopyright.vue b/app/components/common/FooterCopyright.vue index bcf63e3..ca8d326 100644 --- a/app/components/common/FooterCopyright.vue +++ b/app/components/common/FooterCopyright.vue @@ -2,8 +2,14 @@