[
  {
    "path": ".all-contributorsrc",
    "content": "{\n  \"files\": [\"README.md\"],\n  \"imageSize\": 100,\n  \"commit\": false,\n  \"contributors\": [\n    {\n      \"login\": \"sarbikbetal\",\n      \"name\": \"Sarbik Betal\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/41508422?v=4\",\n      \"profile\": \"https://github.com/sarbikbetal\",\n      \"contributions\": [\"code\"]\n    },\n    {\n      \"login\": \"Hardik0307\",\n      \"name\": \"Hardik Bagada\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/41434099?v=4\",\n      \"profile\": \"https://github.com/Hardik0307\",\n      \"contributions\": [\"code\"]\n    },\n    {\n      \"login\": \"antonkomarev\",\n      \"name\": \"Anton Komarev\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/1849174?v=4\",\n      \"profile\": \"https://komarev.com\",\n      \"contributions\": [\"plugin\"]\n    },\n    {\n      \"login\": \"KKVANONYMOUS\",\n      \"name\": \"Kunal Kumar Verma\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/58628586?v=4\",\n      \"profile\": \"https://kkvanonymous.github.io/\",\n      \"contributions\": [\"code\"]\n    },\n    {\n      \"login\": \"jaideepghosh\",\n      \"name\": \"Jaideep Ghosh\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/3909648?v=4\",\n      \"profile\": \"http://jaideepghosh.blogspot.com\",\n      \"contributions\": [\"code\"]\n    },\n    {\n      \"login\": \"YashKandalkar\",\n      \"name\": \"yash\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/35102959?v=4\",\n      \"profile\": \"http://yashkandalkar.github.io\",\n      \"contributions\": [\"code\"]\n    },\n    {\n      \"login\": \"abhijit-hota\",\n      \"name\": \"Abhijit Hota\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/8116174?v=4\",\n      \"profile\": \"https://github.com/abhijit-hota\",\n      \"contributions\": [\"code\", \"test\"]\n    },\n    {\n      \"login\": \"Maddoxx88\",\n      \"name\": \"Sunit Shirke\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/34238672?v=4\",\n      \"profile\": \"https://maddoxx88.github.io/\",\n      \"contributions\": [\"code\"]\n    },\n    {\n      \"login\": \"g-savitha\",\n      \"name\": \"Savitha Gollamudi\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/31612459?v=4\",\n      \"profile\": \"https://www.gsavitha.in\",\n      \"contributions\": [\"code\"]\n    }\n  ],\n  \"contributorsPerLine\": 7,\n  \"projectName\": \"github-profile-readme-generator\",\n  \"projectOwner\": \"rahuldkjain\",\n  \"repoType\": \"github\",\n  \"repoHost\": \"https://github.com\",\n  \"skipCi\": true\n}\n"
  },
  {
    "path": ".eslintignore",
    "content": "node_modules/**"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"env\": {\n    \"browser\": true,\n    \"es2021\": true\n  },\n  \"extends\": [\"plugin:react/recommended\", \"airbnb\", \"prettier\"],\n  \"parserOptions\": {\n    \"ecmaFeatures\": {\n      \"jsx\": true\n    },\n    \"ecmaVersion\": 12,\n    \"sourceType\": \"module\"\n  },\n  \"plugins\": [\"react\"],\n  \"rules\": {\n    \"react/forbid-prop-types\": 0\n  },\n  \"ignorePatterns\": [\"**/*.test.js\"]\n}\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: rahuldkjain\npatreon: # Replace with a single Patreon username\nopen_collective: github-profile-readme-generator\nko_fi: rahuldkjain\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: ['https://paypal.me/rahuldkjain', 'https://www.buymeacoffee.com/rahuldkjain']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: 🐛 Bug Report\nabout: Report a bug in GitHub Profile README Generator\ntitle: '[Bug] '\nlabels: ['bug']\nassignees: ''\n---\n\n## 🐛 Bug Description\n\nA clear and concise description of what the bug is.\n\n## 🔄 Steps to Reproduce\n\n1. Go to [URL or page]\n2. Click on [element]\n3. Fill in [specific fields]\n4. See error\n\n## ✅ Expected Behavior\n\nA clear description of what you expected to happen.\n\n## 📸 Screenshots\n\nIf applicable, add screenshots to help explain your problem.\n\n## 🖥️ Environment\n\n**Desktop:**\n\n- OS: [e.g. macOS, Windows, Linux]\n- Browser: [e.g. Chrome 118, Safari 17, Firefox 119]\n\n**Mobile:**\n\n- Device: [e.g. iPhone 15, Samsung Galaxy S23]\n- OS: [e.g. iOS 17.1, Android 14]\n- Browser: [e.g. Safari, Chrome Mobile]\n\n## 🔧 Additional Context\n\n- Does this happen in incognito/private mode? [Yes/No]\n- Console errors (if any): [Paste console output]\n- Network connectivity: [Good/Slow/Offline]\n\n**Note:** Please test at the current version: https://rahuldkjain.github.io/gh-profile-readme-generator\n\nJoin the **Discord Server** for further discussions.\n\n<a href=\"https://discord.gg/HHMs7Eg\">\n<img src=\"https://discord.com/assets/e4923594e694a21542a489471ecffa50.svg\" alt=\"GPRG Discord Server Link\" width=\"300px\"/>\n</a>\n\nServer Link: https://discord.gg/HHMs7Eg\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-enhancement-request.md",
    "content": "---\nname: Feature/Enhancement request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement, hacktoberfest\nassignees: ''\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n\nJoin the **Discord Server** for further discussions.\n\n<a href=\"https://discord.gg/HHMs7Eg\">\n<img src=\"https://discord.com/assets/e4923594e694a21542a489471ecffa50.svg\" alt=\"GPRG Discord Server Link\" width=\"300px\"/>\n</a>\n\nServer Link: https://discord.gg/HHMs7Eg\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: ✨ Feature Request\nabout: Suggest a new feature for GitHub Profile README Generator\ntitle: '[Feature] '\nlabels: ['enhancement']\nassignees: ''\n---\n\n## ✨ Feature Description\n\nA clear and concise description of the feature you'd like to see.\n\n## 🎯 Problem Statement\n\nWhat problem does this feature solve? Is your feature request related to a problem?\n\n## 💡 Proposed Solution\n\nDescribe the solution you'd like to see implemented.\n\n## 🔄 User Flow\n\nDescribe how a user would interact with this feature:\n\n1. User goes to...\n2. User clicks/types...\n3. System responds with...\n\n## 🎨 Design Considerations\n\n- UI/UX requirements\n- Accessibility considerations\n- Mobile responsiveness needs\n- Theme compatibility (dark/light mode)\n\n## 🔧 Technical Considerations\n\n- Performance impact\n- Browser compatibility requirements\n- Dependencies needed\n- Potential breaking changes\n\n## 📋 Alternative Solutions\n\nDescribe alternatives you've considered.\n\n## 📸 Mockups/Examples\n\nIf applicable, add mockups, sketches, or examples from other tools.\n\n## 🎯 Priority\n\n- [ ] Low - Nice to have\n- [ ] Medium - Would improve UX significantly\n- [ ] High - Critical for user workflow\n- [ ] Critical - Blocking current functionality\n\n## 📱 Target Platforms\n\n- [ ] Desktop\n- [ ] Mobile\n- [ ] Tablet\n- [ ] All platforms\n\n---\n\n💬 **Join our Discord** for feature discussions: https://discord.gg/HHMs7Eg\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\n🚀 Thanks for contributing to GitHub Profile README Generator V2!\n\nBefore submitting your Pull Request, please ensure you've done the following:\n📖 Read the Contributing Guide: https://github.com/rahuldkjain/github-profile-readme-generator/blob/master/CONTRIBUTING.md\n📖 Read the Code of Conduct: https://github.com/rahuldkjain/github-profile-readme-generator/blob/master/CODE_OF_CONDUCT.md\n🔄 Follow our Commit Convention: https://github.com/rahuldkjain/github-profile-readme-generator/blob/master/COMMIT_CONVENTION.md\n👷‍♀️ Create focused, single-purpose PRs\n✅ Test your changes thoroughly\n📝 Use conventional commit messages (feat:, fix:, docs:, etc.)\n📗 Update documentation and add screenshots for UI changes\n\nFor Work In Progress PRs, please use the Draft PR feature.\nAvoid force-pushing after receiving reviews unless requested.\n-->\n\n# 🔄 Pull Request\n\n## 📋 **Type of Change** (check all applicable)\n\n- [ ] 🐛 **Bug Fix** - Fixes an issue without breaking existing functionality\n- [ ] ✨ **Feature** - Adds new functionality\n- [ ] ⚡ **Performance** - Improves performance without changing functionality\n- [ ] ♻️ **Refactor** - Code changes that neither fix bugs nor add features\n- [ ] 📚 **Documentation** - Updates to documentation, comments, or README\n- [ ] 🎨 **Style** - Code style changes (formatting, missing semi-colons, etc.)\n- [ ] 🧪 **Test** - Adding or updating tests\n- [ ] 🏗️ **Build** - Changes to build system or dependencies\n- [ ] 👷 **CI/CD** - Changes to CI/CD workflows\n- [ ] 🔒 **Security** - Security improvements or vulnerability fixes\n- [ ] ♿ **Accessibility** - Improves accessibility compliance\n- [ ] 📱 **Mobile** - Mobile-specific improvements\n- [ ] 🌐 **i18n** - Internationalization changes\n\n## 📖 **Description**\n\n<!-- Provide a clear and concise description of what this PR does -->\n\n### **What changed?**\n\n<!-- Describe the changes made -->\n\n### **Why was this change made?**\n\n<!-- Explain the motivation behind this change -->\n\n### **How does this change help users?**\n\n<!-- Describe the user benefit -->\n\n## 🔗 **Related Issues**\n\n<!-- Link related issues using keywords: Closes #123, Fixes #456, Related to #789 -->\n\n- Closes #\n- Fixes #\n- Related to #\n\n## 🧪 **Testing & Quality Assurance**\n\n### **Testing Done** (check all applicable)\n\n- [ ] ✅ **Manual testing** - Tested functionality manually\n- [ ] 🧪 **Unit tests** - Added/updated unit tests\n- [ ] 🔄 **Integration tests** - Tested with other components\n- [ ] 📱 **Mobile testing** - Tested on mobile devices\n- [ ] ♿ **Accessibility testing** - Tested with screen readers/keyboard nav\n- [ ] 🌐 **Cross-browser testing** - Tested in multiple browsers\n- [ ] 🎨 **Visual testing** - Checked UI/UX in light/dark themes\n\n### **Test Instructions**\n\n<!-- Provide step-by-step instructions for reviewers to test your changes -->\n\n1.\n2.\n3.\n\n### **Expected Behavior**\n\n<!-- Describe what should happen when testing -->\n\n## 📸 **Screenshots/Recordings**\n\n<!--\nFor UI changes, please include:\n- Before/after screenshots\n- Mobile screenshots\n- Dark/light theme screenshots\n- Screen recordings for complex interactions\n-->\n\n### **Before**\n\n<!-- Screenshot/description of current state -->\n\n### **After**\n\n<!-- Screenshot/description of new state -->\n\n## 📋 **Checklist**\n\n### **Code Quality**\n\n- [ ] 🔍 **TypeScript** - No TypeScript errors (`npm run type-check`)\n- [ ] 🧹 **Linting** - No ESLint errors (`npm run lint`)\n- [ ] 🎨 **Formatting** - Code is properly formatted (`npm run format`)\n- [ ] 🏗️ **Build** - Production build succeeds (`npm run build`)\n- [ ] ⚡ **Performance** - No performance regressions introduced\n\n### **Accessibility**\n\n- [ ] ♿ **WCAG Compliance** - Follows WCAG 2.1 AA guidelines\n- [ ] ⌨️ **Keyboard Navigation** - All interactive elements are keyboard accessible\n- [ ] 🔍 **Screen Reader** - Proper ARIA labels and semantic HTML\n- [ ] 🎨 **Color Contrast** - Meets contrast requirements\n- [ ] 🎯 **Focus Management** - Visible focus indicators\n\n### **Mobile & Responsive**\n\n- [ ] 📱 **Mobile Responsive** - Works on mobile devices (320px+)\n- [ ] 🖥️ **Desktop** - Works on desktop (1024px+)\n- [ ] 📐 **Tablet** - Works on tablet sizes (768px+)\n- [ ] 🔄 **Orientation** - Works in portrait and landscape\n\n### **Browser Compatibility**\n\n- [ ] 🌐 **Chrome** - Latest version\n- [ ] 🦊 **Firefox** - Latest version\n- [ ] 🧭 **Safari** - Latest version\n- [ ] 📱 **Mobile Safari** - iOS Safari\n- [ ] 📱 **Chrome Mobile** - Android Chrome\n\n### **Documentation**\n\n- [ ] 📚 **Code Comments** - Added helpful comments for complex logic\n- [ ] 📖 **Documentation** - Updated relevant documentation\n- [ ] 📝 **README** - Updated README if needed\n- [ ] 🔄 **Changelog** - Will be auto-generated from conventional commits\n\n### **Security & Privacy**\n\n- [ ] 🔒 **No Secrets** - No API keys, passwords, or sensitive data exposed\n- [ ] 🛡️ **Input Validation** - Proper validation for user inputs\n- [ ] 🔐 **XSS Prevention** - Protected against XSS attacks\n- [ ] 🍪 **Privacy Compliant** - Follows GDPR/privacy requirements\n\n## 🚀 **Deployment Notes**\n\n<!-- Any special considerations for deployment -->\n\n- [ ] **No breaking changes** - Backward compatible\n- [ ] **Database changes** - N/A (static site)\n- [ ] **Environment variables** - No new env vars needed\n- [ ] **Third-party dependencies** - No new external dependencies\n\n## 📝 **Additional Notes**\n\n<!-- Any additional information, concerns, or context -->\n\n## 👀 **Reviewers**\n\n<!-- Tag specific reviewers if needed -->\n<!-- @username for specific reviewers -->\n\n---\n\n**By submitting this PR, I confirm that:**\n\n- ✅ I have read and agree to the [Code of Conduct](https://github.com/rahuldkjain/github-profile-readme-generator/blob/master/CODE_OF_CONDUCT.md)\n- ✅ I have followed the [Contributing Guidelines](https://github.com/rahuldkjain/github-profile-readme-generator/blob/master/CONTRIBUTING.md)\n- ✅ I have used [Conventional Commits](https://github.com/rahuldkjain/github-profile-readme-generator/blob/master/COMMIT_CONVENTION.md) for my commit messages\n- ✅ I have tested my changes thoroughly\n- ✅ My code follows the project's coding standards\n"
  },
  {
    "path": ".github/config.yml",
    "content": "# Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome\n\n# Comment to be posted to on first time issues\nnewIssueWelcomeComment: >\n  Thanks for opening your first issue here! Your contribution means alot. 🙌 Join Discord Server (https://discord.gg/HHMs7Eg) for discussing issues, pull-requests, new features, etc.\n\n# Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome\n\n# Comment to be posted to on PRs from first time contributors in your repository\nnewPRWelcomeComment: >\n  Thanks for opening this pull request! Make sure you have assigned an issue to this respective PR 😇\n\n# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge\n\n# Comment to be posted to on pull requests merged by a first time user\nfirstPRMergeComment: >\n  Congrats on merging your first pull request🎉! Thanks alot for your contribution. 🙏\n"
  },
  {
    "path": ".github/workflows/deploy.yml",
    "content": "name: Build and Deploy\n\non:\n  push:\n    branches: [master, dev]\n\n# Allow concurrent deployments for different environments\nconcurrency:\n  group: 'pages-${{ github.ref }}'\n  cancel-in-progress: true\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version: '20'\n          cache: 'npm'\n\n      - name: Install dependencies\n        run: npm ci\n\n      - name: Run type check\n        run: npm run type-check\n\n      - name: Run linting\n        run: npm run lint\n\n      - name: Run tests\n        run: npm run test\n\n      - name: Build application\n        run: |\n          echo \"Building for branch: ${{ github.ref_name }}\"\n          echo \"NODE_ENV: $NODE_ENV\"\n          echo \"SURGE_PREVIEW: $SURGE_PREVIEW\"\n          npm run build\n        env:\n          NEXT_PUBLIC_GA_ID: ${{ secrets.NEXT_PUBLIC_GA_ID }}\n          NEXT_PUBLIC_REQUIRE_CONSENT: true\n          NEXT_PUBLIC_ANONYMIZE_IP: true\n          # Set SURGE_PREVIEW for non-master branches to disable basePath\n          SURGE_PREVIEW: ${{ github.ref != 'refs/heads/master' && 'true' || '' }}\n\n      - name: Upload Pages Artifact (Production)\n        if: github.ref == 'refs/heads/master'\n        uses: actions/upload-pages-artifact@v3\n        with:\n          path: ./out\n\n      - name: Upload Preview Artifact\n        if: github.ref != 'refs/heads/master'\n        uses: actions/upload-artifact@v4\n        with:\n          name: preview-build-${{ github.run_number }}-${{ github.run_attempt }}\n          path: ./out\n          retention-days: 30\n\n  # Production deployment to main GitHub Pages\n  deploy-production:\n    needs: build\n    runs-on: ubuntu-latest\n\n    # Only deploy to production from master branch\n    if: github.ref == 'refs/heads/master'\n\n    permissions:\n      pages: write\n      id-token: write\n\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n\n    steps:\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v4\n\n  # Preview deployment for development branches\n  deploy-preview:\n    needs: build\n    runs-on: ubuntu-latest\n\n    # Deploy preview for dev branches (not master, only on direct push)\n    if: github.ref != 'refs/heads/master' && github.event_name == 'push'\n\n    # Add deployment environment to show URL in GitHub UI\n    environment:\n      name: preview-${{ github.ref_name }}\n\n    steps:\n      - name: Calculate sanitized branch name\n        id: branch\n        run: |\n          SANITIZED_BRANCH=$(echo \"${{ github.ref_name }}\" | sed 's/[^a-zA-Z0-9-]/-/g' | tr '[:upper:]' '[:lower:]')\n          echo \"sanitized=$SANITIZED_BRANCH\" >> $GITHUB_OUTPUT\n          echo \"url=https://gprg-${SANITIZED_BRANCH}.surge.sh\" >> $GITHUB_OUTPUT\n      - name: Debug deployment conditions\n        run: |\n          echo \"GitHub ref: ${{ github.ref }}\"\n          echo \"GitHub ref name: ${{ github.ref_name }}\"\n          echo \"Event name: ${{ github.event_name }}\"\n          echo \"Is master?: ${{ github.ref == 'refs/heads/master' }}\"\n          echo \"Is push?: ${{ github.event_name == 'push' }}\"\n          echo \"Should deploy?: ${{ github.ref != 'refs/heads/master' && github.event_name == 'push' }}\"\n\n      - name: Download Preview Artifact\n        uses: actions/download-artifact@v4\n        with:\n          name: preview-build-${{ github.run_number }}-${{ github.run_attempt }}\n          path: ./preview-out\n\n      - name: Deploy to Surge.sh (Preview)\n        id: deploy\n        run: |\n          npm install -g surge\n          echo \"Deploying preview for branch: ${{ github.ref_name }}\"\n          echo \"Sanitized branch name: ${{ steps.branch.outputs.sanitized }}\"\n          echo \"Preview URL: ${{ steps.branch.outputs.url }}\"\n          surge ./preview-out ${{ steps.branch.outputs.url }} --token ${{ secrets.SURGE_TOKEN }}\n          echo \"deployment_url=${{ steps.branch.outputs.url }}\" >> $GITHUB_OUTPUT\n        env:\n          SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }}\n\n      - name: Comment PR with Preview URL\n        if: github.event_name == 'pull_request'\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const previewUrl = '${{ steps.deploy.outputs.deployment_url }}';\n\n            github.rest.issues.createComment({\n              issue_number: context.issue.number,\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              body: `🚀 **Preview Deployment Ready!**\\n\\n📱 Preview URL: ${previewUrl}\\n\\n*This preview will be available for 30 days.*`\n            });\n\n      - name: Create deployment status\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const previewUrl = '${{ steps.deploy.outputs.deployment_url }}';\n\n            // Create a commit status with the deployment URL\n            github.rest.repos.createCommitStatus({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              sha: context.sha,\n              state: 'success',\n              target_url: previewUrl,\n              description: `Preview deployed to ${previewUrl}`,\n              context: 'deployment/preview'\n            });\n\n      - name: Update Status Check\n        run: |\n          echo \"🚀 Preview deployed successfully!\"\n          echo \"📱 Preview URL: ${{ steps.deploy.outputs.deployment_url }}\"\n          echo \"\"\n          echo \"You can find this URL in:\"\n          echo \"1. GitHub Actions > Environments tab\"\n          echo \"2. Commit status checks\"\n          echo \"3. This workflow run summary\"\n\n          # Add to job summary for easy access\n          echo \"## 🚀 Preview Deployment Complete!\" >> $GITHUB_STEP_SUMMARY\n          echo \"\" >> $GITHUB_STEP_SUMMARY\n          echo \"**Branch:** \\`${{ github.ref_name }}\\`\" >> $GITHUB_STEP_SUMMARY\n          echo \"**Preview URL:** [${{ steps.deploy.outputs.deployment_url }}](${{ steps.deploy.outputs.deployment_url }})\" >> $GITHUB_STEP_SUMMARY\n          echo \"\" >> $GITHUB_STEP_SUMMARY\n          echo \"### Where to find this URL:\" >> $GITHUB_STEP_SUMMARY\n          echo \"- **Environments tab:** Go to your repository → Environments → preview-${{ github.ref_name }}\" >> $GITHUB_STEP_SUMMARY\n          echo \"- **Commit status:** Check the commit status checks for 'deployment/preview'\" >> $GITHUB_STEP_SUMMARY\n          echo \"- **This summary:** Bookmark this workflow run for easy access\" >> $GITHUB_STEP_SUMMARY\n"
  },
  {
    "path": ".gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.*\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/versions\n\n# testing\n/coverage\n\n# next.js\n/.next/\n/out/\n\n# production\n/build\n\n# misc\n.DS_Store\n*.pem\n\n# debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n.pnpm-debug.log*\n\n# env files (can opt-in for committing if needed)\n.env*\n\n# vercel\n.vercel\n\n# typescript\n*.tsbuildinfo\nnext-env.d.ts\n\n# Claude\n.cursor/\n.claude/\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nnpx --no-install lint-staged\n"
  },
  {
    "path": ".prettierignore",
    "content": ".cache\npackage.json\npackage-lock.json\npublic\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"jsxSingleQuote\": false,\n  \"tabWidth\": 2,\n  \"printWidth\": 100,\n  \"trailingComma\": \"es5\",\n  \"semi\": true,\n  \"arrowParens\": \"always\",\n  \"endOfLine\": \"lf\",\n  \"plugins\": [\"prettier-plugin-tailwindcss\"]\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [2.0.0] - 2025-10-15\n\n### ✨ Features\n\n- **Complete rewrite**: Migrated to Next.js 15 with App Router and Turbopack\n- **React 19**: Updated to latest React with concurrent features\n- **TypeScript 5**: Full type safety with strict configuration\n- **Modern UI**: Tailwind CSS 4 with design tokens and CSS variables\n- **Accessibility**: WCAG 2.1 AA compliance with accessibility menu\n- **Privacy**: GDPR-compliant analytics with opt-in consent\n- **Performance**: 3x faster builds and 50% smaller bundle size\n- **Auto-fill**: GitHub integration for automatic profile data\n- **Export/Import**: JSON functionality for profile data\n- **Enhanced UX**: Multi-step wizard with real-time validation\n- **Responsive**: Mobile-first design with touch optimization\n\n### 🐛 Bug Fixes\n\n- Fixed skill selection persistence across sessions\n- Resolved theme toggle flickering on page load\n- Fixed social media icon alignment issues\n- Corrected markdown preview rendering edge cases\n\n### ⚡ Performance Improvements\n\n- Implemented code splitting with lazy loading\n- Optimized bundle size with Turbopack\n- Added image optimization for better loading\n- Reduced JavaScript bundle by 50%\n\n### ♻️ Code Refactoring\n\n- Migrated from Gatsby to Next.js 15\n- Converted all components to TypeScript\n- Implemented modern React patterns (hooks, context)\n- Restructured project architecture for scalability\n\n### 📚 Documentation\n\n- Added comprehensive TypeScript documentation\n- Created accessibility guidelines\n- Updated deployment documentation\n- Added contributing guidelines for V2\n\n### 🏗️ Build System\n\n- Migrated to Next.js build system\n- Added Turbopack for development\n- Implemented ESLint + Prettier configuration\n- Added Vitest for testing\n\n### 👷 Continuous Integration\n\n- Enhanced GitHub Actions workflows\n- Added preview deployments with environment tracking\n- Implemented automated release management\n- Added comprehensive testing pipeline\n\n---\n\n## Previous Versions (V1)\n\nFor changes in V1, see the [V1 Release Archive](https://github.com/rahuldkjain/github-profile-readme-generator/releases?q=v1&expanded=true).\n\n### Migration from V1 to V2\n\nV2 represents a complete rewrite with breaking changes:\n\n- **Technology Stack**: Gatsby → Next.js 15\n- **Styling**: CSS Modules → Tailwind CSS 4\n- **State Management**: Local state → Zustand + localStorage\n- **Build System**: Webpack → Turbopack\n- **Type Safety**: JavaScript → TypeScript 5\n\nAll V1 functionality has been preserved and enhanced in V2. See [MIGRATION_STRATEGY.md](./MIGRATION_STRATEGY.md) for detailed migration information.\n"
  },
  {
    "path": "CHEATSHEET.md",
    "content": "# GitHub Profile Generator - Developer Cheatsheet\n\n## 🚀 Quick Start\n```bash\nnpm install && npm run dev\n```\nVisit: http://localhost:3000\n\n---\n\n## 📁 File Structure (Where to Edit)\n\n| Task | File Location |\n|------|--------------|\n| Add form field | `src/components/sections/[section]-section.tsx` |\n| Add validation | `src/lib/validations.ts` |\n| Modify markdown output | `src/lib/markdown-generator.ts` |\n| Add new section | Create in `src/components/sections/` + add to `src/app/page.tsx` |\n| Create form component | `src/components/forms/` |\n| Add skill | `src/constants/skills.ts` |\n| Storage logic | `src/lib/storage.ts` |\n| Theme colors | `src/styles/globals.css` |\n| Header/Footer | `src/components/layout/` |\n\n---\n\n## 🎨 Theme Colors (Always Use These)\n\n```typescript\n// Backgrounds\nbg-background    // Main background\nbg-card         // Card background\nbg-accent       // Accent background\nbg-muted        // Muted background\nbg-primary      // Primary action background\n\n// Text\ntext-foreground         // Main text\ntext-muted-foreground   // Secondary text\ntext-primary-foreground // Text on primary bg\ntext-destructive        // Error text\n\n// Borders & Effects\nborder-border   // Border color\nborder-input    // Input border\nring-ring      // Focus ring\n```\n\n**❌ Never hardcode:** `bg-white`, `text-black`, `border-gray-300`\n\n---\n\n## 📝 Component Templates\n\n### Form Component\n```typescript\n'use client';\n\nimport { forwardRef } from 'react';\nimport type { InputHTMLAttributes } from 'react';\n\nexport interface MyInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {\n  label?: string;\n  error?: string;\n}\n\nexport const MyInput = forwardRef<HTMLInputElement, MyInputProps>(\n  ({ label, error, className = '', ...props }, ref) => {\n    return (\n      <div className=\"w-full space-y-1\">\n        {label && <label htmlFor={props.id} className=\"text-foreground text-sm font-medium\">{label}</label>}\n        <input\n          ref={ref}\n          className={`border-input bg-background text-foreground focus:ring-ring w-full rounded-lg border px-4 py-2 transition-colors focus:outline-none focus:ring-2 disabled:cursor-not-allowed disabled:opacity-50 ${error ? 'border-destructive' : ''} ${className}`}\n          aria-invalid={!!error}\n          {...props}\n        />\n        {error && <p className=\"text-destructive text-sm\" role=\"alert\">{error}</p>}\n      </div>\n    );\n  }\n);\n\nMyInput.displayName = 'MyInput';\n```\n\n### Section Component\n```typescript\n'use client';\n\nimport { UseFormRegister, FieldErrors } from 'react-hook-form';\nimport { FormInput } from '@/components/forms/form-input';\nimport type { MyFormData } from '@/lib/validations';\n\ninterface MySectionProps {\n  register: UseFormRegister<MyFormData>;\n  errors: FieldErrors<MyFormData>;\n}\n\nexport function MySection({ register, errors }: MySectionProps) {\n  return (\n    <div className=\"space-y-6\">\n      <div className=\"border-b border-border pb-4\">\n        <h2 className=\"text-2xl font-bold\">Section Title</h2>\n        <p className=\"text-muted-foreground mt-1 text-sm\">Description</p>\n      </div>\n\n      <div className=\"grid gap-4 md:grid-cols-2\">\n        <FormInput\n          {...register('fieldName')}\n          id=\"fieldName\"\n          label=\"Label\"\n          error={errors.fieldName?.message}\n        />\n      </div>\n    </div>\n  );\n}\n```\n\n---\n\n## 🔒 TypeScript Patterns\n\n```typescript\n// Component Props\ninterface ComponentProps {\n  title: string;              // Required\n  count?: number;            // Optional\n  onAction: () => void;      // Required function\n  onChange?: (val: string) => void; // Optional function\n}\n\n// Zod Schema\nconst schema = z.object({\n  email: z.string().email(),\n  age: z.number().min(0).max(120),\n  url: z.string().url().optional(),\n  isActive: z.boolean().default(false),\n});\n\ntype FormData = z.infer<typeof schema>;\n\n// Form Hook\nconst { register, watch, setValue, formState: { errors } } = useForm<FormData>({\n  resolver: zodResolver(schema),\n  defaultValues: { isActive: false }\n});\n```\n\n---\n\n## ♿ Accessibility Checklist\n\n```typescript\n// ✅ Keyboard Navigation\n<button\n  onClick={handleClick}\n  onKeyDown={(e) => e.key === 'Enter' && handleClick()}\n  className=\"focus:ring-2 focus:ring-primary\"\n>\n\n// ✅ ARIA Labels\n<nav aria-label=\"Main navigation\">\n<button aria-label=\"Close dialog\">\n<input aria-describedby=\"help-text\" aria-invalid={!!error} />\n\n// ✅ Form Labels\n<label htmlFor=\"email\">Email</label>\n<input id=\"email\" />\n\n// ✅ Error Messages\n<p id=\"email-error\" role=\"alert\" className=\"text-destructive\">\n  {error}\n</p>\n\n// ✅ Active States\n<Link href=\"/\" aria-current={isActive ? 'page' : undefined}>\n\n// ✅ Alt Text\n<img src={url} alt=\"Descriptive text\" loading=\"lazy\" />\n```\n\n---\n\n## 📱 Responsive Patterns\n\n```typescript\n// Mobile First\nclassName=\"text-sm md:text-base lg:text-lg\"\n\n// Grid Layouts\nclassName=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\"\n\n// Visibility\nclassName=\"hidden md:block\"      // Desktop only\nclassName=\"block md:hidden\"      // Mobile only\n\n// Spacing\nclassName=\"gap-2 md:gap-4 lg:gap-6\"\nclassName=\"px-4 md:px-6 lg:px-8\"\n\n// Breakpoints\n// base: 0-639px\n// sm: 640px+\n// md: 768px+\n// lg: 1024px+\n// xl: 1280px+\n```\n\n---\n\n## 🎯 Import Order\n\n```typescript\n// 1. React & Next.js\nimport { useState, useEffect } from 'react';\nimport Link from 'next/link';\n\n// 2. Third-party\nimport { useForm } from 'react-hook-form';\nimport { z } from 'zod';\n\n// 3. Internal utils\nimport { saveFormData } from '@/lib/storage';\nimport type { ProfileFormData } from '@/lib/validations';\n\n// 4. Components\nimport { FormInput } from '@/components/forms/form-input';\n\n// 5. Constants\nimport { skills } from '@/constants/skills';\n```\n\n---\n\n## 🏎️ Performance\n\n```typescript\n// Memoize calculations\nconst count = useMemo(() =>\n  expensiveCalculation(data),\n  [data]\n);\n\n// Memoize callbacks\nconst handleClick = useCallback(() => {\n  doSomething();\n}, []);\n\n// Memoize components\nconst MemoizedComponent = React.memo(Component);\n\n// Debounce auto-save\nuseEffect(() => {\n  const timer = setTimeout(() => {\n    saveData();\n  }, 1000);\n  return () => clearTimeout(timer);\n}, [data]);\n\n// Lazy load images\n<img src={url} alt=\"...\" loading=\"lazy\" />\n```\n\n---\n\n## 💾 Storage Pattern\n\n```typescript\n// Save\nimport { saveFormData } from '@/lib/storage';\n\nsaveFormData({\n  profile: getProfileValues(),\n  social: getSocialValues(),\n  // ...\n  skills: selectedSkills,\n  lastSaved: new Date().toISOString(),\n});\n\n// Load\nimport { loadFormData } from '@/lib/storage';\n\nuseEffect(() => {\n  const saved = loadFormData();\n  if (saved) {\n    // Restore data\n    setValue('title', saved.profile.title);\n  }\n}, []);\n\n// Clear\nimport { clearFormData } from '@/lib/storage';\nclearFormData();\n```\n\n---\n\n## 🐛 Common Errors & Fixes\n\n| Error | Fix |\n|-------|-----|\n| \"Type 'any' is not assignable\" | Add explicit types, avoid `any` |\n| \"Property does not exist\" | Add to interface, check spelling |\n| \"Cannot find module '@/...'\" | Check path, restart TS server |\n| \"localStorage is not defined\" | Wrap in `useEffect`, check 'use client' |\n| \"Hydration mismatch\" | Ensure same HTML on server/client |\n| TypeScript errors after install | Run `npm run type-check` |\n\n---\n\n## 🎨 Tailwind Class Order\n\n```\nLayout → Size → Spacing → Typography → Colors → Borders → Effects → States → Responsive\n```\n\nExample:\n```typescript\nclassName=\"flex items-center gap-2 w-full px-4 py-2 text-sm font-medium text-foreground bg-accent rounded-lg border border-border shadow-sm transition-colors hover:bg-accent/80 focus:ring-2 focus:ring-primary disabled:opacity-50 md:px-6 lg:text-base\"\n```\n\n---\n\n## 🔧 Useful Commands\n\n```bash\n# Development\nnpm run dev              # Start dev server (Turbopack)\nnpm run build           # Production build\nnpm run start           # Start production server\nnpm run type-check      # Check TypeScript\nnpm run lint            # Run ESLint\n\n# Git\ngit status              # Check changes\ngit add .               # Stage all changes\ngit commit -m \"feat: add feature\"  # Commit\ngit push                # Push to remote\n```\n\n---\n\n## 🎯 Git Commit Types\n\n```\nfeat(scope):     # New feature\nfix(scope):      # Bug fix\nrefactor(scope): # Code restructure\nstyle(scope):    # Formatting\na11y(scope):     # Accessibility\nperf(scope):     # Performance\ndocs(scope):     # Documentation\ntest(scope):     # Tests\nchore(scope):    # Maintenance\n```\n\n---\n\n## 📚 Key Files to Read\n\n1. **REVAMP_SUMMARY.md** - Full architecture\n2. **.cursorrules** - Code conventions\n3. **.cursorrules-quick** - Quick patterns\n4. **DX_GUIDE.md** - Developer guide\n5. **src/app/page.tsx** - Main wizard implementation\n\n---\n\n## 🤖 Cursor AI Quick Commands\n\n```\n# Include file in context\n@filename\n\n# Include folder\n@folder\n\n# Create component\n@.cursorrules Create a form component for [x]\n\n# Fix code\n@.cursorrules Fix accessibility issues in [component]\n\n# Review\n@.cursorrules Review this code for [standards]\n```\n\n---\n\n## 💡 Pro Tips\n\n1. **Always use 'use client'** for components with state/events\n2. **Never hardcode colors** - use CSS variables\n3. **Type everything** - avoid `any`\n4. **Think accessibility first** - keyboard + ARIA\n5. **Mobile first** - base styles for mobile\n6. **Test dark mode** - both themes\n7. **Debounce saves** - 1 second delay\n8. **Memoize when needed** - useMemo/useCallback\n9. **Clean up effects** - return cleanup function\n10. **Follow patterns** - check existing code first\n\n---\n\n## 🚨 Before Committing\n\n- [ ] No TypeScript errors\n- [ ] No ESLint warnings\n- [ ] Works on mobile (375px)\n- [ ] Works on desktop (1440px)\n- [ ] Keyboard navigable\n- [ ] Focus indicators visible\n- [ ] Dark mode tested\n- [ ] Auto-save works (if form)\n- [ ] No console errors\n- [ ] Follows .cursorrules patterns\n\n---\n\n## 📞 Help Resources\n\n- **Internal**: REVAMP_SUMMARY.md, .cursorrules, DX_GUIDE.md\n- **Next.js**: https://nextjs.org/docs\n- **React**: https://react.dev\n- **Tailwind**: https://tailwindcss.com/docs\n- **React Hook Form**: https://react-hook-form.com\n- **Zod**: https://zod.dev\n- **WCAG**: https://www.w3.org/WAI/WCAG21/quickref/\n\n---\n\n**Print this and keep it handy! 📋**\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n- Using welcoming and inclusive language\n- Being respectful of differing viewpoints and experiences\n- Gracefully accepting constructive criticism\n- Focusing on what is best for the community\n- Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n- The use of sexualized language or imagery and unwelcome sexual attention or\n  advances\n- Trolling, insulting/derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n- Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at rahuldkjain@gmail.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "CODE_STYLE_GUIDE.md",
    "content": "# Coding Style Guide\n\n## Project Architecture\n\nThis project uses **Next.js 15** with **TypeScript** and **Tailwind CSS**. We follow modern React patterns with functional components and hooks.\n\n## File Layout (`src/components/*.tsx`)\n\n1. **Imports**\n   - React imports first\n   - Third-party library imports\n   - Internal component imports\n   - Type imports (using `import type`)\n\n2. **Type Definitions**\n   - Interface definitions for props\n   - Type aliases if needed\n\n3. **Reusable Components**\n   - Smaller components needed for the main component\n   - Place **above** the main component, **not** inside it\n\n4. **Main Component**\n   - Main exported component (e.g., `SkillsSection` in `skills-section.tsx`)\n\n5. **Export Statement**\n   - `export default MainComponent;` or named exports\n\n## TypeScript Guidelines\n\n### Component Props\n\n- Use `interface` for component props with clear naming:\n\n```tsx\ninterface ButtonProps {\n  variant?: 'primary' | 'secondary';\n  size?: 'sm' | 'md' | 'lg';\n  onClick?: () => void;\n  children: React.ReactNode;\n}\n```\n\n### Type Safety\n\n- Avoid `any` types - use `unknown` or proper types\n- Use strict TypeScript configuration\n- Leverage type inference where possible\n- Use `as const` for literal types\n\n```tsx\n// Good\nconst themes = ['light', 'dark'] as const;\ntype Theme = (typeof themes)[number];\n\n// Bad\nconst themes: any = ['light', 'dark'];\n```\n\n## Component Patterns\n\n### Functional Components\n\n- Use **ES6 arrow functions** for all components\n- Use `React.forwardRef` when ref forwarding is needed\n- Prefer named exports for reusable components\n\n```tsx\n// Good\nexport const Button = ({ variant = 'primary', ...props }: ButtonProps) => {\n  return <button className={`btn btn-${variant}`} {...props} />;\n};\n\n// Also good for main components\nconst SkillsSection = ({ skills, onSkillToggle }: SkillsSectionProps) => {\n  // component logic\n};\nexport default SkillsSection;\n```\n\n### Hooks Usage\n\n- Use custom hooks for reusable logic\n- Keep hooks at the top of components\n- Use `useCallback` and `useMemo` for performance optimization\n\n```tsx\nconst MyComponent = () => {\n  const [state, setState] = useState();\n  const { data, loading } = useCustomHook();\n\n  const memoizedValue = useMemo(() => expensiveCalculation(), [dependency]);\n\n  // component JSX\n};\n```\n\n## Styling with Tailwind CSS\n\n### Class Organization\n\n- Use Tailwind utility classes\n- Group related classes together\n- Use responsive prefixes (`sm:`, `md:`, `lg:`)\n\n```tsx\n// Good\n<div className=\"flex flex-col gap-4 rounded-lg border p-4 sm:flex-row sm:gap-6\">\n  <button className=\"bg-primary text-primary-foreground hover:bg-primary/90 rounded px-4 py-2 transition-colors\">\n    Click me\n  </button>\n</div>\n```\n\n### CSS Variables\n\n- Use CSS custom properties for theming\n- Follow the design system color palette\n- Prefer Tailwind classes over custom CSS\n\n## File Naming Conventions\n\n- **Components**: `kebab-case.tsx` (e.g., `skills-section.tsx`)\n- **Hooks**: `use-hook-name.ts` (e.g., `use-local-storage.ts`)\n- **Types**: `kebab-case.ts` (e.g., `profile-types.ts`)\n- **Utils**: `kebab-case.ts` (e.g., `markdown-generator.ts`)\n\n## Spacing & Formatting\n\n### JavaScript/TypeScript\n\n- Use **2 spaces** for indentation (not 4)\n- Use spaces after `if`, `for`, `while`, `switch`\n- No spaces after opening `(` and before closing `)`\n- Use spaces around destructuring\n\n```tsx\n// Good\nconst { name, email } = user;\nconst handleClick = ({ target }: MouseEvent) => {\n  if (target instanceof HTMLElement) {\n    // logic\n  }\n};\n\n// Bad\nconst { name, email } = user;\nconst handleClick = ({ target }: MouseEvent) => {\n  if (target instanceof HTMLElement) {\n    // logic\n  }\n};\n```\n\n### JSX Formatting\n\n- Space before self-closing tag slash\n- No spaces in JSX curly braces\n- Use new lines for multiple props\n\n```tsx\n// Good\n<Input\n  value={value}\n  onChange={handleChange}\n  placeholder=\"Enter text\"\n/>\n\n<Icon className=\"h-4 w-4\" />\n\n// Bad\n<Input value={value} onChange={handleChange} placeholder=\"Enter text\"/>\n<Icon className=\"h-4 w-4\"/>\n```\n\n## Props & Event Handling\n\n### Prop Naming\n\n- Use `camelCase` for prop names\n- Use `PascalCase` if prop value is a React component\n- Use descriptive names with proper prefixes\n\n```tsx\ninterface FormProps {\n  initialValues?: Record<string, unknown>;\n  onSubmit?: (data: FormData) => void;\n  isLoading?: boolean;\n  ErrorComponent?: React.ComponentType;\n}\n```\n\n### Event Handlers\n\n- Prefix with `handle` or `on`\n- Use descriptive names\n- Type event handlers properly\n\n```tsx\nconst handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n  setValue(event.target.value);\n};\n\nconst handleSubmit = async (event: React.FormEvent) => {\n  event.preventDefault();\n  // submit logic\n};\n```\n\n## Best Practices\n\n### Code Quality\n\n- **Always** add semicolons\n- Use meaningful variable and function names\n- Keep components small and focused (< 200 lines)\n- Extract complex logic into custom hooks\n- Use TypeScript strict mode\n\n### Accessibility\n\n- Always add `alt` prop to `img` tags\n- Use semantic HTML elements\n- Add proper ARIA attributes\n- Don't use `outline: none` without alternative focus styles\n- Use proper heading hierarchy\n\n### Performance\n\n- Use `React.memo` for expensive components\n- Implement proper dependency arrays for hooks\n- Avoid inline objects and functions in JSX\n- Use `useCallback` and `useMemo` appropriately\n\n```tsx\n// Good\nconst MemoizedComponent = React.memo(({ data }: Props) => {\n  const processedData = useMemo(() => processData(data), [data]);\n\n  const handleClick = useCallback(() => {\n    // click logic\n  }, []);\n\n  return <div>{/* JSX */}</div>;\n});\n```\n\n### Error Handling\n\n- Use error boundaries for component errors\n- Handle async operations properly\n- Provide fallback UI for loading states\n\n```tsx\nconst AsyncComponent = () => {\n  const [data, setData] = useState(null);\n  const [loading, setLoading] = useState(true);\n  const [error, setError] = useState(null);\n\n  useEffect(() => {\n    fetchData()\n      .then(setData)\n      .catch(setError)\n      .finally(() => setLoading(false));\n  }, []);\n\n  if (loading) return <LoadingSpinner />;\n  if (error) return <ErrorMessage error={error} />;\n  if (!data) return <EmptyState />;\n\n  return <DataDisplay data={data} />;\n};\n```\n\n## Dependencies & Imports\n\n### Import Organization\n\n```tsx\n// 1. React imports\nimport { useState, useEffect, useCallback } from 'react';\nimport type { ReactNode } from 'react';\n\n// 2. Third-party libraries\nimport { motion } from 'framer-motion';\nimport { ChevronDown } from 'lucide-react';\n\n// 3. Internal imports\nimport { Button } from '@/components/ui/button';\nimport { useLocalStorage } from '@/hooks/use-local-storage';\nimport type { ProfileData } from '@/types/profile';\n```\n\n### Package Management\n\n- Prefer stable, well-maintained packages\n- Keep dependencies up to date\n- Use exact versions for critical dependencies\n- Document any custom modifications\n\n## Testing Considerations\n\n- Write testable components with clear props\n- Avoid complex side effects in components\n- Use dependency injection for external services\n- Keep business logic separate from UI logic\n\n## Further Reading\n\nThis guide is based on:\n\n- [Next.js Best Practices](https://nextjs.org/docs/app/building-your-application/styling/tailwind-css)\n- [React TypeScript Cheatsheet](https://react-typescript-cheatsheet.netlify.app/)\n- [Tailwind CSS Best Practices](https://tailwindcss.com/docs/reusing-styles)\n\nFor questions about code style, please discuss with maintainers on our [Discord community](https://discord.gg/HHMs7Eg).\n"
  },
  {
    "path": "COMMIT_CONVENTION.md",
    "content": "# 📝 Commit Message Convention\n\nThis project follows [Conventional Commits](https://www.conventionalcommits.org/) specification for automated changelog generation and semantic versioning.\n\n## Format\n\n```\n<type>[optional scope]: <description>\n\n[optional body]\n\n[optional footer(s)]\n```\n\n## Types\n\n| Type       | Description              | Version Bump |\n| ---------- | ------------------------ | ------------ |\n| `feat`     | New feature              | Minor        |\n| `fix`      | Bug fix                  | Patch        |\n| `perf`     | Performance improvement  | Patch        |\n| `refactor` | Code refactoring         | Patch        |\n| `docs`     | Documentation changes    | Patch        |\n| `style`    | Code style changes       | Patch        |\n| `test`     | Adding or updating tests | Patch        |\n| `build`    | Build system changes     | Patch        |\n| `ci`       | CI/CD changes            | Patch        |\n| `chore`    | Maintenance tasks        | No bump      |\n\n## Breaking Changes\n\nAdd `BREAKING CHANGE:` in the footer or `!` after type to indicate breaking changes:\n\n```bash\nfeat!: remove deprecated API endpoints\n\nBREAKING CHANGE: The old API endpoints have been removed. Use the new v2 endpoints instead.\n```\n\n## Examples\n\n### Features\n\n```bash\nfeat: add GitHub auto-fill integration\nfeat(ui): implement dark mode toggle\nfeat!: migrate to Next.js 15 App Router\n```\n\n### Bug Fixes\n\n```bash\nfix: resolve skill selection persistence issue\nfix(mobile): correct responsive navigation layout\nfix(a11y): improve keyboard navigation for forms\n```\n\n### Performance\n\n```bash\nperf: optimize image loading with next/image\nperf(build): reduce bundle size by 30%\n```\n\n### Documentation\n\n```bash\ndocs: update installation instructions\ndocs(api): add TypeScript examples\ndocs(readme): fix broken demo links\n```\n\n### Refactoring\n\n```bash\nrefactor: convert components to TypeScript\nrefactor(store): migrate to Zustand state management\n```\n\n## Scopes (Optional)\n\nUse scopes to indicate the area of change:\n\n- `ui` - User interface components\n- `api` - API related changes\n- `build` - Build system\n- `ci` - Continuous integration\n- `docs` - Documentation\n- `test` - Testing\n- `a11y` - Accessibility\n- `perf` - Performance\n- `mobile` - Mobile-specific changes\n\n## Tools\n\n### Commitizen (Recommended)\n\nInstall commitizen for interactive commit messages:\n\n```bash\nnpm install -g commitizen cz-conventional-changelog\necho '{ \"path\": \"cz-conventional-changelog\" }' > ~/.czrc\n```\n\nUse `git cz` instead of `git commit`:\n\n```bash\ngit add .\ngit cz\n```\n\n### VS Code Extension\n\nInstall \"Conventional Commits\" extension for VS Code to get commit message templates.\n\n## Automated Release Process\n\n1. **Commit** using conventional format\n2. **Push** to master branch\n3. **Release Please** analyzes commits\n4. **Creates PR** with changelog and version bump\n5. **Merge PR** to trigger release and deployment\n\n## Examples in Practice\n\n```bash\n# Adding new feature\ngit commit -m \"feat(ui): add accessibility menu with font size controls\"\n\n# Fixing bug\ngit commit -m \"fix(mobile): resolve navigation menu overflow on small screens\"\n\n# Breaking change\ngit commit -m \"feat!: migrate to Next.js 15 App Router\n\nBREAKING CHANGE: Pages directory structure has changed.\nSee migration guide for updating custom pages.\"\n\n# Performance improvement\ngit commit -m \"perf(build): implement code splitting for 50% bundle reduction\"\n\n# Documentation update\ngit commit -m \"docs(contributing): add TypeScript coding standards\"\n```\n\n## Benefits\n\n- ✅ **Automated changelogs** - No manual changelog maintenance\n- ✅ **Semantic versioning** - Automatic version bumps based on commit types\n- ✅ **Release notes** - Rich, categorized release notes\n- ✅ **Consistency** - Standardized commit history\n- ✅ **Tooling integration** - Works with Release Please, semantic-release, etc.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to GitHub Profile README Generator\n\nWhen contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change.\n\n<a href=\"https://discord.gg/HHMs7Eg\" target=\"blank\">\n<img src=\"https://img.shields.io/discord/735303195105951764?color=%23677BC4&label=Join%20Community&style=flat-square\" alt=\"join discord community of github profile readme generator\"/>\n</a>\n\nPlease note we have a code of conduct, please follow it in all your interactions with the project.\n\n## 🚀 Tech Stack\n\nThis project is built with modern web technologies:\n\n- **Framework**: [Next.js 15](https://nextjs.org/) with App Router\n- **Language**: [TypeScript](https://www.typescriptlang.org/) for type safety\n- **Styling**: [Tailwind CSS](https://tailwindcss.com/) for utility-first styling\n- **Icons**: [Lucide React](https://lucide.dev/) for consistent iconography\n- **Animations**: [Framer Motion](https://www.framer.com/motion/) for smooth animations\n- **Forms**: [React Hook Form](https://react-hook-form.com/) for form management\n- **Analytics**: [Google Analytics 4](https://developers.google.com/analytics/devguides/collection/ga4) with privacy compliance\n- **Testing**: [Vitest](https://vitest.dev/) for unit testing\n- **Linting**: [ESLint](https://eslint.org/) + [Prettier](https://prettier.io/) for code quality\n\n## 🛠️ Development Setup\n\n### Prerequisites\n\n- **Node.js**: Version 18.17 or higher\n- **npm**: Version 9 or higher (comes with Node.js)\n- **Git**: For version control\n\n### Local Development\n\n1. **Fork & Clone the repository**\n\n```bash\n# Fork the repo on GitHub, then clone your fork\ngit clone https://github.com/YOUR_USERNAME/github-profile-readme-generator.git\ncd github-profile-readme-generator\n```\n\n2. **Install dependencies**\n\n```bash\nnpm install\n```\n\n3. **Set up environment variables** (optional)\n\n```bash\n# Copy the example environment file\ncp env.example .env.local\n\n# Add your Google Analytics ID if you want to test analytics\nNEXT_PUBLIC_GA_ID=G-XXXXXXXXXX\n```\n\n4. **Start the development server**\n\n```bash\nnpm run dev\n```\n\nThe app will be available at `http://localhost:3000`\n\n### Available Scripts\n\n```bash\n# Development\nnpm run dev          # Start development server\nnpm run build        # Build for production\nnpm run start        # Start production server\nnpm run export       # Export static site\n\n# Code Quality\nnpm run lint         # Run ESLint\nnpm run lint:fix     # Fix ESLint issues automatically\nnpm run type-check   # Run TypeScript type checking\n\n# Testing\nnpm run test         # Run tests\nnpm run test:watch   # Run tests in watch mode\nnpm run test:ui      # Run tests with UI\n```\n\n## 📝 Pull Request Process\n\n### Before You Start\n\n1. **Check existing issues** to see if your feature/bug is already being worked on\n2. **Create an issue** if one doesn't exist for your contribution\n3. **Join our Discord** to discuss your ideas with the community\n4. **Read our [Code Style Guide](CODE_STYLE_GUIDE.md)** to understand our coding standards\n\n### Making Changes\n\n1. **Create a feature branch** from `main`\n\n```bash\ngit checkout -b feature/your-feature-name\n# or\ngit checkout -b fix/bug-description\n```\n\n2. **Follow our coding standards**\n   - Use TypeScript with strict mode\n   - Follow the existing code style (ESLint + Prettier)\n   - Write meaningful commit messages\n   - Add tests for new features\n   - Update documentation if needed\n\n3. **Test your changes**\n\n```bash\n# Run all checks before submitting\nnpm run lint        # Check code style\nnpm run type-check  # Check TypeScript\nnpm run test        # Run tests\nnpm run build       # Ensure it builds successfully\n```\n\n4. **Commit your changes**\n\n```bash\n# Use conventional commit messages\ngit add .\ngit commit -m \"feat: add new skill category filter\"\n# or\ngit commit -m \"fix: resolve mobile navigation issue\"\n```\n\n### Submitting Your PR\n\n1. **Push your branch**\n\n```bash\ngit push origin feature/your-feature-name\n```\n\n2. **Create a Pull Request** on GitHub with:\n   - Clear title describing the change\n   - Detailed description of what was changed and why\n   - Screenshots for UI changes\n   - Reference to any related issues\n\n3. **PR Requirements**:\n   - ✅ All tests pass\n   - ✅ No TypeScript errors\n   - ✅ ESLint passes\n   - ✅ Builds successfully\n   - ✅ Follows our code style guide\n   - ✅ Includes tests for new features\n   - ✅ Updates documentation if needed\n\n### Review Process\n\n1. **Automated checks** will run on your PR\n2. **Maintainers** will review your code\n3. **Address feedback** by pushing new commits to your branch\n4. **Merge** happens after approval from maintainers\n\n## 🎯 Contribution Guidelines\n\n### What We're Looking For\n\n- **Bug fixes** with clear reproduction steps\n- **New features** that align with the project's goals\n- **Performance improvements** with benchmarks\n- **Accessibility improvements** following WCAG guidelines\n- **Documentation** improvements and translations\n- **Test coverage** improvements\n\n### Areas That Need Help\n\n- 🌍 **Internationalization** (i18n) support\n- 📱 **Mobile experience** improvements\n- ♿ **Accessibility** enhancements\n- 🎨 **UI/UX** improvements\n- 🧪 **Test coverage** expansion\n- 📚 **Documentation** improvements\n- 🔧 **Developer experience** tools\n\n### Component Development\n\nWhen creating new components:\n\n```tsx\n// Follow this structure for new components\ninterface ComponentProps {\n  // Define clear prop types\n  title: string;\n  onAction?: () => void;\n  variant?: 'primary' | 'secondary';\n}\n\nexport const Component = ({ title, onAction, variant = 'primary' }: ComponentProps) => {\n  // Component logic here\n\n  return <div className=\"component-styles\">{/* JSX here */}</div>;\n};\n```\n\n### File Organization\n\n```\nsrc/\n├── app/                 # Next.js app directory\n├── components/          # Reusable UI components\n│   ├── forms/          # Form-related components\n│   ├── layout/         # Layout components\n│   ├── sections/       # Page sections\n│   └── ui/             # Basic UI components\n├── hooks/              # Custom React hooks\n├── lib/                # Utility functions and configurations\n├── types/              # TypeScript type definitions\n└── constants/          # Application constants\n```\n\n## 🐛 Reporting Bugs\n\nWhen reporting bugs, please include:\n\n1. **Steps to reproduce** the bug\n2. **Expected behavior** vs actual behavior\n3. **Screenshots** or screen recordings if applicable\n4. **Browser/OS information**\n5. **Console errors** if any\n\nUse our [bug report template](https://github.com/rahuldkjain/github-profile-readme-generator/issues/new/choose) for consistency.\n\n## 💡 Suggesting Features\n\nFor feature requests:\n\n1. **Check existing issues** to avoid duplicates\n2. **Describe the problem** you're trying to solve\n3. **Propose a solution** with examples\n4. **Consider the impact** on existing users\n5. **Be open to discussion** and alternative approaches\n\n## 🏷️ Issue Labels\n\nWe use labels to organize issues:\n\n- `bug` - Something isn't working\n- `enhancement` - New feature or request\n- `good first issue` - Good for newcomers\n- `help wanted` - Extra attention is needed\n- `documentation` - Improvements to docs\n- `accessibility` - A11y improvements\n- `performance` - Performance improvements\n\n## 📋 Code Review Checklist\n\nBefore requesting review, ensure:\n\n- [ ] Code follows our style guide\n- [ ] All tests pass locally\n- [ ] TypeScript compiles without errors\n- [ ] ESLint passes without warnings\n- [ ] Component is accessible (proper ARIA labels, keyboard navigation)\n- [ ] Mobile-responsive design\n- [ ] Performance considerations addressed\n- [ ] Documentation updated if needed\n- [ ] Commit messages are clear and descriptive\n\n## 🎉 Recognition\n\nContributors are recognized in:\n\n- **README.md** contributors section\n- **All Contributors** bot for automated recognition\n- **Release notes** for significant contributions\n- **Discord community** shoutouts\n\n## 📞 Getting Help\n\n- **Discord**: [Join our community](https://discord.gg/HHMs7Eg)\n- **Issues**: [GitHub Issues](https://github.com/rahuldkjain/github-profile-readme-generator/issues)\n- **Discussions**: [GitHub Discussions](https://github.com/rahuldkjain/github-profile-readme-generator/discussions)\n\n## 📄 License\n\nBy contributing, you agree that your contributions will be licensed under the same license as the project (MIT License).\n\n---\n\nThank you for contributing to GitHub Profile README Generator! 🚀\n"
  },
  {
    "path": "DEPLOYMENT.md",
    "content": "# 🚀 Production Deployment Guide\n\n## Pre-Deployment Checklist\n\n### ✅ SEO & Performance\n\n- [x] **Meta Tags**: Complete Open Graph and Twitter Card metadata\n- [x] **Structured Data**: JSON-LD schema for better search visibility\n- [x] **Canonical URLs**: Proper canonical URLs for all pages\n- [x] **Sitemap**: Auto-generated XML sitemap at `/sitemap.xml`\n- [x] **Robots.txt**: SEO-friendly robots.txt configuration\n- [x] **PWA Manifest**: Mobile app-like experience with manifest.json\n\n### ✅ Assets & Performance\n\n- [x] **Static Assets**: All assets properly placed in `/public` directory\n- [x] **Image Optimization**: OG image and favicon configured\n- [x] **Bundle Optimization**: Turbopack enabled for faster builds\n- [x] **CSS Optimization**: Tailwind CSS optimized for production\n- [x] **Font Loading**: Local fonts with proper fallbacks\n\n### ✅ Analytics & Tracking\n\n- [x] **Google Analytics**: GA4 integration with environment variable\n- [x] **Buy Me Coffee**: Widget properly integrated\n- [x] **Error Tracking**: Console error handling\n\n## Environment Configuration\n\n### 1. Create Environment File\n\n```bash\ncp .env.example .env.local\n```\n\n### 2. Configure Analytics & Privacy\n\n```env\n# Required for production analytics\nNEXT_PUBLIC_GA_ID=G-XXXXXXXXXX\n\n# Optional: Google Search Console verification\nNEXT_PUBLIC_GOOGLE_SITE_VERIFICATION=your-verification-code\n\n# Privacy & GDPR Compliance (recommended)\nNEXT_PUBLIC_REQUIRE_CONSENT=true\nNEXT_PUBLIC_ANONYMIZE_IP=true\n```\n\n**GA4 Setup Instructions:**\n\n1. Create a GA4 property in Google Analytics\n2. Copy your Measurement ID (format: G-XXXXXXXXXX)\n3. Add it to your environment variables\n4. The app includes GDPR-compliant consent management\n5. Custom events track: GitHub auto-fill, README completion, file exports\n\n## Build & Deploy\n\n### GitHub Pages Deployment\n\n```bash\n# Build for production\nnpm run build\n\n# The built files will be in the 'out' directory\n# GitHub Pages will automatically serve from this directory\n```\n\n### Custom Domain Deployment\n\n1. Update the base URL in `next.config.ts`\n2. Update URLs in `src/app/layout.tsx` metadata\n3. Update sitemap and robots.txt URLs\n\n## Performance Metrics\n\n### Bundle Analysis\n\n- **Main Bundle**: ~282 kB (optimized)\n- **First Load JS**: ~174 kB shared\n- **Build Time**: ~3.2s with Turbopack\n\n### SEO Score\n\n- **Structured Data**: ✅ Complete\n- **Meta Tags**: ✅ All pages covered\n- **Performance**: ✅ Optimized bundles\n- **Accessibility**: ✅ ARIA labels and semantic HTML\n- **PWA**: ✅ Manifest and service worker ready\n\n## Post-Deployment Verification\n\n### 1. SEO Tools\n\n- [ ] Test with [Google Rich Results Test](https://search.google.com/test/rich-results)\n- [ ] Verify with [Facebook Sharing Debugger](https://developers.facebook.com/tools/debug/)\n- [ ] Check with [Twitter Card Validator](https://cards-dev.twitter.com/validator)\n\n### 2. Performance Testing\n\n- [ ] Run [Google PageSpeed Insights](https://pagespeed.web.dev/)\n- [ ] Test with [GTmetrix](https://gtmetrix.com/)\n- [ ] Verify mobile responsiveness\n\n### 3. Functionality Testing\n\n- [ ] Test all form submissions\n- [ ] Verify GitHub API integration\n- [ ] Check markdown generation\n- [ ] Test theme switching\n- [ ] Verify analytics tracking\n\n## Monitoring\n\n### Analytics Setup\n\n1. **Google Analytics**: Monitor user engagement and conversion\n2. **Search Console**: Track search performance and indexing\n3. **Error Monitoring**: Monitor console errors and user issues\n\n### Key Metrics to Track\n\n- **Page Load Speed**: < 3 seconds\n- **Core Web Vitals**: LCP, FID, CLS scores\n- **Conversion Rate**: README generation completion\n- **User Engagement**: Time on site, bounce rate\n\n## Troubleshooting\n\n### Common Issues\n\n1. **Build Failures**: Check Node.js version (18+)\n2. **Asset Loading**: Verify all assets are in `/public`\n3. **Analytics Not Working**: Check environment variables\n4. **SEO Issues**: Validate structured data and meta tags\n\n### Support\n\n- **Issues**: [GitHub Issues](https://github.com/rahuldkjain/github-profile-readme-generator/issues)\n- **Discussions**: [GitHub Discussions](https://github.com/rahuldkjain/github-profile-readme-generator/discussions)\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://rahuldkjain.github.io/github-profile-readme-generator\">\n    <img alt=\"GitHub Profile Readme Generator\" src=\"./src/images/mdg.png\" width=\"60\" />\n  </a>\n</p>\n<h1 align=\"center\">\n  GitHub Profile README Generator\n</h1>\n\n<p align=\"center\">\n<a href=\"https://github.com/rahuldkjain/github-profile-readme-generator/blob/master/LICENSE\" target=\"blank\">\n<img src=\"https://img.shields.io/github/license/rahuldkjain/github-profile-readme-generator?style=flat-square\" alt=\"github-profile-readme-generator license\" />\n</a>\n<a href=\"https://github.com/rahuldkjain/github-profile-readme-generator/fork\" target=\"blank\">\n<img src=\"https://img.shields.io/github/forks/rahuldkjain/github-profile-readme-generator?style=flat-square\" alt=\"github-profile-readme-generator forks\"/>\n</a>\n<a href=\"https://github.com/rahuldkjain/github-profile-readme-generator/stargazers\" target=\"blank\">\n<img src=\"https://img.shields.io/github/stars/rahuldkjain/github-profile-readme-generator?style=flat-square\" alt=\"github-profile-readme-generator stars\"/>\n</a>\n<a href=\"https://github.com/rahuldkjain/github-profile-readme-generator/issues\" target=\"blank\">\n<img src=\"https://img.shields.io/github/issues/rahuldkjain/github-profile-readme-generator?style=flat-square\" alt=\"github-profile-readme-generator issues\"/>\n</a>\n<a href=\"https://github.com/rahuldkjain/github-profile-readme-generator/pulls\" target=\"blank\">\n<img src=\"https://img.shields.io/github/issues-pr/rahuldkjain/github-profile-readme-generator?style=flat-square\" alt=\"github-profile-readme-generator pull-requests\"/>\n</a>\n<a href=\"https://discord.gg/HHMs7Eg\" target=\"blank\">\n<img src=\"https://img.shields.io/discord/735303195105951764?label=Join%20Community&logo=discord&style=flat-square\" alt=\"join discord community of github profile readme generator\"/>\n</a>\n</p>\n\n<p align=\"center\"><img src=\"/public/demo.gif\" alt=\"github-profile-readme-generator gif\" /></p>\n\n<p align=\"center\">\n    <a href=\"https://rahuldkjain.github.io/github-profile-readme-generator\" target=\"blank\">View Demo</a>\n    ·\n    <a href=\"https://github.com/rahuldkjain/github-profile-readme-generator/issues/new/choose\">Report Bug</a>\n    ·\n    <a href=\"https://github.com/rahuldkjain/github-profile-readme-generator/issues/new/choose\">Request Feature</a>\n</p>\n\n<p align=\"center\">\n<i>Loved the tool? Please consider <a href=\"https://paypal.me/rahuldkjain/10\">donating</a>  💸 to help it improve!</i>\n</p>\n\n<p align=\"center\">\n<a href=\"https://www.paypal.me/rahuldkjain\"><img src=\"https://img.shields.io/badge/support-PayPal-blue?logo=PayPal&style=flat-square&label=Donate\" alt=\"sponsor github profile readme generator\"/>\n</a>\n<a href='https://ko-fi.com/A0A81XXSX' target='_blank'><img height='23' width=\"100\" src='https://cdn.ko-fi.com/cdn/kofi3.png?v=2' alt='Buy Coffee for rahuldkjain' />\n</a>\n<a href=\"https://www.buymeacoffee.com/rahuldkjain\" target=\"_blank\"><img src=\"https://cdn.buymeacoffee.com/buttons/default-orange.png\" alt=\"Buy Me A Coffee\" height=\"23\" width=\"100\" style=\"border-radius:1px\" />\n</p>\n\n#### Tired of editing GitHub Profile README with new features?\n\nThis tool provides an easy way to create a GitHub profile readme with the latest add-ons such as `visitors count`, `github stats`, etc.\n\n## 🚀 Demo\n\n<a href=\"https://rahuldkjain.github.io/github-profile-readme-generator\" target=\"blank\">\n<img src=\"https://img.shields.io/website?url=https%3A%2F%2Frahuldkjain.github.io%2Fgithub-profile-readme-generator&logo=github&style=flat-square\" />\n</a>\n\nTry the tool: [GitHub Profile README Generator](https://rahuldkjain.github.io/github-profile-readme-generator)\n\n## 🧐 Features\n\nJust fill in the details such as `Name`, `Tagline`, `Dev Platforms Username`, `Current Work`, `Portfolio`, `Blog`, etc. with a minimal UI.\n\n- **Uniform Dev Icons**\n\n- **Uniform Social Icons**\n\n- **Visitors Counter Badge**\n\n- **GitHub Profile Stats Card**\n\n- **GitHub Top Skills**\n\n- **GitHub Streak Stats**\n\n- **Dynamic Dev(.)to Blogs** (GitHub Action)\n\n- **Dynamic Medium Blogs** (GitHub Action)\n\n- **Dynamic Personal Blogs from RSS Feed** (GitHub Action)\n\n- **Wakatime Stats** [contribute](https://github.com/rahuldkjain/github-profile-readme-generator/issues/115)\n\n- **Buy Me A Coffee button**\n\nClick on `Generate README` to get your README in `markdown`.\nYou can preview the README too.\n\n## 🛠️ Installation Steps\n\n1. Clone the repository\n\n```bash\ngit clone https://github.com/rahuldkjain/github-profile-readme-generator.git\n```\n\n2. Change the working directory\n\n```bash\ncd github-profile-readme-generator\n```\n\n3. Install dependencies\n\n```bash\nnpm install\n```\n\n4. Run the app\n\n```bash\nnpm run dev\n```\n\n🌟 You are all set!\n\n## 🍰 Contributing\n\nPlease contribute using [GitHub Flow](https://guides.github.com/introduction/flow). Create a branch, add commits, and [open a pull request](https://github.com/rahuldkjain/github-profile-readme-generator/compare).\n\nPlease read [`CONTRIBUTING`](CONTRIBUTING.md) for details on our [`CODE OF CONDUCT`](CODE_OF_CONDUCT.md), and the process for submitting pull requests to us.\n\n## 💻 Built with\n\n- [Next.js 15](https://nextjs.org/) - React framework with App Router\n- [TypeScript](https://www.typescriptlang.org/) - Type safety and better DX\n- [Tailwind CSS](https://tailwindcss.com/) - Utility-first CSS framework\n- [Framer Motion](https://www.framer.com/motion/) - Production-ready motion library\n- [Lucide React](https://lucide.dev/) - Beautiful & consistent icons\n- [React Hook Form](https://react-hook-form.com/) - Performant forms with easy validation\n\n## 🙇 Special Thanks\n\n- [Anurag Hazra](https://github.com/anuraghazra) for amazing [github-readme-stats](https://github.com/anuraghazra/github-readme-stats)\n- [Anton Komarev](https://github.com/antonkomarev) for super cool [github-profile-views-counter](https://github.com/antonkomarev/github-profile-views-counter)\n- [Gautam Krishna R](https://github.com/gautamkrishnar) for the awesome [blog post workflow](https://github.com/gautamkrishnar/blog-post-workflow)\n- [Jonah Lawrence](https://github.com/DenverCoder1) for the incredible [github-readme-streak-stats](https://github.com/DenverCoder1/github-readme-streak-stats)\n- [Julien Monty](https://github.com/konpa) for super useful [devicon](https://github.com/konpa/devicon)\n- [Eliot Sanford](https://github.com/techieeliot) for adding hashnode as a blog input\n\n## 🙇 Sponsors\n\n- [Scott C Wilson](https://github.com/scottcwilson) donated the first-ever grant to this tool. A big thanks to him.\n- [Max Schmitt](https://github.com/mxschmitt) loved the tool and showed support with his donation. Thanks a lot.\n- [Aadit Kamat](https://github.com/aaditkamat) find the tool useful and showed support with his donation. A big thanks to him.\n- [Jean-Michel Fayard](https://github.com/jmfayard) used the generator to create his GitHub Profile README and he loved it. Thanks to him for showing support to the tool with the donation.\n\n## 🔒 Privacy & Analytics\n\nThis tool includes privacy-friendly analytics to help improve the user experience:\n\n- **Google Analytics 4** with GDPR-compliant consent management\n- **IP anonymization** and privacy-first configuration\n- **Custom events** tracking for GitHub auto-fill, README generation, and exports\n- **Cookie consent banner** - users can opt-out anytime\n- **No personal data** collection - only anonymous usage patterns\n\n\n## 📄 Font Licensing\n\nThis project uses the **Wotfard** font family:\n\n- **Font**: Wotfard Regular\n- **Usage**: This font is used under fair use for open source projects\n- **Source**: Downloaded from online typography resources\n- **Note**: If you're the font creator and have concerns about usage, please [contact us](mailto:rahuldkjain@gmail.com)\n\nFor commercial use of this project, please verify font licensing requirements.\n\n## 🙏 Support\n\n<p align=\"left\">\n<a href=\"https://www.paypal.me/rahuldkjain/10\"><img src=\"https://ionicabizau.github.io/badges/paypal.svg\" alt=\"sponsor github profile readme generator\"/>\n</a>\n<a href=\"https://twitter.com/intent/tweet?text=Wow:&url=https%3A%2F%2Frahuldkjain.github.io%2Fgithub-profile-readme-generator\">\n<img src=\"https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Frahuldkjain.github.io%2Fgithub-profile-readme-generator\" alt=\"tweet github profile readme generator\"/>\n</a>\n</p>\n\n<p align=\"left\">\n  <a href='https://ko-fi.com/A0A81XXSX' target='_blank'><img height='23' width=\"100\" src='https://cdn.ko-fi.com/cdn/kofi3.png?v=2' alt='Buy Coffee for rahuldkjain' />\n  </a>\n  <a href=\"https://www.buymeacoffee.com/rahuldkjain\" target=\"_blank\"><img src=\"https://cdn.buymeacoffee.com/buttons/default-orange.png\" alt=\"Buy Me A Coffee\" height=\"23\" width=\"100\" style=\"border-radius:2px\" />\n</p>\n\n## 🌟 Star History\n<picture>\n  <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://api.star-history.com/svg?repos=rahuldkjain/github-profile-readme-generator&type=Date&theme=dark\" />\n  <source media=\"(prefers-color-scheme: light)\" srcset=\"https://api.star-history.com/svg?repos=rahuldkjain/github-profile-readme-generator&type=Date\" />\n  <img alt=\"GPRG Star History Chart\" src=\"https://api.star-history.com/svg?repos=rahuldkjain/github-profile-readme-generator&type=Date\" />\n</picture>\n\n<hr>\n<p align=\"center\">\nDeveloped with ❤️ in India 🇮🇳 \n</p>\n"
  },
  {
    "path": "env.example",
    "content": "# GitHub Profile README Generator - Environment Configuration\n\n# Google Analytics 4 Configuration\n# Get your GA4 Measurement ID from Google Analytics\n# Format: G-XXXXXXXXXX\nNEXT_PUBLIC_GA_ID=G-XXXXXXXXXX\n\n# Optional: Google Search Console Verification\n# Get this from Google Search Console -> Settings -> Ownership verification\nNEXT_PUBLIC_GOOGLE_SITE_VERIFICATION=your-verification-code\n\n# Privacy & GDPR Compliance\n# Set to 'true' to require explicit consent before loading analytics\n# Set to 'false' to load analytics by default (not GDPR compliant)\nNEXT_PUBLIC_REQUIRE_CONSENT=true\n\n# Analytics Configuration\n# Set to 'true' to anonymize IP addresses (recommended for privacy)\nNEXT_PUBLIC_ANONYMIZE_IP=true\n\n# Development Configuration\n# Set to 'development' to disable analytics in development mode\nNODE_ENV=development\n\n# Optional: Custom Domain Configuration\n# Update if deploying to a custom domain\nNEXT_PUBLIC_SITE_URL=https://your-domain.com\n"
  },
  {
    "path": "eslint.config.mjs",
    "content": "import { dirname } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { FlatCompat } from \"@eslint/eslintrc\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nconst compat = new FlatCompat({\n  baseDirectory: __dirname,\n});\n\nconst eslintConfig = [\n  ...compat.extends(\"next/core-web-vitals\", \"next/typescript\", \"prettier\"),\n  {\n    ignores: [\n      \"node_modules/**\",\n      \".next/**\",\n      \"out/**\",\n      \"build/**\",\n      \"dist/**\",\n      \"coverage/**\",\n      \"*.config.js\",\n      \"*.config.ts\",\n      \"next-env.d.ts\",\n      \"old-gatsby-backup/**\",\n    ],\n  },\n  {\n    rules: {\n      \"@typescript-eslint/no-unused-vars\": [\n        \"warn\",\n        {\n          argsIgnorePattern: \"^_\",\n          varsIgnorePattern: \"^_\",\n        },\n      ],\n      \"@typescript-eslint/no-explicit-any\": \"warn\",\n      \"react/no-unescaped-entities\": \"off\",\n      \"react-hooks/exhaustive-deps\": \"warn\",\n    },\n  },\n];\n\nexport default eslintConfig;\n"
  },
  {
    "path": "next.config.ts",
    "content": "import type { NextConfig } from 'next';\nimport { PHASE_PRODUCTION_BUILD } from 'next/constants';\n\nconst nextConfig = (phase: string): NextConfig => {\n  // Determine if we should use basePath (production build, not Surge preview)\n  const isProductionBuild = phase === PHASE_PRODUCTION_BUILD;\n  const isSurgePreview = process.env.SURGE_PREVIEW === 'true';\n  const shouldUseBasePath = isProductionBuild && !isSurgePreview;\n  const basePath = shouldUseBasePath ? '/github-profile-readme-generator' : '';\n\n  return {\n    // Output as static site for GitHub Pages\n    output: 'export',\n\n    // Base path for GitHub Pages (only for production builds, not Surge previews)\n    basePath,\n\n    // Asset prefix to ensure all assets use the correct path\n    assetPrefix: shouldUseBasePath ? '/github-profile-readme-generator/' : '',\n\n    // Environment variables\n    env: {\n      NEXT_PUBLIC_BASE_PATH: basePath,\n    },\n\n    // Image optimization for static export\n    images: {\n      unoptimized: true, // Required for static export\n    },\n\n    // Trailing slashes for better compatibility\n    trailingSlash: true,\n\n    // Enable strict mode for better error catching\n    reactStrictMode: true,\n\n    // Enable experimental features for better performance\n    experimental: {\n      // Optimize CSS\n      optimizeCss: true,\n      // Enable optimized package imports for heavy libraries\n      optimizePackageImports: [\n        'framer-motion',\n        '@hookform/resolvers',\n        'react-markdown',\n        'remark-gfm',\n        'rehype-raw',\n        'rehype-sanitize',\n        'zod',\n        'zustand',\n        'lucide-react',\n        '@headlessui/react',\n      ],\n    },\n\n    // Compiler options for better performance\n    compiler: {\n      // Remove console.log in production\n      removeConsole: isProductionBuild ? { exclude: ['error', 'warn'] } : false,\n      // Enable React compiler optimizations\n      reactRemoveProperties: isProductionBuild,\n    },\n\n    // Optimize transpilation\n    transpilePackages: ['react-markdown', 'remark-gfm', 'rehype-raw', 'rehype-sanitize'],\n\n    // Turbopack configuration (replaces webpack config)\n    turbopack: {\n      // Enable faster module resolution\n      resolveAlias: {\n        // Optimize common imports\n        '@': './src',\n      },\n    },\n\n    // Webpack optimizations for development (only when not using Turbopack)\n    webpack: (config, { dev, isServer }) => {\n      if (dev && !isServer && !process.env.TURBOPACK) {\n        // Optimize development builds\n        config.optimization = {\n          ...config.optimization,\n          splitChunks: {\n            chunks: 'all',\n            cacheGroups: {\n              vendor: {\n                test: /[\\\\/]node_modules[\\\\/]/,\n                name: 'vendors',\n                chunks: 'all',\n                priority: 10,\n              },\n              markdown: {\n                test: /[\\\\/]node_modules[\\\\/](react-markdown|remark-|rehype-)/,\n                name: 'markdown',\n                chunks: 'all',\n                priority: 20,\n              },\n            },\n          },\n        };\n\n        // Enable faster rebuilds\n        config.cache = {\n          type: 'filesystem',\n          buildDependencies: {\n            config: [__filename],\n          },\n        };\n      }\n\n      return config;\n    },\n  };\n};\n\nexport default nextConfig;\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"github-profile-readme-generator\",\n  \"version\": \"2.0.0\",\n  \"description\": \"Generate GitHub profile README easily with the latest add-ons like visitors count, GitHub stats, etc using minimal UI\",\n  \"private\": true,\n  \"author\": \"Rahul Jain <rahuldkjain@gmail.com>\",\n  \"scripts\": {\n    \"dev\": \"TURBOPACK=1 next dev --turbo\",\n    \"build\": \"next build --turbo\",\n    \"export\": \"next build --turbo\",\n    \"start\": \"next start\",\n    \"type-check\": \"tsc --noEmit\",\n    \"lint\": \"eslint\",\n    \"format\": \"prettier --write \\\"src/**/*.{ts,tsx,js,jsx,json,css,md}\\\"\",\n    \"format:check\": \"prettier --check \\\"src/**/*.{ts,tsx,js,jsx,json,css,md}\\\"\",\n    \"test\": \"vitest\",\n    \"test:ui\": \"vitest --ui\",\n    \"test:coverage\": \"vitest --coverage\"\n  },\n  \"dependencies\": {\n    \"@headlessui/react\": \"^2.2.9\",\n    \"@hookform/resolvers\": \"^5.2.2\",\n    \"@next/third-parties\": \"^15.5.4\",\n    \"@tailwindcss/typography\": \"^0.5.19\",\n    \"critters\": \"^0.0.23\",\n    \"framer-motion\": \"^12.23.24\",\n    \"lucide-react\": \"^0.545.0\",\n    \"next\": \"15.5.4\",\n    \"react\": \"19.1.0\",\n    \"react-dom\": \"19.1.0\",\n    \"react-hook-form\": \"^7.65.0\",\n    \"react-markdown\": \"^10.1.0\",\n    \"rehype-raw\": \"^7.0.0\",\n    \"rehype-sanitize\": \"^6.0.0\",\n    \"remark-gfm\": \"^4.0.1\",\n    \"zod\": \"^4.1.12\",\n    \"zustand\": \"^5.0.8\"\n  },\n  \"devDependencies\": {\n    \"@eslint/eslintrc\": \"^3\",\n    \"@tailwindcss/postcss\": \"^4\",\n    \"@testing-library/jest-dom\": \"^6.9.1\",\n    \"@testing-library/react\": \"^16.3.0\",\n    \"@testing-library/user-event\": \"^14.6.1\",\n    \"@types/node\": \"^20\",\n    \"@types/react\": \"^19\",\n    \"@types/react-dom\": \"^19\",\n    \"@vitejs/plugin-react\": \"^5.0.4\",\n    \"eslint\": \"^9\",\n    \"eslint-config-next\": \"15.5.4\",\n    \"eslint-config-prettier\": \"^10.1.8\",\n    \"jsdom\": \"^27.0.0\",\n    \"prettier\": \"^3.6.2\",\n    \"prettier-plugin-tailwindcss\": \"^0.6.14\",\n    \"tailwindcss\": \"^4\",\n    \"typescript\": \"^5\",\n    \"vitest\": \"^3.2.4\"\n  }\n}\n"
  },
  {
    "path": "postcss.config.mjs",
    "content": "const config = {\n  plugins: [\"@tailwindcss/postcss\"],\n};\n\nexport default config;\n"
  },
  {
    "path": "public/manifest.json",
    "content": "{\n  \"name\": \"GitHub Profile README Generator\",\n  \"short_name\": \"GitHub README Gen\",\n  \"description\": \"Create amazing GitHub profile READMEs in seconds with customizable templates and easy-to-use interface\",\n  \"start_url\": \"./\",\n  \"display\": \"standalone\",\n  \"background_color\": \"#ffffff\",\n  \"theme_color\": \"#000000\",\n  \"orientation\": \"portrait-primary\",\n  \"icons\": [\n    {\n      \"src\": \"/mdg.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image/png\",\n      \"purpose\": \"maskable any\"\n    },\n    {\n      \"src\": \"/mdg.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image/png\",\n      \"purpose\": \"maskable any\"\n    }\n  ],\n  \"categories\": [\"developer\", \"productivity\", \"utilities\"],\n  \"lang\": \"en\",\n  \"dir\": \"ltr\",\n  \"scope\": \"./\",\n  \"prefer_related_applications\": false\n}\n"
  },
  {
    "path": "public/robots.txt",
    "content": "# https://www.robotstxt.org/robotstxt.html\nUser-agent: *\nAllow: /\n\n# Host\nHost: https://rahuldkjain.github.io\n\n# Sitemaps\nSitemap: https://rahuldkjain.github.io/gh-profile-readme-generator/sitemap.xml\n"
  },
  {
    "path": "setupTests.js",
    "content": "import { configure } from 'enzyme';\nimport Adapter from 'enzyme-adapter-react-16';\n\nconfigure({ adapter: new Adapter() });\n"
  },
  {
    "path": "src/app/about/page.tsx",
    "content": "import { Header } from '@/components/layout/header';\nimport { Footer } from '@/components/layout/footer';\nimport type { Metadata } from 'next';\nimport Image from 'next/image';\n\nexport const metadata: Metadata = {\n  title: 'About',\n  description:\n    'Learn about GitHub Profile README Generator - an open-source tool for creating awesome GitHub profile READMEs with customizable templates, skills showcase, and social links integration.',\n  alternates: {\n    canonical: '/about',\n  },\n  openGraph: {\n    title: 'About | GitHub Profile README Generator',\n    description:\n      'Learn about GitHub Profile README Generator - an open-source tool for creating awesome GitHub profile READMEs',\n    url: '/about',\n  },\n};\n\nexport default function AboutPage() {\n  return (\n    <div className=\"flex min-h-screen flex-col\">\n      <Header />\n\n      <main className=\"container mx-auto flex-1 px-4 py-12\">\n        <div className=\"page-content mx-auto max-w-4xl\">\n          <h1 className=\"mb-6 text-4xl font-bold\">👨‍💻 About</h1>\n\n          <div className=\"mb-8 flex gap-2\">\n            <a\n              href=\"https://github.com/rahuldkjain/github-profile-readme-generator/blob/master/LICENSE\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n            >\n              <Image\n                src=\"https://img.shields.io/github/license/rahuldkjain/github-profile-readme-generator?style=flat-square\"\n                alt=\"github-profile-readme-generator license\"\n                width={100}\n                height={100}\n              />\n            </a>\n          </div>\n\n          <p className=\"text-lg\">\n            <strong>GitHub Profile README Generator</strong> is an OSS (Open Source Software) that\n            provides a cool interface to generate GitHub profile README in markdown.\n          </p>\n\n          <p>\n            The tool aims to provide hassle-free experience to add trending addons like profile{' '}\n            <strong>visitors count</strong>, <strong>github-stats</strong>,{' '}\n            <strong>dynamic blog posts</strong> etc.\n          </p>\n\n          <p>\n            The profile should be neat and minimal to give a clear overview of the work. Non-uniform\n            icons, too much content, too much images/gifs distracts visitors to see your actual\n            work.\n          </p>\n\n          <p>To solve this, GitHub Profile README Generator came into existence.</p>\n\n          <p>\n            So many developers contributed to the project and made it more awesome to use. You can\n            contribute too to make it grow even further.\n          </p>\n\n          <div className=\"my-6 flex gap-3\">\n            <a\n              href=\"https://github.com/rahuldkjain/github-profile-readme-generator/issues\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n            >\n              <Image\n                src=\"https://img.shields.io/github/issues/rahuldkjain/github-profile-readme-generator?style=flat-square\"\n                alt=\"github-profile-readme-generator issues\"\n                width={100}\n                height={100}\n              />\n            </a>\n            <a\n              href=\"https://github.com/rahuldkjain/github-profile-readme-generator/pulls\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n            >\n              <Image\n                src=\"https://img.shields.io/github/issues-pr/rahuldkjain/github-profile-readme-generator?style=flat-square\"\n                alt=\"github-profile-readme-generator pull-requests\"\n                width={130}\n                height={130}\n              />\n            </a>\n          </div>\n\n          <h3 className=\"mt-8 mb-4 text-2xl font-bold\">Contributors 🙏</h3>\n\n          <p>List of the developers who contributed to the project. A big shout out for them.</p>\n\n          <a\n            href=\"https://github.com/rahuldkjain/github-profile-readme-generator/graphs/contributors\"\n            target=\"_blank\"\n            rel=\"noopener noreferrer\"\n          >\n            <Image\n              src=\"https://contributors-img.web.app/image?repo=rahuldkjain/github-profile-readme-generator\"\n              alt=\"Contributors\"\n              className=\"my-4\"\n              width={600}\n              height={600}\n            />\n          </a>\n\n          <hr className=\"my-8\" />\n\n          <h2 className=\"mb-4 text-3xl font-bold\">How do I create a profile README?</h2>\n\n          <p>\n            The profile README is created by creating a new repository that's the same name as your\n            username. For example, my GitHub username is <strong>rahuldkjain</strong> so I created a\n            new repository with the name <strong>rahuldkjain</strong>. Note: at the time of this\n            writing, in order to access the profile README feature, the letter-casing must match\n            your GitHub username.\n          </p>\n\n          <ol className=\"list-decimal space-y-3 pl-6\">\n            <li>\n              Create a new repository with the same name (including casing) as your GitHub username:{' '}\n              <a\n                href=\"https://github.com/new\"\n                target=\"_blank\"\n                rel=\"noopener noreferrer\"\n                className=\"text-primary hover:underline\"\n              >\n                https://github.com/new\n              </a>\n            </li>\n            <li>\n              Create a README.md file inside the new repo with content (text, GIFs, images, emojis,\n              etc.)\n            </li>\n            <li>\n              Commit your fancy new README! If you're on GitHub's web interface you can choose to\n              commit directly to the repo's main branch (i.e., master or main) which will make it\n              immediately visible on your profile\n            </li>\n            <li>\n              Push changes to GitHub (if you made changes locally i.e., on your computer and not\n              github.com)\n            </li>\n          </ol>\n\n          <hr className=\"my-8\" />\n\n          <h2 className=\"mb-4 text-3xl font-bold\">How to use?</h2>\n\n          <p>\n            Tired of editing profile README(.md) to add new features like visitors-count badge,\n            github-stats etc?\n          </p>\n\n          <p>Don't worry. Keep calm, fill the form and let the tool do the work for you</p>\n\n          <Image\n            src=\"https://raw.githubusercontent.com/rahuldkjain/github-profile-readme-generator/master/src/images/github-profile-readme-generator.gif\"\n            alt=\"github profile readme generator\"\n            width=\"320\"\n            height={100}\n            className=\"my-6\"\n          />\n\n          <hr className=\"my-8\" />\n\n          <h2 className=\"mb-4 text-3xl font-bold\">Why visitors count keeps on increasing?</h2>\n\n          <p>\n            So many users raised an issue that the counter keeps on increasing everytime the page\n            reloads.\n          </p>\n\n          <p>\n            Well it is visitors count not \"unique\" visitors count. The goal of the addon is to\n            provide a good stat of how well the github profile is doing.\n          </p>\n\n          <p>\n            Proper use or misuse of the addon is the sole responsibility of the user. The developer\n            of the addon is working on it to fix this issue.\n          </p>\n        </div>\n      </main>\n\n      <Footer />\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/app/addons/page.tsx",
    "content": "import { Header } from '@/components/layout/header';\nimport { Footer } from '@/components/layout/footer';\nimport type { Metadata } from 'next';\n\nexport const metadata: Metadata = {\n  title: 'Addons',\n  description:\n    'Discover the awesome open-source addons and tools used in GitHub Profile README Generator. Explore the technology stack and libraries that power this amazing tool.',\n  alternates: {\n    canonical: '/addons',\n  },\n  openGraph: {\n    title: 'Addons | GitHub Profile README Generator',\n    description:\n      'Discover the awesome open-source addons and tools used in GitHub Profile README Generator',\n    url: '/addons',\n  },\n};\n\nexport default function AddonsPage() {\n  return (\n    <div className=\"flex min-h-screen flex-col\">\n      <Header />\n\n      <main className=\"container mx-auto flex-1 px-4 py-12\">\n        <div className=\"page-content mx-auto max-w-4xl\">\n          <h1 className=\"mb-6 text-4xl font-bold\">🚀 Addons</h1>\n\n          <p className=\"text-lg\">\n            GitHub Profile README Generator tool uses few open-source addons developed by other\n            developers. Including such features makes the tool useful. The developers of this tool\n            is very grateful to use these awesome addons.\n          </p>\n\n          <hr className=\"my-8\" />\n\n          <h2 className=\"text-3xl font-bold\">\n            <a\n              href=\"https://github.com/anuraghazra/github-readme-stats\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              className=\"text-primary hover:underline\"\n            >\n              GitHub README Stats\n            </a>\n          </h2>\n\n          <p>⚡️ Dynamically generated stats for your github readmes</p>\n\n          <h4 className=\"mt-6 mb-3 text-xl font-semibold\">GitHub Stats Card</h4>\n\n          <a href=\"https://github.com/rahuldkjain\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <img\n              src=\"https://github-readme-stats.vercel.app/api?username=rahuldkjain&show_icons=true\"\n              width=\"320\"\n              alt=\"Rahul's github stats\"\n            />\n          </a>\n\n          <h4 className=\"mt-6 mb-3 text-xl font-semibold\">Top Skills Card</h4>\n\n          <a href=\"https://github.com/rahuldkjain\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <img\n              src=\"https://github-readme-stats.vercel.app/api/top-langs/?username=rahuldkjain&layout=compact&hide=html\"\n              width=\"320\"\n              alt=\"Rahul's github top skills\"\n            />\n          </a>\n\n          <p>\n            Developed by{' '}\n            <a\n              href=\"https://github.com/anuraghazra\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              className=\"text-primary hover:underline\"\n            >\n              Anurag Hazra\n            </a>\n            .\n          </p>\n\n          <p>\n            You can customize the theme too. See how to customize yours{' '}\n            <a\n              href=\"https://github.com/anuraghazra/github-readme-stats\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              className=\"text-primary hover:underline\"\n            >\n              here\n            </a>\n          </p>\n\n          <hr className=\"my-8\" />\n\n          <h2 className=\"text-3xl font-bold\">\n            <a\n              href=\"https://github.com/DenverCoder1/github-readme-streak-stats\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              className=\"text-primary hover:underline\"\n            >\n              GitHub Readme Streak Stats\n            </a>\n          </h2>\n\n          <p>\n            Stay motivated while contributing to open source by displaying your current contribution\n            streak\n          </p>\n\n          <img\n            src=\"https://github-readme-streak-stats.herokuapp.com/?user=rahuldkjain\"\n            alt=\"rahuldkjain\"\n            className=\"my-4\"\n          />\n\n          <p>\n            Developed by{' '}\n            <a\n              href=\"https://github.com/DenverCoder1\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              className=\"text-primary hover:underline\"\n            >\n              Jonah Lawrence\n            </a>\n            .\n          </p>\n\n          <p>\n            See how to customize the theme{' '}\n            <a\n              href=\"https://github.com/DenverCoder1/github-readme-streak-stats\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              className=\"text-primary hover:underline\"\n            >\n              here\n            </a>\n          </p>\n\n          <hr className=\"my-8\" />\n\n          <h2 className=\"text-3xl font-bold\">\n            <a\n              href=\"https://github.com/antonkomarev/github-profile-views-counter\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              className=\"text-primary hover:underline\"\n            >\n              GitHub Profile Views Counter\n            </a>\n          </h2>\n\n          <p>\n            It counts how many times your GitHub profile has been viewed. Free cloud micro-service.\n          </p>\n\n          <img\n            src=\"https://komarev.com/ghpvc/?username=rahuldkjain&style=flat-square\"\n            alt=\"rahuldkjain\"\n            className=\"my-4\"\n          />\n\n          <p>\n            Developed by{' '}\n            <a\n              href=\"https://github.com/antonkomarev\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              className=\"text-primary hover:underline\"\n            >\n              Anton Komarev\n            </a>\n            .\n          </p>\n\n          <p>\n            You can customize the color, label and style too. See how to customize{' '}\n            <a\n              href=\"https://github.com/antonkomarev/github-profile-views-counter\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              className=\"text-primary hover:underline\"\n            >\n              here\n            </a>\n          </p>\n\n          <hr className=\"my-8\" />\n\n          <h2 className=\"text-3xl font-bold\">\n            <a\n              href=\"https://github.com/gautamkrishnar/blog-post-workflow\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              className=\"text-primary hover:underline\"\n            >\n              Dynamic Latest Blog Posts\n            </a>\n          </h2>\n\n          <p>\n            Show your latest blog posts from any sources (like dev.to, medium etc) or StackOverflow\n            activity on your GitHub profile/project readme automatically using the RSS feed.\n          </p>\n\n          <img\n            src=\"https://user-images.githubusercontent.com/8397274/88047382-29b8b280-cb6f-11ea-9efb-2af2b10f3e0c.png\"\n            width=\"320\"\n            alt=\"dynamic latest blog example\"\n            className=\"my-4\"\n          />\n\n          <p>\n            Developed by{' '}\n            <a\n              href=\"https://github.com/gautamkrishnar\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              className=\"text-primary hover:underline\"\n            >\n              Gautam Krishna R\n            </a>\n          </p>\n\n          <h3 className=\"mt-6 mb-3 text-2xl font-semibold\">How to use</h3>\n\n          <ul className=\"list-disc space-y-3 pl-6\">\n            <li>Go to your repository</li>\n            <li>\n              Add the following section to your **README.md** file, you can give whatever title you\n              want. Just make sure that you use **&lt;!-- BLOG-POST-LIST:START --&gt;&lt;!--\n              BLOG-POST-LIST:END --&gt;** in your readme. The workflow will replace this comment\n              with the actual blog post list:\n            </li>\n          </ul>\n\n          <pre className=\"my-4 overflow-x-auto rounded-lg bg-slate-800 p-4 text-sm text-white dark:bg-slate-900\">\n            <code>{`# Blog posts\n\n<!-- BLOG-POST-LIST:START -->\n<!-- BLOG-POST-LIST:END -->`}</code>\n          </pre>\n\n          <ul className=\"list-disc space-y-3 pl-6\">\n            <li>\n              Create a folder named <code>.github</code> and create <code>workflows</code> folder\n              inside it if it doesn't exist.\n            </li>\n            <li>\n              Create a new file named <code>blog-post-workflow.yml</code> with the following\n              contents inside the workflows folder:\n            </li>\n          </ul>\n\n          <pre className=\"my-4 overflow-x-auto rounded-lg bg-slate-800 p-4 text-sm text-white dark:bg-slate-900\">\n            <code>{`name: Latest blog post workflow\non:\n  schedule:\n    # Runs every hour\n    - cron: '0 * * * *'\njobs:\n  update-readme-with-blog:\n    name: Update this repo's README with latest blog posts\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - uses: gautamkrishnar/blog-post-workflow@master\n        with:\n          feed_list: 'https://dev.to/feed/rahuldkjain, https://medium.com/feed/@rahuldkjain'`}</code>\n          </pre>\n\n          <ul className=\"list-disc space-y-3 pl-6\">\n            <li>Replace the above url list with your own rss feed urls.</li>\n            <li>Commit and wait for it to run</li>\n          </ul>\n\n          <p>\n            To know more, check out the{' '}\n            <a\n              href=\"https://github.com/gautamkrishnar/blog-post-workflow\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n              className=\"text-primary hover:underline\"\n            >\n              official github repository\n            </a>\n          </p>\n        </div>\n      </main>\n\n      <Footer />\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/app/globals.css",
    "content": "@import 'tailwindcss';\n@plugin '@tailwindcss/typography';\n\n/* Screen reader only utility */\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: -1px;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  white-space: nowrap;\n  border-width: 0;\n}\n\n:root {\n  /* Light mode colors */\n  --background: #ffffff;\n  --foreground: #171717;\n  --card: #f9fafb;\n  --card-foreground: #171717;\n  --primary: #2563eb;\n  --primary-foreground: #ffffff;\n  --secondary: #64748b;\n  --secondary-foreground: #ffffff;\n  --muted: #f1f5f9;\n  --muted-foreground: #64748b;\n  --accent: #f1f5f9;\n  --accent-foreground: #0f172a;\n  --destructive: #ef4444;\n  --destructive-foreground: #ffffff;\n  --border: #e2e8f0;\n  --input: #e2e8f0;\n  --ring: #2563eb;\n  --radius: 0.5rem;\n}\n\n@theme inline {\n  --color-background: var(--background);\n  --color-foreground: var(--foreground);\n  --color-card: var(--card);\n  --color-card-foreground: var(--card-foreground);\n  --color-primary: var(--primary);\n  --color-primary-foreground: var(--primary-foreground);\n  --color-secondary: var(--secondary);\n  --color-secondary-foreground: var(--secondary-foreground);\n  --color-muted: var(--muted);\n  --color-muted-foreground: var(--muted-foreground);\n  --color-accent: var(--accent);\n  --color-accent-foreground: var(--accent-foreground);\n  --color-destructive: var(--destructive);\n  --color-destructive-foreground: var(--destructive-foreground);\n  --color-border: var(--border);\n  --color-input: var(--input);\n  --color-ring: var(--ring);\n}\n\n@media (prefers-color-scheme: dark) {\n  :root {\n    /* Dark mode colors */\n    --background: #0a0a0a;\n    --foreground: #ededed;\n    --card: #171717;\n    --card-foreground: #ededed;\n    --primary: #3b82f6;\n    --primary-foreground: #ffffff;\n    --secondary: #94a3b8;\n    --secondary-foreground: #0f172a;\n    --muted: #1e293b;\n    --muted-foreground: #94a3b8;\n    --accent: #1e293b;\n    --accent-foreground: #f1f5f9;\n    --destructive: #dc2626;\n    --destructive-foreground: #ffffff;\n    --border: #1e293b;\n    --input: #1e293b;\n    --ring: #3b82f6;\n  }\n}\n\n/* Manual light mode class override (to override system preference) */\n.light {\n  --background: #ffffff;\n  --foreground: #171717;\n  --card: #f9fafb;\n  --card-foreground: #171717;\n  --primary: #2563eb;\n  --primary-foreground: #ffffff;\n  --secondary: #64748b;\n  --secondary-foreground: #ffffff;\n  --muted: #f1f5f9;\n  --muted-foreground: #64748b;\n  --accent: #f1f5f9;\n  --accent-foreground: #0f172a;\n  --destructive: #ef4444;\n  --destructive-foreground: #ffffff;\n  --border: #e2e8f0;\n  --input: #e2e8f0;\n  --ring: #2563eb;\n}\n\n/* Manual dark mode class override */\n.dark {\n  --background: #0a0a0a;\n  --foreground: #ededed;\n  --card: #171717;\n  --card-foreground: #ededed;\n  --primary: #3b82f6;\n  --primary-foreground: #ffffff;\n  --secondary: #94a3b8;\n  --secondary-foreground: #0f172a;\n  --muted: #1e293b;\n  --muted-foreground: #94a3b8;\n  --accent: #1e293b;\n  --accent-foreground: #f1f5f9;\n  --destructive: #dc2626;\n  --destructive-foreground: #ffffff;\n  --border: #1e293b;\n  --input: #1e293b;\n  --ring: #3b82f6;\n}\n\n* {\n  border-color: var(--border);\n}\n\nbody {\n  background: var(--background);\n  color: var(--foreground);\n  font-family: var(--font-sans, Arial, Helvetica, sans-serif);\n}\n\n/* Optimized transitions for theme changes - only target necessary elements */\nhtml {\n  transition: background-color 100ms ease-out;\n}\n\nbody {\n  transition:\n    background-color 100ms ease-out,\n    color 100ms ease-out;\n}\n\n/* Target specific UI elements for faster transitions */\n[class*='bg-'],\n[class*='text-'],\n[class*='border-'] {\n  transition:\n    background-color 100ms ease-out,\n    color 100ms ease-out,\n    border-color 100ms ease-out;\n}\n\n/* SVG icons transition */\nsvg {\n  transition:\n    fill 100ms ease-out,\n    stroke 100ms ease-out,\n    color 100ms ease-out;\n}\n\n/* Button and interactive elements */\nbutton,\na,\ninput,\nselect,\ntextarea {\n  transition:\n    background-color 100ms ease-out,\n    color 100ms ease-out,\n    border-color 100ms ease-out,\n    opacity 100ms ease-out;\n}\n\n/* Cards and containers */\n[class*='card'],\n[class*='bg-card'] {\n  transition:\n    background-color 100ms ease-out,\n    border-color 100ms ease-out;\n}\n\n/* Optimize theme switching performance */\nhtml.theme-switching * {\n  transition: none !important;\n}\n\nhtml.theme-switching {\n  transition: none !important;\n}\n\n/* Respect reduced motion preferences */\n@media (prefers-reduced-motion: reduce) {\n  * {\n    transition: none !important;\n    animation: none !important;\n  }\n}\n\n/* Reduced motion override via settings */\n:root[style*='--motion-reduce'] * {\n  transition: none !important;\n  animation: none !important;\n}\n\n/* Markdown Preview Styles */\n.markdown-preview {\n  color: var(--foreground);\n}\n\n.markdown-preview h1,\n.markdown-preview h2,\n.markdown-preview h3,\n.markdown-preview h4,\n.markdown-preview h5,\n.markdown-preview h6 {\n  color: var(--foreground);\n}\n\n.markdown-preview p {\n  color: var(--foreground);\n  line-height: 1.6;\n}\n\n.markdown-preview strong,\n.markdown-preview b {\n  color: var(--foreground);\n  font-weight: 600;\n}\n\n.markdown-preview img {\n  display: inline-block;\n  vertical-align: middle;\n}\n\n.markdown-preview a img {\n  margin: 0;\n}\n\n/* Custom page content styles to override prose */\n.page-content {\n  color: var(--foreground);\n}\n\n.page-content h1,\n.page-content h2,\n.page-content h3,\n.page-content h4,\n.page-content h5,\n.page-content h6 {\n  color: var(--foreground);\n  line-height: 1.2;\n  margin-bottom: 1rem;\n}\n\n.page-content h1 {\n  font-size: 2.25rem;\n  font-weight: 700;\n}\n\n.page-content h2 {\n  font-size: 1.875rem;\n  font-weight: 700;\n}\n\n.page-content h3 {\n  font-size: 1.5rem;\n  font-weight: 600;\n}\n\n.page-content h4 {\n  font-size: 1.25rem;\n  font-weight: 600;\n}\n\n.page-content p {\n  color: var(--foreground);\n  line-height: 1.6;\n  margin-bottom: 1rem;\n}\n\n.page-content strong,\n.page-content b {\n  color: var(--foreground);\n  font-weight: 600;\n}\n\n.page-content a {\n  color: var(--primary);\n  text-decoration: underline;\n}\n\n.page-content a:hover {\n  text-decoration: none;\n}\n\n.page-content ul,\n.page-content ol {\n  color: var(--foreground);\n  margin-bottom: 1rem;\n  padding-left: 1.5rem;\n}\n\n.page-content li {\n  margin-bottom: 0.5rem;\n}\n\n.page-content blockquote {\n  color: var(--foreground);\n  border-left: 4px solid var(--primary);\n  padding-left: 1rem;\n  margin: 1.5rem 0;\n  font-style: italic;\n}\n\n.page-content hr {\n  border-color: var(--border);\n  margin: 2rem 0;\n}\n\n.page-content pre {\n  background-color: var(--muted);\n  color: var(--foreground);\n  padding: 1rem;\n  border-radius: 0.5rem;\n  overflow-x: auto;\n  margin: 1rem 0;\n}\n\n.page-content code {\n  background-color: var(--muted);\n  color: var(--foreground);\n  padding: 0.125rem 0.25rem;\n  border-radius: 0.25rem;\n  font-size: 0.875rem;\n}\n\n.page-content img {\n  max-width: 100%;\n  height: auto;\n  margin: 1rem 0;\n}\n\n/* High Contrast Mode */\n.high-contrast {\n  --background: #000000;\n  --foreground: #ffffff;\n  --card: #000000;\n  --card-foreground: #ffffff;\n  --primary: #ffff00;\n  --primary-foreground: #000000;\n  --secondary: #00ffff;\n  --secondary-foreground: #000000;\n  --muted: #333333;\n  --muted-foreground: #ffffff;\n  --accent: #00ff00;\n  --accent-foreground: #000000;\n  --destructive: #ff0000;\n  --destructive-foreground: #ffffff;\n  --border: #ffffff;\n  --input: #ffffff;\n  --ring: #ffff00;\n}\n\n.high-contrast * {\n  border-width: 2px;\n}\n\n.high-contrast button,\n.high-contrast a,\n.high-contrast input,\n.high-contrast textarea,\n.high-contrast select {\n  outline: 2px solid var(--foreground);\n  outline-offset: 2px;\n}\n\n/* Form placeholder opacity - reduce to avoid looking like filled fields */\ninput::placeholder,\ntextarea::placeholder,\nselect::placeholder {\n  opacity: 0.4;\n}\n\n/* Font Size Variants */\n.text-small {\n  font-size: 14px;\n}\n\n.text-small h1 {\n  font-size: 1.75rem;\n}\n\n.text-small h2 {\n  font-size: 1.5rem;\n}\n\n.text-small h3 {\n  font-size: 1.25rem;\n}\n\n.text-large {\n  font-size: 18px;\n}\n\n.text-large h1 {\n  font-size: 2.5rem;\n}\n\n.text-large h2 {\n  font-size: 2rem;\n}\n\n.text-large h3 {\n  font-size: 1.75rem;\n}\n"
  },
  {
    "path": "src/app/layout.tsx",
    "content": "import type { Metadata } from 'next';\nimport { Roboto_Mono } from 'next/font/google';\nimport localFont from 'next/font/local';\nimport './globals.css';\nimport { ThemeProvider } from '@/components/layout/theme-provider';\nimport { ToastProvider } from '@/components/ui/toast';\nimport { BuyMeACoffeeWidget } from '@/components/ui/buy-me-coffee';\nimport { ConditionalAnalytics } from '@/components/analytics/conditional-analytics';\nimport { CookieConsent } from '@/components/ui/cookie-consent';\nimport { getAssetPath } from '@/lib/asset-path';\n\nconst robotoMono = Roboto_Mono({\n  variable: '--font-mono',\n  subsets: ['latin'],\n  weight: ['400', '500', '600', '700'],\n});\n\nconst wotfard = localFont({\n  src: '../../public/fonts/wotfard/Wotfard-Regular.woff',\n  variable: '--font-sans',\n  weight: '400',\n});\n\nexport const metadata: Metadata = {\n  title: {\n    default: 'GitHub Profile README Generator - Create Amazing Profile in Seconds',\n    template: '%s | GitHub Profile README Generator',\n  },\n  description:\n    'The best profile README generator to create an amazing GitHub profile in seconds. Customize your profile with skills, social links, stats, and more. Free, open-source, and easy to use.',\n  keywords: [\n    'github',\n    'profile',\n    'readme',\n    'generator',\n    'markdown',\n    'github profile',\n    'readme generator',\n    'github readme',\n    'profile generator',\n    'github stats',\n    'github badges',\n    'developer profile',\n    'github profile maker',\n    'readme maker',\n  ],\n  authors: [{ name: 'Rahul Jain', url: 'https://github.com/rahuldkjain' }],\n  creator: 'Rahul Jain',\n  publisher: 'Rahul Jain',\n  formatDetection: {\n    email: false,\n    address: false,\n    telephone: false,\n  },\n  metadataBase: new URL('https://rahuldkjain.github.io/gh-profile-readme-generator/'),\n  alternates: {\n    canonical: '/',\n  },\n  openGraph: {\n    title: 'GitHub Profile README Generator - Create Amazing Profile in Seconds',\n    description:\n      'Create an amazing GitHub profile README in seconds with customizable templates and easy-to-use interface. Add skills, social links, GitHub stats, and more.',\n    url: 'https://rahuldkjain.github.io/gh-profile-readme-generator/',\n    siteName: 'GitHub Profile README Generator',\n    locale: 'en_US',\n    type: 'website',\n    images: [\n      {\n        url: '/og-image.png',\n        width: 1200,\n        height: 630,\n        alt: 'GitHub Profile README Generator - Create Amazing Profile in Seconds',\n      },\n    ],\n  },\n  twitter: {\n    card: 'summary_large_image',\n    title: 'GitHub Profile README Generator',\n    description:\n      'Create an amazing GitHub profile README in seconds with customizable templates. Free and easy to use.',\n    creator: '@rahuldkjain',\n    images: ['/og-image.png'],\n  },\n  icons: {\n    icon: [\n      { url: '/favicon.ico', sizes: 'any' },\n      { url: getAssetPath('/mdg.png'), type: 'image/png' },\n    ],\n    apple: getAssetPath('/mdg.png'),\n  },\n  manifest: getAssetPath('/manifest.json'),\n  robots: {\n    index: true,\n    follow: true,\n    googleBot: {\n      index: true,\n      follow: true,\n      'max-video-preview': -1,\n      'max-image-preview': 'large',\n      'max-snippet': -1,\n    },\n  },\n  verification: {\n    google: 'google-site-verification-code', // User will need to add their code\n  },\n};\n\nexport default function RootLayout({\n  children,\n}: Readonly<{\n  children: React.ReactNode;\n}>) {\n  const jsonLd = {\n    '@context': 'https://schema.org',\n    '@type': 'WebApplication',\n    name: 'GitHub Profile README Generator',\n    description:\n      'Create an amazing GitHub profile README in seconds with customizable templates and easy-to-use interface.',\n    url: 'https://rahuldkjain.github.io/gh-profile-readme-generator/',\n    applicationCategory: 'DeveloperApplication',\n    operatingSystem: 'Any',\n    offers: {\n      '@type': 'Offer',\n      price: '0',\n      priceCurrency: 'USD',\n    },\n    author: {\n      '@type': 'Person',\n      name: 'Rahul Jain',\n      url: 'https://github.com/rahuldkjain',\n    },\n    aggregateRating: {\n      '@type': 'AggregateRating',\n      ratingValue: '4.8',\n      ratingCount: '1000',\n    },\n  };\n\n  return (\n    <html lang=\"en\" suppressHydrationWarning>\n      <head>\n        {/* Favicon and manifest are now handled by Next.js metadata API above */}\n        <meta name=\"theme-color\" content=\"#000000\" />\n        <meta name=\"apple-mobile-web-app-capable\" content=\"yes\" />\n        <meta name=\"apple-mobile-web-app-status-bar-style\" content=\"default\" />\n        <meta name=\"apple-mobile-web-app-title\" content=\"GitHub README Gen\" />\n        <script\n          type=\"application/ld+json\"\n          dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}\n        />\n      </head>\n      <body className={`${wotfard.variable} ${robotoMono.variable} font-sans antialiased`}>\n        <ThemeProvider>\n          <ToastProvider>{children}</ToastProvider>\n        </ThemeProvider>\n        <BuyMeACoffeeWidget />\n        <ConditionalAnalytics />\n        <CookieConsent />\n      </body>\n    </html>\n  );\n}\n"
  },
  {
    "path": "src/app/page.tsx",
    "content": "'use client';\n\nimport { useState, useEffect, useMemo, lazy, Suspense, useCallback } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { motion } from 'framer-motion';\nimport { Download } from 'lucide-react';\nimport { profileSchema, linksSchema, socialSchema } from '@/lib/validations';\nimport { DEFAULT_DATA, DEFAULT_LINK, DEFAULT_SOCIAL } from '@/constants/defaults';\nimport { initialSkillState } from '@/constants/skills';\nimport { BasicInfoSection } from '@/components/sections/basic-info-section';\nimport { LinksSection } from '@/components/sections/links-section';\nimport { SocialSection } from '@/components/sections/social-section';\nimport { generateMarkdown } from '@/lib/markdown-generator';\nimport { saveFormData, loadFormData, clearFormData } from '@/lib/storage';\nimport type { ProfileFormData, LinksFormData, SocialFormData } from '@/lib/validations';\nimport { DEFAULT_SUPPORT } from '@/constants/defaults';\nimport { Header } from '@/components/layout/header';\nimport { Footer } from '@/components/layout/footer';\nimport { useErrorToast, useSuccessToast } from '@/components/ui/toast';\nimport { trackReadmeGenerated, trackFileExported } from '@/lib/analytics';\nimport { useConfirmDialog } from '@/components/ui/confirm-dialog';\n\n// Lazy load heavy components\nconst SkillsSection = lazy(() =>\n  import('@/components/sections/skills-section').then((module) => ({\n    default: module.SkillsSection,\n  }))\n);\nconst MarkdownPreview = lazy(() =>\n  import('@/components/ui/markdown-preview').then((module) => ({ default: module.MarkdownPreview }))\n);\n\ntype Step = 'basic' | 'links' | 'social' | 'skills' | 'preview';\n\nconst steps: { id: Step; title: string; description: string }[] = [\n  { id: 'basic', title: 'Basic Info', description: 'Tell us about yourself' },\n  { id: 'links', title: 'Links', description: 'Portfolio, blog, resume' },\n  { id: 'social', title: 'Social', description: 'Social media profiles' },\n  { id: 'skills', title: 'Skills', description: 'Technologies you know' },\n  { id: 'preview', title: 'Preview', description: 'Review and generate' },\n];\n\nexport default function GeneratorPage() {\n  // Toast hooks\n  const showError = useErrorToast();\n  const showSuccess = useSuccessToast();\n  const { showConfirm, ConfirmDialog } = useConfirmDialog();\n  // Load saved data FIRST before any state initialization\n  const savedData = useMemo(() => {\n    if (typeof window === 'undefined') return null;\n    const data = loadFormData();\n    console.log('🎯 Initial load - Saved data:', data);\n    return data;\n  }, []); // Empty deps - only run once on mount\n\n  const [currentStep, setCurrentStep] = useState<Step>('basic');\n  const [skills, setSkills] = useState(() => {\n    // Lazy initialization - use saved skills if available\n    const initialSkills = savedData?.skills || initialSkillState;\n    console.log(\n      '🎯 Initial skills state:',\n      Object.values(initialSkills).filter(Boolean).length,\n      'selected'\n    );\n    return initialSkills;\n  });\n  const [lastSaved, setLastSaved] = useState<Date | null>(() => {\n    if (savedData?.lastSaved) {\n      return new Date(savedData.lastSaved);\n    }\n    return null;\n  });\n  const [saveStatus, setSaveStatus] = useState<'idle' | 'saving' | 'saved'>('idle');\n  const [hasInitialized, setHasInitialized] = useState(false);\n\n  const {\n    register: registerProfile,\n    formState: { errors: profileErrors },\n    watch: watchProfile,\n    reset: resetProfile,\n    trigger: triggerProfile,\n  } = useForm<ProfileFormData>({\n    resolver: zodResolver(profileSchema),\n    defaultValues: savedData?.profile ? { ...DEFAULT_DATA, ...savedData.profile } : DEFAULT_DATA,\n    mode: 'onChange',\n  });\n\n  const {\n    register: registerLinks,\n    formState: { errors: linksErrors },\n    watch: watchLinks,\n    reset: resetLinks,\n    trigger: triggerLinks,\n  } = useForm<LinksFormData>({\n    resolver: zodResolver(linksSchema),\n    defaultValues: savedData?.links ? { ...DEFAULT_LINK, ...savedData.links } : DEFAULT_LINK,\n    mode: 'onChange',\n  });\n\n  const {\n    register: registerSocial,\n    formState: { errors: socialErrors },\n    watch: watchSocial,\n    reset: resetSocial,\n    trigger: triggerSocial,\n  } = useForm<SocialFormData>({\n    resolver: zodResolver(socialSchema),\n    defaultValues: savedData?.social ? { ...DEFAULT_SOCIAL, ...savedData.social } : DEFAULT_SOCIAL,\n    mode: 'onChange',\n  });\n\n  // Watch all form values for live preview\n  const profileData = watchProfile();\n  const linksData = watchLinks();\n  const socialData = watchSocial();\n\n  // Generate markdown with useMemo to prevent unnecessary recalculations\n  const markdown = useMemo(() => {\n    return generateMarkdown({\n      profile: profileData,\n      links: linksData,\n      social: socialData,\n      support: DEFAULT_SUPPORT,\n      skills,\n    });\n  }, [profileData, linksData, socialData, skills]);\n\n  // Mark as initialized after first render to enable auto-save\n  useEffect(() => {\n    console.log('🔍 Mount - Data already loaded in initialization');\n    if (savedData) {\n      console.log('✅ Mount - Restored from localStorage automatically');\n    } else {\n      console.log('🆕 Mount - Starting fresh (no saved data)');\n    }\n\n    // Set initialized to true after a brief delay to ensure forms are fully set up\n    const timer = setTimeout(() => {\n      console.log('🎬 Initialization complete - Auto-save now enabled');\n      setHasInitialized(true);\n    }, 100);\n\n    return () => clearTimeout(timer);\n  }, [savedData]);\n\n  // Auto-save form data - only after initialization complete\n  useEffect(() => {\n    // Skip until initialization is complete\n    if (!hasInitialized) {\n      console.log('⏭️ Auto-save - Waiting for initialization to complete');\n      return;\n    }\n\n    console.log('💾 Auto-save - Starting...');\n    console.log('📊 Auto-save - Profile data:', profileData);\n    console.log('📊 Auto-save - Links data:', linksData);\n    console.log('📊 Auto-save - Social data:', socialData);\n    console.log('📊 Auto-save - Skills selected:', Object.values(skills).filter(Boolean).length);\n\n    setSaveStatus('saving');\n    const timer = setTimeout(() => {\n      const now = new Date();\n      const dataToSave = {\n        profile: profileData,\n        links: linksData,\n        social: socialData,\n        support: DEFAULT_SUPPORT,\n        skills,\n        lastSaved: now.toISOString(),\n      };\n\n      console.log('💾 Auto-save - Saving to localStorage:', dataToSave);\n      saveFormData(dataToSave);\n\n      // Verify it was saved\n      const savedDataCheck = localStorage.getItem('github-profile-generator');\n      console.log('✅ Auto-save - Verified in localStorage:', savedDataCheck ? 'YES' : 'NO');\n      console.log('📏 Auto-save - Data size:', savedDataCheck?.length || 0, 'bytes');\n\n      setLastSaved(now);\n      setSaveStatus('saved');\n\n      // Reset to idle after animation\n      setTimeout(() => setSaveStatus('idle'), 2000);\n    }, 1000); // Save 1 second after last change\n\n    return () => clearTimeout(timer);\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [\n    hasInitialized,\n    JSON.stringify(profileData),\n    JSON.stringify(linksData),\n    JSON.stringify(socialData),\n    JSON.stringify(skills),\n  ]);\n\n  const handleSkillChange = (skill: string, checked: boolean) => {\n    setSkills((prev) => ({ ...prev, [skill]: checked }));\n  };\n\n  const handleGitHubAutoFill = (data: {\n    profile: Partial<ProfileFormData>;\n    links: Partial<LinksFormData>;\n    social: Partial<SocialFormData>;\n    skills: string[];\n  }) => {\n    // Update profile data\n    if (data.profile.title) {\n      resetProfile((prev) => ({ ...prev, ...data.profile }));\n    }\n\n    // Update links data\n    if (data.links.blog) {\n      resetLinks((prev) => ({ ...prev, ...data.links }));\n    }\n\n    // Update social data\n    if (data.social.github || data.social.twitter) {\n      resetSocial((prev) => ({ ...prev, ...data.social }));\n    }\n\n    // Update skills\n    if (data.skills.length > 0) {\n      const newSkills = { ...skills };\n      data.skills.forEach((skill) => {\n        if (skill in newSkills) {\n          newSkills[skill] = true;\n        }\n      });\n      setSkills(newSkills);\n    }\n  };\n\n  // Restore is now automatic on mount, but keep this for manual restore if needed\n  // This function is no longer needed but kept for backwards compatibility\n\n  // Check if there's any meaningful data to clear\n  const hasAnyData = useMemo(() => {\n    // Check profile data (excluding empty strings)\n    const hasProfileData = Object.entries(profileData).some(([key, value]) => {\n      if (key === 'subtitle' && value === '') return false; // Empty subtitle is now default\n      return typeof value === 'string' ? value.trim() !== '' : value !== false && value !== null;\n    });\n\n    // Check links data\n    const hasLinksData = Object.values(linksData).some((value) => value && value.trim() !== '');\n\n    // Check social data\n    const hasSocialData = Object.values(socialData).some((value) =>\n      typeof value === 'string' ? value.trim() !== '' : value === true\n    );\n\n    // Check skills data\n    const hasSkillsData = Object.values(skills).some((selected) => selected === true);\n\n    return hasProfileData || hasLinksData || hasSocialData || hasSkillsData;\n  }, [profileData, linksData, socialData, skills]);\n\n  const handleClearAll = useCallback(() => {\n    showConfirm({\n      title: 'Clear All Data',\n      message:\n        'Are you sure you want to clear all data? This will reset all form fields, skills, and settings. This action cannot be undone.',\n      confirmText: 'Clear All',\n      cancelText: 'Cancel',\n      variant: 'warning',\n      onConfirm: () => {\n        clearFormData();\n        resetProfile(DEFAULT_DATA);\n        resetLinks(DEFAULT_LINK);\n        resetSocial(DEFAULT_SOCIAL);\n        setSkills(initialSkillState);\n        setLastSaved(null);\n        setSaveStatus('idle');\n        showSuccess('All data cleared successfully', 'Form has been reset to default values');\n      },\n    });\n  }, [showConfirm, resetProfile, resetLinks, resetSocial, setSkills, showSuccess]);\n\n  const handleDownloadJSON = () => {\n    const data = {\n      version: '1.0.0',\n      exportedAt: new Date().toISOString(),\n      profile: profileData,\n      links: linksData,\n      social: socialData,\n      support: DEFAULT_SUPPORT,\n      skills: Object.entries(skills)\n        .filter(([_, selected]) => selected)\n        .map(([skill]) => skill),\n    };\n\n    const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });\n    const url = URL.createObjectURL(blob);\n    const a = document.createElement('a');\n    a.href = url;\n    a.download = `github-profile-${new Date().getTime()}.json`;\n    document.body.appendChild(a);\n    a.click();\n\n    // Track JSON export\n    trackFileExported('json_export', 'json');\n    document.body.removeChild(a);\n    URL.revokeObjectURL(url);\n  };\n\n  const handleImportJSON = (event: React.ChangeEvent<HTMLInputElement>) => {\n    const file = event.target.files?.[0];\n    if (!file) return;\n\n    const reader = new FileReader();\n    reader.onload = (e) => {\n      try {\n        const imported = JSON.parse(e.target?.result as string);\n\n        // Validate and import data\n        if (imported.profile) {\n          resetProfile({ ...DEFAULT_DATA, ...imported.profile } as ProfileFormData);\n        }\n        if (imported.links) {\n          resetLinks({ ...DEFAULT_LINK, ...imported.links } as LinksFormData);\n        }\n        if (imported.social) {\n          resetSocial({ ...DEFAULT_SOCIAL, ...imported.social } as SocialFormData);\n        }\n        if (imported.skills && Array.isArray(imported.skills)) {\n          const newSkills = { ...initialSkillState };\n          imported.skills.forEach((skill: string) => {\n            if (skill in newSkills) {\n              newSkills[skill] = true;\n            }\n          });\n          setSkills(newSkills);\n        }\n\n        alert('Profile data imported successfully!');\n      } catch (error) {\n        alert('Error importing JSON: ' + (error as Error).message);\n      }\n    };\n    reader.readAsText(file);\n\n    // Reset input\n    event.target.value = '';\n  };\n\n  const currentStepIndex = steps.findIndex((s) => s.id === currentStep);\n\n  // Validate current step before navigation\n  const validateCurrentStep = async (): Promise<boolean> => {\n    let isValid = true;\n    const errorMessages: string[] = [];\n\n    switch (currentStep) {\n      case 'basic':\n        const profileValid = await triggerProfile();\n        if (!profileValid) {\n          isValid = false;\n          // Get specific error messages\n          if (profileErrors.title) {\n            errorMessages.push(`Name: ${profileErrors.title.message}`);\n          }\n          // Add other field errors as needed\n          Object.entries(profileErrors).forEach(([field, error]) => {\n            if (field !== 'title' && error?.message) {\n              errorMessages.push(`${field}: ${error.message}`);\n            }\n          });\n        }\n        break;\n\n      case 'links':\n        const linksValid = await triggerLinks();\n        if (!linksValid) {\n          isValid = false;\n          Object.entries(linksErrors).forEach(([field, error]) => {\n            if (error?.message) {\n              errorMessages.push(`${field}: ${error.message}`);\n            }\n          });\n        }\n        break;\n\n      case 'social':\n        const socialValid = await triggerSocial();\n        if (!socialValid) {\n          isValid = false;\n          Object.entries(socialErrors).forEach(([field, error]) => {\n            if (error?.message) {\n              errorMessages.push(`${field}: ${error.message}`);\n            }\n          });\n        }\n        break;\n\n      case 'skills':\n        // Skills don't have validation requirements\n        break;\n\n      case 'preview':\n        // Preview doesn't need validation\n        break;\n    }\n\n    if (!isValid) {\n      const stepName = steps.find((s) => s.id === currentStep)?.title || 'current step';\n      showError(\n        `Please fix errors in ${stepName}`,\n        errorMessages.length > 0 ? errorMessages.join(', ') : 'Please check all required fields'\n      );\n    }\n\n    return isValid;\n  };\n\n  const goToNextStep = async () => {\n    // Validate current step before proceeding\n    const isValid = await validateCurrentStep();\n    if (!isValid) {\n      return; // Don't proceed if validation fails\n    }\n\n    const nextIndex = currentStepIndex + 1;\n    if (nextIndex < steps.length) {\n      setCurrentStep(steps[nextIndex].id);\n\n      // Show success message for completing a step\n      const currentStepName = steps[currentStepIndex].title;\n      showSuccess(`${currentStepName} completed!`, 'Moving to next step');\n\n      // Track README generation completion when reaching preview step\n      if (steps[nextIndex].id === 'preview') {\n        const socialData = watchSocial();\n        const linksData = watchLinks();\n        const selectedSkillsCount = Object.values(skills).filter(Boolean).length;\n\n        trackReadmeGenerated({\n          hasSkills: selectedSkillsCount > 0,\n          hasSocial: Object.values(socialData).some(\n            (value) => typeof value === 'string' && value.trim() !== ''\n          ),\n          hasLinks: Object.values(linksData).some(\n            (value) => typeof value === 'string' && value.trim() !== ''\n          ),\n          stepCount: currentStepIndex + 1,\n        });\n      }\n    }\n  };\n\n  const goToPrevStep = () => {\n    const prevIndex = currentStepIndex - 1;\n    if (prevIndex >= 0) {\n      setCurrentStep(steps[prevIndex].id);\n    }\n  };\n\n  return (\n    <div className=\"flex min-h-screen flex-col\">\n      {/* Header with Save Status */}\n      <Header saveStatus={saveStatus} lastSaved={lastSaved} />\n\n      <main className=\"container mx-auto flex-1 px-4 py-8\">\n        <div className=\"mx-auto max-w-6xl\">\n          {/* Progress Steps - Responsive */}\n          <nav aria-label=\"Form progress\" className=\"mb-8\">\n            <div className=\"flex items-center justify-center overflow-x-auto px-4\">\n              <div className=\"flex min-w-max items-center\">\n                {steps.map((step, index) => (\n                  <div key={step.id} className=\"flex items-center\">\n                    <button\n                      onClick={() => setCurrentStep(step.id)}\n                      className={`flex flex-col items-center gap-1 px-2 py-1 ${\n                        currentStep === step.id\n                          ? 'text-primary'\n                          : index < currentStepIndex\n                            ? 'text-foreground'\n                            : 'text-muted-foreground'\n                      }`}\n                      aria-label={`Step ${index + 1}: ${step.title}`}\n                      aria-current={currentStep === step.id ? 'step' : undefined}\n                    >\n                      <div\n                        className={`flex h-8 w-8 items-center justify-center rounded-full border-2 transition-colors sm:h-10 sm:w-10 ${\n                          currentStep === step.id\n                            ? 'border-primary bg-primary text-primary-foreground'\n                            : index < currentStepIndex\n                              ? 'border-primary bg-primary/20'\n                              : 'border-border'\n                        }`}\n                      >\n                        <span className=\"text-xs font-medium sm:text-sm\">{index + 1}</span>\n                      </div>\n                      <div className=\"hidden text-center sm:block\">\n                        <p className=\"text-xs font-medium whitespace-nowrap\">{step.title}</p>\n                        <p className=\"text-muted-foreground text-xs whitespace-nowrap\">\n                          {step.description}\n                        </p>\n                      </div>\n                    </button>\n                    {index < steps.length - 1 && (\n                      <div\n                        className={`mx-2 h-0.5 w-8 sm:mx-4 sm:w-12 ${\n                          index < currentStepIndex ? 'bg-primary' : 'bg-border'\n                        }`}\n                      />\n                    )}\n                  </div>\n                ))}\n              </div>\n            </div>\n            {/* Screen reader announcement for step changes */}\n            <div className=\"sr-only\" aria-live=\"polite\" aria-atomic=\"true\">\n              Current step: {steps[currentStepIndex].title} - {steps[currentStepIndex].description}\n            </div>\n          </nav>\n\n          {/* Form Content */}\n          <motion.div\n            key={currentStep}\n            initial={{ opacity: 0, x: 20 }}\n            animate={{ opacity: 1, x: 0 }}\n            exit={{ opacity: 0, x: -20 }}\n            transition={{ duration: 0.3 }}\n            className=\"border-border bg-card rounded-lg border p-6 shadow-sm md:p-8\"\n          >\n            {currentStep === 'basic' && (\n              <BasicInfoSection\n                register={registerProfile}\n                errors={profileErrors}\n                socialRegister={registerSocial}\n                watchSocial={watchSocial}\n                onGitHubAutoFill={handleGitHubAutoFill}\n                onImportJSON={handleImportJSON}\n                onClearAll={handleClearAll}\n                hasClearableData={hasAnyData}\n              />\n            )}\n            {currentStep === 'links' && (\n              <LinksSection register={registerLinks} errors={linksErrors} />\n            )}\n            {currentStep === 'social' && (\n              <SocialSection register={registerSocial} errors={socialErrors} watch={watchSocial} />\n            )}\n            {currentStep === 'skills' && (\n              <Suspense\n                fallback={\n                  <div className=\"animate-pulse space-y-4\">\n                    <div className=\"h-8 rounded bg-gray-200\"></div>\n                    <div className=\"grid grid-cols-2 gap-4 md:grid-cols-3 lg:grid-cols-4\">\n                      {Array.from({ length: 12 }).map((_, i) => (\n                        <div key={i} className=\"h-12 rounded bg-gray-200\"></div>\n                      ))}\n                    </div>\n                  </div>\n                }\n              >\n                <SkillsSection\n                  selectedSkills={skills}\n                  onSkillChange={handleSkillChange}\n                  registerProfile={registerProfile}\n                />\n              </Suspense>\n            )}\n            {currentStep === 'preview' && (\n              <div className=\"space-y-6\">\n                <div className=\"border-border border-b pb-4\">\n                  {/* Mobile: Stack vertically, Desktop: Side by side */}\n                  <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n                    <div>\n                      <h2 className=\"text-xl font-bold sm:text-2xl\">Preview & Generate</h2>\n                      <p className=\"text-muted-foreground mt-1 text-sm\">\n                        Your README is ready! Copy or download it below.\n                      </p>\n                    </div>\n                    {/* Export Button - With text */}\n                    <button\n                      onClick={handleDownloadJSON}\n                      className=\"bg-primary text-primary-foreground hover:bg-primary/90 flex items-center justify-center gap-2 rounded-lg px-3 py-2 text-sm transition-colors\"\n                      title=\"Export profile data as JSON\"\n                      aria-label=\"Export profile data as JSON\"\n                    >\n                      <Download className=\"h-4 w-4\" />\n                      <span>Export</span>\n                    </button>\n                  </div>\n                </div>\n\n                <Suspense\n                  fallback={\n                    <div className=\"animate-pulse space-y-4\">\n                      <div className=\"h-8 rounded bg-gray-200\"></div>\n                      <div className=\"h-96 rounded bg-gray-200\"></div>\n                    </div>\n                  }\n                >\n                  <MarkdownPreview markdown={markdown} title=\"Your GitHub Profile README\" />\n                </Suspense>\n              </div>\n            )}\n          </motion.div>\n\n          {/* Navigation Buttons */}\n          <nav className=\"mt-6 flex justify-between\" aria-label=\"Form navigation\">\n            <button\n              onClick={goToPrevStep}\n              disabled={currentStepIndex === 0}\n              className=\"border-border hover:bg-accent rounded-lg border px-6 py-2 font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50\"\n              aria-label={`Go to previous step${currentStepIndex > 0 ? `: ${steps[currentStepIndex - 1].title}` : ''}`}\n            >\n              Previous\n            </button>\n            {/* Hide Next button at preview step since we're already at the end */}\n            {currentStepIndex < steps.length - 1 && (\n              <button\n                onClick={goToNextStep}\n                className=\"bg-primary text-primary-foreground hover:bg-primary/90 rounded-lg px-6 py-2 font-medium transition-colors\"\n                aria-label={`Go to next step: ${steps[currentStepIndex + 1].title}`}\n              >\n                Next\n              </button>\n            )}\n          </nav>\n        </div>\n      </main>\n      <Footer />\n\n      {/* Confirmation Dialog */}\n      <ConfirmDialog />\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/app/robots.ts",
    "content": "import { MetadataRoute } from 'next';\n\nexport const dynamic = 'force-static';\n\nexport default function robots(): MetadataRoute.Robots {\n  const baseUrl = 'https://rahuldkjain.github.io/gh-profile-readme-generator';\n\n  return {\n    rules: [\n      {\n        userAgent: '*',\n        allow: '/',\n        disallow: [],\n      },\n    ],\n    sitemap: `${baseUrl}/sitemap.xml`,\n  };\n}\n"
  },
  {
    "path": "src/app/sitemap.ts",
    "content": "import { MetadataRoute } from 'next';\n\nexport const dynamic = 'force-static';\n\nexport default function sitemap(): MetadataRoute.Sitemap {\n  const baseUrl = 'https://rahuldkjain.github.io/gh-profile-readme-generator';\n\n  return [\n    {\n      url: baseUrl,\n      lastModified: new Date(),\n      changeFrequency: 'weekly',\n      priority: 1.0,\n    },\n    {\n      url: `${baseUrl}/about`,\n      lastModified: new Date(),\n      changeFrequency: 'monthly',\n      priority: 0.7,\n    },\n    {\n      url: `${baseUrl}/addons`,\n      lastModified: new Date(),\n      changeFrequency: 'monthly',\n      priority: 0.7,\n    },\n    {\n      url: `${baseUrl}/support`,\n      lastModified: new Date(),\n      changeFrequency: 'monthly',\n      priority: 0.6,\n    },\n  ];\n}\n"
  },
  {
    "path": "src/app/support/page.tsx",
    "content": "import { Header } from '@/components/layout/header';\nimport { Footer } from '@/components/layout/footer';\nimport type { Metadata } from 'next';\n\nexport const metadata: Metadata = {\n  title: 'Support',\n  description:\n    'Support the development of GitHub Profile README Generator and help make it better. Learn how to contribute, report issues, and sponsor the project.',\n  alternates: {\n    canonical: '/support',\n  },\n  openGraph: {\n    title: 'Support | GitHub Profile README Generator',\n    description:\n      'Support the development of GitHub Profile README Generator and help make it better',\n    url: '/support',\n  },\n};\n\nexport default function SupportPage() {\n  return (\n    <div className=\"flex min-h-screen flex-col\">\n      <Header />\n\n      <main className=\"container mx-auto flex-1 px-4 py-12\">\n        <div className=\"page-content mx-auto max-w-4xl\">\n          <h1 className=\"mb-6 text-4xl font-bold\">💵 Support OSS</h1>\n\n          <blockquote className=\"border-primary border-l-4 pl-4 italic\">\n            Think of giving not as a duty but as a privilege - John D. Rockefeller Jr.\n          </blockquote>\n\n          <p className=\"text-lg\">\n            🚀 GitHub Profile README Generator tool is free and will always be free. Numerous\n            developers has put their time and efforts to make this tool more powerful. However,\n            these developers are doing their full time job along with open-source contributions.\n          </p>\n\n          <p>\n            You can come forward to support the developers by making small donations. You will never\n            know what this support mean to them. If you find the tool really helpful, then it will\n            be very grateful to support the tool 🙇.\n          </p>\n\n          <div className=\"my-6 flex flex-wrap gap-3\">\n            <a\n              href=\"https://www.paypal.me/rahuldkjain/10\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n            >\n              <img src=\"https://ionicabizau.github.io/badges/paypal.svg\" alt=\"PayPal\" />\n            </a>\n            <a href=\"https://ko-fi.com/A0A81XXSX\" target=\"_blank\" rel=\"noopener noreferrer\">\n              <img\n                height=\"23\"\n                width=\"100\"\n                src=\"https://cdn.ko-fi.com/cdn/kofi3.png?v=2\"\n                alt=\"Buy Coffee for rahuldkjain\"\n              />\n            </a>\n            <a\n              href=\"https://www.buymeacoffee.com/rahuldkjain\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n            >\n              <img\n                src=\"https://cdn.buymeacoffee.com/buttons/default-orange.png\"\n                alt=\"Buy Me A Coffee\"\n                height=\"23\"\n                width=\"100\"\n                style={{ borderRadius: '2px' }}\n              />\n            </a>\n          </div>\n\n          <hr className=\"my-8\" />\n\n          <h2 className=\"mb-4 text-3xl font-bold\">Social Support 🤝</h2>\n\n          <a\n            href=\"https://twitter.com/intent/tweet?text=Wow:&url=https%3A%2F%2Frahuldkjain.github.io%2Fgithub-profile-readme-generator\"\n            target=\"_blank\"\n            rel=\"noopener noreferrer\"\n          >\n            <img\n              src=\"https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Frahuldkjain.github.io%2Fgithub-profile-readme-generator\"\n              alt=\"tweet github profile readme generator\"\n            />\n          </a>\n\n          <p>Let the world know how you feel using this tool. Share with others on twitter.</p>\n\n          <hr className=\"my-8\" />\n\n          <h2 className=\"mb-4 text-3xl font-bold\">Sponsors 🙏</h2>\n\n          <ul className=\"space-y-3\">\n            <li>\n              <a\n                href=\"https://github.com/scottcwilson\"\n                target=\"_blank\"\n                rel=\"noopener noreferrer\"\n                className=\"text-primary hover:underline\"\n              >\n                Scott C Wilson\n              </a>{' '}\n              donated the first ever grant to this tool. A big thanks to him.\n            </li>\n            <li>\n              <a\n                href=\"https://github.com/mxschmitt\"\n                target=\"_blank\"\n                rel=\"noopener noreferrer\"\n                className=\"text-primary hover:underline\"\n              >\n                Max Schmitt\n              </a>{' '}\n              loved the tool and showed the support with his donation. Thanks a lot.\n            </li>\n          </ul>\n\n          <hr className=\"my-8\" />\n\n          <div className=\"bg-primary/5 border-primary/20 rounded-lg border p-6\">\n            <h3 className=\"mb-3 text-xl font-semibold\">Other Ways to Support</h3>\n            <ul className=\"space-y-2\">\n              <li>⭐ Star the project on GitHub</li>\n              <li>🐛 Report bugs and issues</li>\n              <li>💡 Suggest new features</li>\n              <li>🔧 Contribute code via pull requests</li>\n              <li>📢 Share the tool with your network</li>\n              <li>📝 Write articles or tutorials about the tool</li>\n            </ul>\n          </div>\n        </div>\n      </main>\n\n      <Footer />\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/components/analytics/conditional-analytics.tsx",
    "content": "'use client';\n\nimport { useEffect } from 'react';\nimport { GoogleAnalytics } from '@next/third-parties/google';\nimport { useConsent } from '@/hooks/use-consent';\nimport { initializeAnalytics } from '@/lib/analytics';\n\n/**\n * Conditionally loads Google Analytics based on user consent\n */\nexport function ConditionalAnalytics() {\n  const { status } = useConsent();\n  const gaId = process.env.NEXT_PUBLIC_GA_ID;\n\n  // Initialize analytics when consent is accepted\n  useEffect(() => {\n    if (status === 'accepted' && gaId) {\n      // Small delay to ensure GA4 is loaded\n      const timer = setTimeout(() => {\n        initializeAnalytics();\n      }, 1000);\n\n      return () => clearTimeout(timer);\n    }\n  }, [status, gaId]);\n\n  // Only render GoogleAnalytics if consent is accepted and GA ID exists\n  if (status !== 'accepted' || !gaId) {\n    return null;\n  }\n\n  return <GoogleAnalytics gaId={gaId} />;\n}\n"
  },
  {
    "path": "src/components/forms/__tests__/form-input.test.tsx",
    "content": "import { render, screen } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { describe, it, expect, vi } from 'vitest';\nimport { FormInput } from '../form-input';\n\ndescribe('FormInput', () => {\n  it('renders basic input with label', () => {\n    render(<FormInput id=\"test-input\" label=\"Test Label\" />);\n\n    expect(screen.getByLabelText('Test Label')).toBeInTheDocument();\n    expect(screen.getByRole('textbox')).toBeInTheDocument();\n  });\n\n  it('renders without label when not provided', () => {\n    render(<FormInput id=\"test-input\" placeholder=\"Enter text\" />);\n\n    expect(screen.getByPlaceholderText('Enter text')).toBeInTheDocument();\n    expect(screen.queryByRole('label')).not.toBeInTheDocument();\n  });\n\n  it('shows required asterisk when required prop is true', () => {\n    render(<FormInput id=\"test-input\" label=\"Required Field\" required />);\n\n    expect(screen.getByText('*')).toBeInTheDocument();\n    expect(screen.getByText('*')).toHaveClass('text-destructive');\n  });\n\n  it('displays error message when error prop is provided', () => {\n    const errorMessage = 'This field is required';\n    render(<FormInput id=\"test-input\" label=\"Test Field\" error={errorMessage} />);\n\n    const errorElement = screen.getByRole('alert');\n    expect(errorElement).toBeInTheDocument();\n    expect(errorElement).toHaveTextContent(errorMessage);\n    expect(errorElement).toHaveClass('text-destructive');\n  });\n\n  it('displays helper text when provided and no error', () => {\n    const helperText = 'This is helpful information';\n    render(<FormInput id=\"test-input\" label=\"Test Field\" helperText={helperText} />);\n\n    expect(screen.getByText(helperText)).toBeInTheDocument();\n    expect(screen.getByText(helperText)).toHaveClass('text-muted-foreground');\n  });\n\n  it('hides helper text when error is present', () => {\n    const helperText = 'This is helpful information';\n    const errorMessage = 'Error occurred';\n\n    render(\n      <FormInput id=\"test-input\" label=\"Test Field\" helperText={helperText} error={errorMessage} />\n    );\n\n    expect(screen.getByText(errorMessage)).toBeInTheDocument();\n    expect(screen.queryByText(helperText)).not.toBeInTheDocument();\n  });\n\n  it('applies error styling when error is present', () => {\n    render(<FormInput id=\"test-input\" label=\"Test Field\" error=\"Error message\" />);\n\n    const input = screen.getByRole('textbox');\n    expect(input).toHaveClass('border-destructive', 'focus:ring-destructive');\n  });\n\n  it('applies custom className', () => {\n    const customClass = 'custom-input-class';\n    render(<FormInput id=\"test-input\" className={customClass} />);\n\n    const input = screen.getByRole('textbox');\n    expect(input).toHaveClass(customClass);\n  });\n\n  it('forwards ref correctly', () => {\n    const ref = vi.fn();\n    render(<FormInput ref={ref} id=\"test-input\" />);\n\n    expect(ref).toHaveBeenCalledWith(expect.any(HTMLInputElement));\n  });\n\n  it('handles user input correctly', async () => {\n    const user = userEvent.setup();\n    const handleChange = vi.fn();\n\n    render(<FormInput id=\"test-input\" onChange={handleChange} />);\n\n    const input = screen.getByRole('textbox');\n    await user.type(input, 'Hello World');\n\n    expect(input).toHaveValue('Hello World');\n    expect(handleChange).toHaveBeenCalled();\n  });\n\n  it('passes through all HTML input attributes', () => {\n    render(\n      <FormInput\n        id=\"test-input\"\n        type=\"email\"\n        placeholder=\"Enter email\"\n        disabled\n        maxLength={50}\n        data-testid=\"email-input\"\n      />\n    );\n\n    const input = screen.getByTestId('email-input');\n    expect(input).toHaveAttribute('type', 'email');\n    expect(input).toHaveAttribute('placeholder', 'Enter email');\n    expect(input).toBeDisabled();\n    expect(input).toHaveAttribute('maxLength', '50');\n  });\n\n  it('associates label with input using htmlFor and id', () => {\n    render(<FormInput id=\"test-input\" label=\"Test Label\" />);\n\n    const label = screen.getByText('Test Label');\n    const input = screen.getByRole('textbox');\n\n    expect(label).toHaveAttribute('for', 'test-input');\n    expect(input).toHaveAttribute('id', 'test-input');\n  });\n\n  it('has proper accessibility attributes for error state', () => {\n    render(<FormInput id=\"test-input\" label=\"Test Field\" error=\"Error message\" />);\n\n    const errorElement = screen.getByRole('alert');\n    expect(errorElement).toHaveAttribute('role', 'alert');\n  });\n});\n"
  },
  {
    "path": "src/components/forms/form-checkbox.tsx",
    "content": "'use client';\n\nimport { forwardRef } from 'react';\nimport type { InputHTMLAttributes } from 'react';\n\nexport interface FormCheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {\n  label?: string;\n  error?: string;\n}\n\nexport const FormCheckbox = forwardRef<HTMLInputElement, FormCheckboxProps>(\n  ({ label, error, className = '', ...props }, ref) => {\n    return (\n      <div className=\"w-full space-y-1\">\n        <div className=\"flex items-center gap-2\">\n          <input\n            ref={ref}\n            type=\"checkbox\"\n            className={`border-input bg-background text-primary focus:ring-ring h-4 w-4 rounded transition-colors focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 ${\n              error ? 'border-destructive' : ''\n            } ${className}`}\n            {...props}\n          />\n          {label && (\n            <label htmlFor={props.id} className=\"text-foreground text-sm font-medium\">\n              {label}\n            </label>\n          )}\n        </div>\n        {error && (\n          <p className=\"text-destructive text-sm\" role=\"alert\">\n            {error}\n          </p>\n        )}\n      </div>\n    );\n  }\n);\n\nFormCheckbox.displayName = 'FormCheckbox';\n"
  },
  {
    "path": "src/components/forms/form-input.tsx",
    "content": "'use client';\n\nimport { forwardRef } from 'react';\nimport type { InputHTMLAttributes } from 'react';\n\nexport interface FormInputProps extends InputHTMLAttributes<HTMLInputElement> {\n  label?: string;\n  error?: string;\n  helperText?: string;\n}\n\nexport const FormInput = forwardRef<HTMLInputElement, FormInputProps>(\n  ({ label, error, helperText, className = '', ...props }, ref) => {\n    return (\n      <div className=\"w-full space-y-2\">\n        {label && (\n          <label htmlFor={props.id} className=\"text-foreground block text-sm font-medium\">\n            {label}\n            {props.required && <span className=\"text-destructive ml-1\">*</span>}\n          </label>\n        )}\n        <input\n          ref={ref}\n          className={`border-input bg-background text-foreground placeholder:text-muted-foreground focus:ring-ring w-full rounded-lg border px-4 py-2 transition-colors focus:ring-2 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 ${\n            error ? 'border-destructive focus:ring-destructive' : ''\n          } ${className}`}\n          {...props}\n        />\n        {error && (\n          <p className=\"text-destructive text-sm\" role=\"alert\">\n            {error}\n          </p>\n        )}\n        {helperText && !error && <p className=\"text-muted-foreground text-sm\">{helperText}</p>}\n      </div>\n    );\n  }\n);\n\nFormInput.displayName = 'FormInput';\n"
  },
  {
    "path": "src/components/forms/form-select.tsx",
    "content": "'use client';\n\nimport { forwardRef } from 'react';\nimport { Select, type SelectOption } from '@/components/ui/select';\n\nexport interface FormSelectProps {\n  label?: string;\n  error?: string;\n  helperText?: string;\n  placeholder?: string;\n  options: SelectOption[];\n  value?: string;\n  onChange?: (value: string) => void;\n  disabled?: boolean;\n  required?: boolean;\n  id?: string;\n  className?: string;\n}\n\nexport const FormSelect = forwardRef<HTMLButtonElement, FormSelectProps>((props, ref) => {\n  return <Select ref={ref} {...props} />;\n});\n\nFormSelect.displayName = 'FormSelect';\n"
  },
  {
    "path": "src/components/forms/form-textarea.tsx",
    "content": "'use client';\n\nimport { forwardRef } from 'react';\nimport type { TextareaHTMLAttributes } from 'react';\n\nexport interface FormTextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {\n  label?: string;\n  error?: string;\n  helperText?: string;\n}\n\nexport const FormTextarea = forwardRef<HTMLTextAreaElement, FormTextareaProps>(\n  ({ label, error, helperText, className = '', ...props }, ref) => {\n    return (\n      <div className=\"w-full space-y-2\">\n        {label && (\n          <label htmlFor={props.id} className=\"text-foreground block text-sm font-medium\">\n            {label}\n            {props.required && <span className=\"text-destructive ml-1\">*</span>}\n          </label>\n        )}\n        <textarea\n          ref={ref}\n          className={`border-input bg-background text-foreground placeholder:text-muted-foreground focus:ring-ring w-full rounded-lg border px-4 py-2 transition-colors focus:ring-2 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 ${\n            error ? 'border-destructive focus:ring-destructive' : ''\n          } ${className}`}\n          {...props}\n        />\n        {error && (\n          <p className=\"text-destructive text-sm\" role=\"alert\">\n            {error}\n          </p>\n        )}\n        {helperText && !error && <p className=\"text-muted-foreground text-sm\">{helperText}</p>}\n      </div>\n    );\n  }\n);\n\nFormTextarea.displayName = 'FormTextarea';\n"
  },
  {
    "path": "src/components/forms/github-username-input.tsx",
    "content": "'use client';\n\nimport { forwardRef } from 'react';\nimport {\n  fetchGitHubUser,\n  mapLanguageToSkills,\n  generateSmartSubtitle,\n  type GitHubApiError,\n} from '@/lib/github-api';\nimport { useErrorToast, useToast } from '@/components/ui/toast';\nimport { trackGitHubAutofill } from '@/lib/analytics';\nimport type { ProfileFormData, LinksFormData, SocialFormData } from '@/lib/validations';\n\ninterface GitHubUsernameInputProps {\n  value: string;\n  name?: string;\n  onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;\n  onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;\n  onDataFetched?: (data: {\n    profile: Partial<ProfileFormData>;\n    links: Partial<LinksFormData>;\n    social: Partial<SocialFormData>;\n    skills: string[];\n  }) => void;\n}\n\nexport const GitHubUsernameInput = forwardRef<HTMLInputElement, GitHubUsernameInputProps>(\n  function GitHubUsernameInput({ value, name, onChange, onBlur, onDataFetched }, ref) {\n    const errorToast = useErrorToast();\n    const { promise } = useToast();\n\n    const handleFetch = async () => {\n      if (!value.trim()) {\n        errorToast('Please enter a GitHub username');\n        return;\n      }\n\n      // Track GitHub auto-fill usage\n      trackGitHubAutofill(value.trim());\n\n      try {\n        const userData = await promise(fetchGitHubUser(value.trim()), {\n          loading: `Fetching data for ${value.trim()}...`,\n          success: (data) => `Successfully loaded ${data?.name || value.trim()}'s profile!`,\n          error: (error: GitHubApiError) => error.message,\n        });\n\n        if (!userData) {\n          errorToast('Unable to fetch user data', 'Please check the username and try again.');\n          return;\n        }\n\n        // Map GitHub data to form data\n        const suggestedSkills: string[] = [];\n        userData.topLanguages.forEach((lang) => {\n          suggestedSkills.push(...mapLanguageToSkills(lang));\n        });\n\n        if (onDataFetched) {\n          onDataFetched({\n            profile: {\n              title: userData.name,\n              subtitle: generateSmartSubtitle(userData),\n            },\n            links: {\n              blog: userData.blog,\n            },\n            social: {\n              github: userData.username,\n              twitter: userData.twitter,\n            },\n            skills: [...new Set(suggestedSkills)], // Remove duplicates\n          });\n        }\n      } catch (error) {\n        const apiError = error as GitHubApiError;\n\n        // Handle rate limit errors with retry action\n        if (apiError.type === 'rate_limit') {\n          errorToast(\n            'GitHub API Rate Limit Exceeded',\n            apiError.message,\n            apiError.retryAfter\n              ? {\n                  label: `Retry in ${apiError.retryAfter}m`,\n                  onClick: () => {\n                    setTimeout(() => handleFetch(), apiError.retryAfter! * 60 * 1000);\n                  },\n                }\n              : undefined\n          );\n        } else {\n          // For other errors, show retry action\n          errorToast('Failed to fetch GitHub data', apiError.message, {\n            label: 'Retry',\n            onClick: handleFetch,\n          });\n        }\n      }\n    };\n\n    return (\n      <div className=\"space-y-3\">\n        {/* Mobile: Stack vertically, Desktop: Side by side */}\n        <div className=\"flex flex-col gap-2 sm:flex-row\">\n          <input\n            ref={ref}\n            type=\"text\"\n            name={name}\n            value={value}\n            onChange={onChange}\n            onBlur={onBlur}\n            placeholder=\"Enter GitHub username\"\n            className=\"border-border bg-input focus:border-ring focus:ring-ring w-full rounded-lg border px-3 py-2 text-sm focus:ring-2 focus:outline-none sm:flex-1\"\n            onKeyDown={(e) => {\n              if (e.key === 'Enter') {\n                e.preventDefault();\n                handleFetch();\n              }\n            }}\n          />\n          <button\n            onClick={handleFetch}\n            className=\"bg-primary text-primary-foreground hover:bg-primary/90 w-full rounded-lg px-4 py-2 text-sm font-medium transition-colors sm:w-auto sm:whitespace-nowrap\"\n            aria-label=\"Auto-fill from GitHub profile\"\n          >\n            ✨ Auto-fill\n          </button>\n        </div>\n\n        <p className=\"text-muted-foreground text-xs\">\n          Enter your GitHub username and click \"Auto-fill\" to populate fields with your profile data\n          and suggest relevant skills.\n        </p>\n      </div>\n    );\n  }\n);\n"
  },
  {
    "path": "src/components/layout/footer.tsx",
    "content": "import Link from 'next/link';\nimport Image from 'next/image';\nimport { getAssetPath } from '@/lib/asset-path';\n\nexport function Footer() {\n  return (\n    <footer className=\"border-border bg-card border-t py-8\">\n      <div className=\"container mx-auto px-4\">\n        {/* Logo Section */}\n        <div className=\"mb-8 flex items-center justify-center gap-3\">\n          <Image\n            src={getAssetPath('/mdg.png')}\n            alt=\"GitHub Profile README Generator Logo\"\n            width={48}\n            height={48}\n            className=\"h-12 w-12\"\n            unoptimized\n          />\n          <span className=\"text-xl font-bold\">GitHub Profile README Generator</span>\n        </div>\n\n        <div className=\"grid gap-8 md:grid-cols-4\">\n          {/* About */}\n          <div>\n            <h3 className=\"mb-3 font-semibold\">About</h3>\n            <p className=\"text-muted-foreground text-sm\">\n              Create an awesome GitHub profile README with ease. Made with ❤️ for the developer\n              community.\n            </p>\n          </div>\n\n          {/* Quick Links */}\n          <div>\n            <h3 className=\"mb-3 font-semibold\">Quick Links</h3>\n            <ul className=\"space-y-2 text-sm\">\n              <li>\n                <Link\n                  href=\"/\"\n                  className=\"text-muted-foreground hover:text-primary transition-colors\"\n                >\n                  Generator\n                </Link>\n              </li>\n              <li>\n                <Link\n                  href=\"/addons\"\n                  className=\"text-muted-foreground hover:text-primary transition-colors\"\n                >\n                  Addons\n                </Link>\n              </li>\n              <li>\n                <Link\n                  href=\"/about\"\n                  className=\"text-muted-foreground hover:text-primary transition-colors\"\n                >\n                  About\n                </Link>\n              </li>\n              <li>\n                <Link\n                  href=\"/support\"\n                  className=\"text-muted-foreground hover:text-primary transition-colors\"\n                >\n                  Support\n                </Link>\n              </li>\n            </ul>\n          </div>\n\n          {/* Resources */}\n          <div>\n            <h3 className=\"mb-3 font-semibold\">Resources</h3>\n            <ul className=\"space-y-2 text-sm\">\n              <li>\n                <a\n                  href=\"https://github.com/rahuldkjain/github-profile-readme-generator\"\n                  className=\"text-muted-foreground hover:text-primary transition-colors\"\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                >\n                  GitHub Repository\n                </a>\n              </li>\n              <li>\n                <a\n                  href=\"https://github.com/rahuldkjain/github-profile-readme-generator/issues\"\n                  className=\"text-muted-foreground hover:text-primary transition-colors\"\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                >\n                  Report Issues\n                </a>\n              </li>\n              <li>\n                <a\n                  href=\"https://github.com/rahuldkjain/github-profile-readme-generator/blob/master/LICENSE\"\n                  className=\"text-muted-foreground hover:text-primary transition-colors\"\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                >\n                  License\n                </a>\n              </li>\n            </ul>\n          </div>\n\n          {/* Connect */}\n          <div>\n            <h3 className=\"mb-3 font-semibold\">Connect</h3>\n            <ul className=\"space-y-2 text-sm\">\n              <li>\n                <a\n                  href=\"https://github.com/rahuldkjain\"\n                  className=\"text-muted-foreground hover:text-primary transition-colors\"\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                >\n                  GitHub\n                </a>\n              </li>\n              <li>\n                <a\n                  href=\"https://twitter.com/rahuldkjain\"\n                  className=\"text-muted-foreground hover:text-primary transition-colors\"\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                >\n                  Twitter\n                </a>\n              </li>\n              <li>\n                <a\n                  href=\"https://linkedin.com/in/rahuldkjain\"\n                  className=\"text-muted-foreground hover:text-primary transition-colors\"\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                >\n                  LinkedIn\n                </a>\n              </li>\n            </ul>\n          </div>\n        </div>\n\n        <div className=\"text-muted-foreground border-border mt-8 border-t pt-6 text-center text-sm\">\n          <p>\n            © {new Date().getFullYear()} GitHub Profile README Generator. Made with ❤️ by{' '}\n            <a\n              href=\"https://github.com/rahuldkjain\"\n              className=\"text-primary font-medium hover:underline\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n            >\n              Rahul Jain\n            </a>\n          </p>\n          <p className=\"mt-2\">\n            Open source under the{' '}\n            <a\n              href=\"https://github.com/rahuldkjain/github-profile-readme-generator/blob/master/LICENSE\"\n              className=\"text-primary hover:underline\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n            >\n              Apache License 2.0\n            </a>\n          </p>\n        </div>\n      </div>\n    </footer>\n  );\n}\n"
  },
  {
    "path": "src/components/layout/header.tsx",
    "content": "'use client';\n\nimport Link from 'next/link';\nimport Image from 'next/image';\nimport { usePathname } from 'next/navigation';\nimport { ThemeToggle } from '@/components/ui/theme-toggle';\nimport { AccessibilityMenu } from '@/components/ui/accessibility-menu';\nimport { GitHubStats } from '@/components/ui/github-stats';\nimport { getAssetPath } from '@/lib/asset-path';\n\nconst navigation = [\n  { name: 'Generator', href: '/' },\n  { name: 'Addons', href: '/addons' },\n  { name: 'About', href: '/about' },\n  { name: 'Support', href: '/support' },\n];\n\ninterface HeaderProps {\n  saveStatus?: 'idle' | 'saving' | 'saved';\n  lastSaved?: Date | null;\n}\n\nexport function Header({}: HeaderProps = {}) {\n  const pathname = usePathname();\n\n  return (\n    <header className=\"border-border bg-card sticky top-0 z-50 border-b\">\n      <div className=\"container mx-auto px-4 py-4\">\n        <div className=\"flex items-center justify-between gap-4\">\n          {/* Logo, Title, and GitHub Stats */}\n          <div className=\"flex items-center gap-4\">\n            <Link href=\"/\" prefetch={true} className=\"flex items-center gap-3 hover:opacity-80\">\n              <Image\n                src={getAssetPath('/mdg.png')}\n                alt=\"GitHub Profile README Generator Logo\"\n                width={40}\n                height={40}\n                className=\"h-10 w-10\"\n                priority\n                unoptimized\n              />\n              <span className=\"hidden text-xl font-bold sm:inline-block lg:text-2xl\">\n                GitHub Profile README Generator\n              </span>\n            </Link>\n            <GitHubStats />\n          </div>\n\n          {/* Right side content */}\n          <div className=\"flex items-center gap-3\">\n            <nav className=\"hidden lg:block\" aria-label=\"Main navigation\">\n              <ul className=\"flex gap-4\">\n                {navigation.map((item) => {\n                  // Normalize paths for comparison (remove trailing slashes)\n                  const normalizedPathname = pathname.replace(/\\/$/, '') || '/';\n                  const normalizedHref = item.href.replace(/\\/$/, '') || '/';\n                  const isActive = normalizedPathname === normalizedHref;\n                  return (\n                    <li key={item.name}>\n                      <Link\n                        href={item.href}\n                        prefetch={true}\n                        className={`hover:text-primary text-sm font-medium transition-colors ${\n                          isActive ? 'text-primary font-semibold' : 'text-muted-foreground'\n                        }`}\n                        aria-current={isActive ? 'page' : undefined}\n                      >\n                        {item.name}\n                      </Link>\n                    </li>\n                  );\n                })}\n              </ul>\n            </nav>\n\n            <div className=\"flex items-center gap-2\">\n              <AccessibilityMenu />\n              <ThemeToggle />\n            </div>\n          </div>\n        </div>\n\n        {/* Mobile Navigation */}\n        <nav className=\"mt-4 lg:hidden\" aria-label=\"Mobile navigation\">\n          <ul className=\"flex gap-4 overflow-x-auto\">\n            {navigation.map((item) => {\n              // Normalize paths for comparison (remove trailing slashes)\n              const normalizedPathname = pathname.replace(/\\/$/, '') || '/';\n              const normalizedHref = item.href.replace(/\\/$/, '') || '/';\n              const isActive = normalizedPathname === normalizedHref;\n              return (\n                <li key={item.name}>\n                  <Link\n                    href={item.href}\n                    prefetch={true}\n                    className={`hover:text-primary text-sm font-medium whitespace-nowrap transition-colors ${\n                      isActive ? 'text-primary font-semibold' : 'text-muted-foreground'\n                    }`}\n                    aria-current={isActive ? 'page' : undefined}\n                  >\n                    {item.name}\n                  </Link>\n                </li>\n              );\n            })}\n          </ul>\n        </nav>\n      </div>\n    </header>\n  );\n}\n"
  },
  {
    "path": "src/components/layout/theme-provider.tsx",
    "content": "'use client';\n\nimport { useEffect, useState } from 'react';\nimport { useTheme } from '@/hooks/use-theme';\nimport { useThemeStore } from '@/lib/store';\n\nexport function ThemeProvider({ children }: { children: React.ReactNode }) {\n  const [mounted, setMounted] = useState(false);\n  const { accessibility } = useThemeStore();\n  useTheme(); // Initialize theme\n\n  useEffect(() => {\n    setMounted(true);\n  }, []);\n\n  // Apply accessibility settings to document\n  useEffect(() => {\n    if (!mounted) return;\n\n    const root = document.documentElement;\n\n    // High contrast mode\n    if (accessibility.highContrast) {\n      root.classList.add('high-contrast');\n    } else {\n      root.classList.remove('high-contrast');\n    }\n\n    // Font size\n    root.classList.remove('text-small', 'text-large');\n    if (accessibility.fontSize === 'small') {\n      root.classList.add('text-small');\n    } else if (accessibility.fontSize === 'large') {\n      root.classList.add('text-large');\n    }\n\n    // Reduced motion (already handled by CSS)\n    if (accessibility.reducedMotion) {\n      root.style.setProperty('--motion-reduce', '1');\n    } else {\n      root.style.removeProperty('--motion-reduce');\n    }\n  }, [mounted, accessibility]);\n\n  // Prevent flash of unstyled content\n  if (!mounted) {\n    return <div style={{ visibility: 'hidden' }}>{children}</div>;\n  }\n\n  return <>{children}</>;\n}\n"
  },
  {
    "path": "src/components/sections/basic-info-section.tsx",
    "content": "'use client';\n\nimport { Upload } from 'lucide-react';\n\nimport { useState, useEffect } from 'react';\nimport { UseFormRegister, FieldErrors, UseFormWatch } from 'react-hook-form';\nimport { FormInput } from '@/components/forms/form-input';\nimport { FormTextarea } from '@/components/forms/form-textarea';\nimport { FormCheckbox } from '@/components/forms/form-checkbox';\nimport { GitHubUsernameInput } from '@/components/forms/github-username-input';\nimport { CollapsibleSection } from '@/components/ui/collapsible-section';\nimport type { ProfileFormData, LinksFormData, SocialFormData } from '@/lib/validations';\n\ninterface BasicInfoSectionProps {\n  register: UseFormRegister<ProfileFormData>;\n  errors: FieldErrors<ProfileFormData>;\n  socialRegister: UseFormRegister<SocialFormData>;\n  watchSocial: UseFormWatch<SocialFormData>;\n  onGitHubAutoFill?: (data: {\n    profile: Partial<ProfileFormData>;\n    links: Partial<LinksFormData>;\n    social: Partial<SocialFormData>;\n    skills: string[];\n  }) => void;\n  onImportJSON?: (event: React.ChangeEvent<HTMLInputElement>) => void;\n  onClearAll?: () => void;\n  hasClearableData?: boolean;\n}\n\nexport function BasicInfoSection({\n  register,\n  errors,\n  socialRegister,\n  watchSocial,\n  onGitHubAutoFill,\n  onImportJSON,\n  onClearAll,\n  hasClearableData = true,\n}: BasicInfoSectionProps) {\n  const githubUsername = watchSocial('github') || '';\n  const [isMobile, setIsMobile] = useState(false);\n\n  useEffect(() => {\n    const checkMobile = () => {\n      setIsMobile(window.innerWidth < 768);\n    };\n    checkMobile();\n    window.addEventListener('resize', checkMobile);\n    return () => window.removeEventListener('resize', checkMobile);\n  }, []);\n\n  return (\n    <div className=\"space-y-6\">\n      <div className=\"border-border border-b pb-4\">\n        <div className=\"flex items-center justify-between\">\n          <div>\n            <h2 className=\"text-2xl font-bold\">Basic Information</h2>\n            <p className=\"text-muted-foreground mt-1 text-sm\">\n              Tell us about yourself and what you do\n            </p>\n          </div>\n          {/* Action Buttons */}\n          <div className=\"flex items-center gap-2\">\n            {/* Clear All Button */}\n            {onClearAll && (\n              <button\n                onClick={onClearAll}\n                disabled={!hasClearableData}\n                className={`flex items-center justify-center rounded-lg border p-3 transition-colors ${\n                  hasClearableData\n                    ? 'bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground border-border'\n                    : 'bg-muted text-muted-foreground border-border cursor-not-allowed opacity-50'\n                }`}\n                title={hasClearableData ? 'Clear all data' : 'No data to clear'}\n                aria-label={hasClearableData ? 'Clear all data' : 'No data to clear'}\n              >\n                <svg className=\"h-5 w-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n                  <path\n                    strokeLinecap=\"round\"\n                    strokeLinejoin=\"round\"\n                    strokeWidth={2}\n                    d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n                  />\n                </svg>\n                <span className=\"ml-2 text-sm\">Clear All</span>\n              </button>\n            )}\n\n            {/* Import JSON Button */}\n            {onImportJSON && (\n              <label className=\"bg-secondary text-secondary-foreground hover:bg-secondary/90 flex cursor-pointer items-center justify-center rounded-lg p-3 transition-colors\">\n                <Upload className=\"h-5 w-5\" />\n                <input\n                  type=\"file\"\n                  accept=\".json\"\n                  onChange={onImportJSON}\n                  className=\"hidden\"\n                  title=\"Import profile data from JSON\"\n                  aria-label=\"Import profile data from JSON\"\n                />\n              </label>\n            )}\n          </div>\n        </div>\n      </div>\n\n      {/* Quick Start: GitHub Auto-fill */}\n      {onGitHubAutoFill && (\n        <div className=\"border-primary/30 bg-primary/5 rounded-lg border-2 p-4\">\n          <div className=\"mb-3 flex items-start gap-2\">\n            <span className=\"text-2xl\">🚀</span>\n            <div className=\"flex-1\">\n              <h3 className=\"text-sm font-semibold\">Quick Start with GitHub</h3>\n              <p className=\"text-muted-foreground mt-1 text-xs\">\n                Enter your GitHub username to automatically populate your profile with smart\n                defaults\n              </p>\n            </div>\n          </div>\n          <GitHubUsernameInput\n            {...socialRegister('github')}\n            value={githubUsername}\n            onDataFetched={onGitHubAutoFill}\n          />\n        </div>\n      )}\n\n      {/* Basic Fields - Always visible */}\n      <div className=\"grid gap-6 md:grid-cols-2\">\n        <FormInput\n          {...register('title')}\n          id=\"title\"\n          label=\"Your Name\"\n          placeholder=\"John Doe\"\n          error={errors.title?.message}\n          required\n        />\n\n        <FormInput\n          {...register('subtitle')}\n          id=\"subtitle\"\n          label=\"Subtitle\"\n          placeholder=\"A passionate developer\"\n          error={errors.subtitle?.message}\n        />\n      </div>\n\n      {/* Additional Fields - Collapsible on mobile */}\n      {isMobile ? (\n        <div className=\"space-y-3\">\n          <CollapsibleSection title=\"Current Work\" icon=\"🔭\" description=\"What you're working on\">\n            <FormTextarea\n              {...register('currentWork')}\n              id=\"currentWork\"\n              label=\"I'm currently working on\"\n              placeholder=\"a MERN Stack project\"\n              rows={2}\n              error={errors.currentWork?.message}\n            />\n          </CollapsibleSection>\n\n          <CollapsibleSection title=\"Learning\" icon=\"🌱\" description=\"What you're learning\">\n            <FormTextarea\n              {...register('currentLearn')}\n              id=\"currentLearn\"\n              label=\"I'm currently learning\"\n              placeholder=\"GraphQL and TypeScript\"\n              rows={2}\n              error={errors.currentLearn?.message}\n            />\n          </CollapsibleSection>\n\n          <CollapsibleSection\n            title=\"Collaboration\"\n            icon=\"👯\"\n            description=\"What you want to collaborate on\"\n          >\n            <FormTextarea\n              {...register('collaborateOn')}\n              id=\"collaborateOn\"\n              label=\"I'm looking to collaborate on\"\n              placeholder=\"open source projects\"\n              rows={2}\n              error={errors.collaborateOn?.message}\n            />\n          </CollapsibleSection>\n\n          <CollapsibleSection title=\"Help Needed\" icon=\"🤝\" description=\"What you need help with\">\n            <FormTextarea\n              {...register('helpWith')}\n              id=\"helpWith\"\n              label=\"I'm looking for help with\"\n              placeholder=\"learning system design\"\n              rows={2}\n              error={errors.helpWith?.message}\n            />\n          </CollapsibleSection>\n\n          <CollapsibleSection title=\"Ask Me About\" icon=\"💬\" description=\"Your areas of expertise\">\n            <FormTextarea\n              {...register('ama')}\n              id=\"ama\"\n              label=\"Ask me about\"\n              placeholder=\"React, Node.js, and web development\"\n              rows={2}\n              error={errors.ama?.message}\n            />\n          </CollapsibleSection>\n\n          <CollapsibleSection title=\"Contact\" icon=\"📫\" description=\"How to reach you\">\n            <FormInput\n              {...register('contact')}\n              id=\"contact\"\n              label=\"How to reach me\"\n              type=\"email\"\n              placeholder=\"your.email@example.com\"\n              error={errors.contact?.message}\n            />\n          </CollapsibleSection>\n\n          <CollapsibleSection\n            title=\"Fun Fact\"\n            icon=\"⚡\"\n            description=\"Something interesting about you\"\n          >\n            <FormTextarea\n              {...register('funFact')}\n              id=\"funFact\"\n              label=\"Fun fact\"\n              placeholder=\"I think I am funny\"\n              rows={2}\n              error={errors.funFact?.message}\n            />\n          </CollapsibleSection>\n        </div>\n      ) : (\n        <>\n          <FormTextarea\n            {...register('currentWork')}\n            id=\"currentWork\"\n            label=\"🔭 I'm currently working on\"\n            placeholder=\"a MERN Stack project\"\n            rows={2}\n            error={errors.currentWork?.message}\n          />\n\n          <FormTextarea\n            {...register('currentLearn')}\n            id=\"currentLearn\"\n            label=\"🌱 I'm currently learning\"\n            placeholder=\"GraphQL and TypeScript\"\n            rows={2}\n            error={errors.currentLearn?.message}\n          />\n\n          <FormTextarea\n            {...register('collaborateOn')}\n            id=\"collaborateOn\"\n            label=\"👯 I'm looking to collaborate on\"\n            placeholder=\"open source projects\"\n            rows={2}\n            error={errors.collaborateOn?.message}\n          />\n\n          <FormTextarea\n            {...register('helpWith')}\n            id=\"helpWith\"\n            label=\"🤝 I'm looking for help with\"\n            placeholder=\"learning system design\"\n            rows={2}\n            error={errors.helpWith?.message}\n          />\n\n          <FormTextarea\n            {...register('ama')}\n            id=\"ama\"\n            label=\"💬 Ask me about\"\n            placeholder=\"React, Node.js, and web development\"\n            rows={2}\n            error={errors.ama?.message}\n          />\n\n          <FormInput\n            {...register('contact')}\n            id=\"contact\"\n            label=\"📫 How to reach me\"\n            type=\"email\"\n            placeholder=\"your.email@example.com\"\n            error={errors.contact?.message}\n          />\n\n          <FormTextarea\n            {...register('funFact')}\n            id=\"funFact\"\n            label=\"⚡ Fun fact\"\n            placeholder=\"I think I am funny\"\n            rows={2}\n            error={errors.funFact?.message}\n          />\n        </>\n      )}\n\n      {/* Profile Badge Option */}\n      <div className=\"border-border mt-6 border-t pt-6\">\n        <div className=\"bg-accent/50 rounded-lg p-4\">\n          <h4 className=\"mb-2 flex items-center gap-2 text-sm font-semibold\">\n            <span>📊</span>\n            <span>Profile Enhancement</span>\n          </h4>\n          <FormCheckbox\n            {...register('visitorsBadge')}\n            id=\"visitorsBadge\"\n            label=\"Show profile visitors counter badge\"\n          />\n        </div>\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/components/sections/links-section.tsx",
    "content": "'use client';\n\nimport { UseFormRegister, FieldErrors } from 'react-hook-form';\nimport { FormInput } from '@/components/forms/form-input';\nimport type { LinksFormData } from '@/lib/validations';\n\ninterface LinksSectionProps {\n  register: UseFormRegister<LinksFormData>;\n  errors: FieldErrors<LinksFormData>;\n}\n\nexport function LinksSection({ register, errors }: LinksSectionProps) {\n  return (\n    <div className=\"space-y-6\">\n      <div className=\"border-b border-border pb-4\">\n        <h2 className=\"text-2xl font-bold\">Links</h2>\n        <p className=\"text-muted-foreground mt-1 text-sm\">\n          Add links to your portfolio, blog, and resume\n        </p>\n      </div>\n\n      <FormInput\n        {...register('portfolio')}\n        id=\"portfolio\"\n        label=\"👨‍💻 Portfolio\"\n        type=\"url\"\n        placeholder=\"https://yourportfolio.com\"\n        error={errors.portfolio?.message}\n        helperText=\"Your personal website or portfolio\"\n      />\n\n      <FormInput\n        {...register('blog')}\n        id=\"blog\"\n        label=\"📝 Blog\"\n        type=\"url\"\n        placeholder=\"https://yourblog.com\"\n        error={errors.blog?.message}\n        helperText=\"Where you write articles\"\n      />\n\n      <FormInput\n        {...register('resume')}\n        id=\"resume\"\n        label=\"📄 Resume/CV\"\n        type=\"url\"\n        placeholder=\"https://drive.google.com/your-resume\"\n        error={errors.resume?.message}\n        helperText=\"Link to your resume or CV\"\n      />\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/components/sections/skills-section.tsx",
    "content": "'use client';\n\nimport { useState, useMemo, useEffect } from 'react';\nimport { Info } from 'lucide-react';\nimport { UseFormRegister } from 'react-hook-form';\nimport { FormCheckbox } from '@/components/forms/form-checkbox';\nimport { FormInput } from '@/components/forms/form-input';\nimport { Select } from '@/components/ui/select';\nimport { CollapsibleSection } from '@/components/ui/collapsible-section';\nimport { categorizedSkills, categories } from '@/constants/skills';\nimport { getSkillIconUrl } from '@/lib/markdown-generator';\nimport type { ProfileFormData } from '@/lib/validations';\n\ninterface SkillsSectionProps {\n  selectedSkills: Record<string, boolean>;\n  onSkillChange: (skill: string, checked: boolean) => void;\n  registerProfile: UseFormRegister<ProfileFormData>;\n}\n\nexport function SkillsSection({\n  selectedSkills,\n  onSkillChange,\n  registerProfile,\n}: SkillsSectionProps) {\n  const [searchQuery, setSearchQuery] = useState('');\n  const [selectedCategory, setSelectedCategory] = useState<string>('all');\n  const [isMobile, setIsMobile] = useState(false);\n\n  // Check if we're on mobile for responsive behavior\n  useEffect(() => {\n    const checkMobile = () => {\n      setIsMobile(window.innerWidth < 768);\n    };\n    checkMobile();\n    window.addEventListener('resize', checkMobile);\n    return () => window.removeEventListener('resize', checkMobile);\n  }, []);\n\n  const selectedCount = useMemo(() => {\n    return Object.values(selectedSkills).filter(Boolean).length;\n  }, [selectedSkills]);\n\n  const filteredCategories = useMemo(() => {\n    if (selectedCategory !== 'all') {\n      return [selectedCategory];\n    }\n    return categories;\n  }, [selectedCategory]);\n\n  const filterSkills = (skills: string[]) => {\n    if (!searchQuery) return skills;\n    return skills.filter((skill) => skill.toLowerCase().includes(searchQuery.toLowerCase()));\n  };\n\n  // Create options for the select component\n  const categoryOptions = [\n    { value: 'all', label: 'All Categories' },\n    ...categories.map((category) => ({\n      value: category,\n      label: categorizedSkills[category].title,\n    })),\n  ];\n\n  return (\n    <div className=\"space-y-6\">\n      <div className=\"border-border border-b pb-4\">\n        <div className=\"flex items-center justify-between\">\n          <div>\n            <h2 className=\"text-2xl font-bold\">Skills & Technologies</h2>\n            <p className=\"text-muted-foreground mt-1 text-sm\">\n              Select the skills you want to showcase ({selectedCount} selected)\n            </p>\n          </div>\n        </div>\n      </div>\n\n      {/* Search and Filter - Stack on mobile */}\n      <div className=\"flex flex-col gap-4 sm:grid sm:grid-cols-2\">\n        <FormInput\n          id=\"skill-search\"\n          placeholder=\"Search skills...\"\n          value={searchQuery}\n          onChange={(e) => setSearchQuery(e.target.value)}\n        />\n\n        <Select\n          value={selectedCategory}\n          onChange={setSelectedCategory}\n          options={categoryOptions}\n          placeholder=\"Select category\"\n        />\n      </div>\n\n      {/* Skills Grid - Responsive layout */}\n      <div className=\"space-y-6\">\n        {filteredCategories.map((category) => {\n          const { title, skills } = categorizedSkills[category];\n          const filtered = filterSkills(skills);\n\n          if (filtered.length === 0) return null;\n\n          const skillsGrid = (\n            <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5\">\n              {filtered.map((skill) => {\n                const iconUrl = getSkillIconUrl(skill);\n                const isSelected = selectedSkills[skill] || false;\n\n                return (\n                  <button\n                    key={skill}\n                    type=\"button\"\n                    onClick={() => onSkillChange(skill, !isSelected)}\n                    className={`relative flex flex-col items-center gap-2 rounded-lg border-2 p-2 transition-all hover:scale-105 sm:p-3 ${\n                      isSelected\n                        ? 'border-primary bg-primary/10'\n                        : 'border-border hover:border-primary/50'\n                    }`}\n                    aria-pressed={isSelected}\n                  >\n                    <img\n                      src={iconUrl}\n                      alt={skill}\n                      className=\"h-8 w-8 object-contain sm:h-10 sm:w-10\"\n                      loading=\"eager\"\n                    />\n                    <span className=\"text-center text-xs leading-tight capitalize\">\n                      {skill.replace(/_/g, ' ')}\n                    </span>\n                    {isSelected && (\n                      <div className=\"bg-primary absolute top-1 right-1 h-2 w-2 rounded-full\" />\n                    )}\n                  </button>\n                );\n              })}\n            </div>\n          );\n\n          // On mobile, use collapsible sections for better organization\n          if (isMobile && selectedCategory === 'all') {\n            return (\n              <CollapsibleSection\n                key={category}\n                title={title}\n                description={`${filtered.length} skills available`}\n                icon=\"🛠️\"\n                defaultOpen={filtered.some((skill) => selectedSkills[skill])}\n              >\n                {skillsGrid}\n              </CollapsibleSection>\n            );\n          }\n\n          // Desktop layout or when a specific category is selected\n          return (\n            <div key={category} className=\"space-y-4\">\n              <h3 className=\"text-lg font-semibold\">{title}</h3>\n              {skillsGrid}\n            </div>\n          );\n        })}\n      </div>\n\n      {searchQuery &&\n        filteredCategories.every(\n          (cat) => filterSkills(categorizedSkills[cat].skills).length === 0\n        ) && (\n          <div className=\"text-muted-foreground py-8 text-center\">\n            <p>No skills found matching \"{searchQuery}\"</p>\n          </div>\n        )}\n\n      {/* GitHub Stats & Badges - Mobile-friendly layout */}\n      <div className=\"border-border mt-8 border-t pt-6\">\n        <div\n          className={`space-y-4 rounded-lg p-4 transition-all sm:p-6 ${selectedCount > 0 ? 'bg-accent/50' : 'bg-muted/30'}`}\n        >\n          <div>\n            <h4 className=\"mb-1 flex items-center gap-2 text-base font-semibold sm:text-lg\">\n              <span>📈</span>\n              <span>GitHub Profile Enhancements</span>\n            </h4>\n            <p className=\"text-muted-foreground text-sm\">\n              Add visual statistics and achievements to your profile\n            </p>\n            {selectedCount === 0 && (\n              <p className=\"text-muted-foreground mt-2 flex items-center gap-1 text-xs\">\n                <Info className=\"h-3 w-3\" />\n                Select at least one skill above to enable these enhancements\n              </p>\n            )}\n          </div>\n\n          {/* Mobile: Use collapsible section, Desktop: Show grid */}\n          {isMobile ? (\n            <CollapsibleSection\n              title=\"Enhancement Options\"\n              description={`${selectedCount > 0 ? 'Available' : 'Disabled'} - Select skills first`}\n              icon=\"⚙️\"\n              defaultOpen={selectedCount > 0}\n            >\n              <div\n                className={`space-y-3 ${selectedCount === 0 ? 'pointer-events-none opacity-50' : ''}`}\n              >\n                <FormCheckbox\n                  {...registerProfile('githubStats')}\n                  id=\"githubStats\"\n                  label=\"GitHub Stats Card\"\n                  disabled={selectedCount === 0}\n                />\n                <FormCheckbox\n                  {...registerProfile('topLanguages')}\n                  id=\"topLanguages\"\n                  label=\"Top Languages Card\"\n                  disabled={selectedCount === 0}\n                />\n                <FormCheckbox\n                  {...registerProfile('streakStats')}\n                  id=\"streakStats\"\n                  label=\"GitHub Streak Stats\"\n                  disabled={selectedCount === 0}\n                />\n                <FormCheckbox\n                  {...registerProfile('githubProfileTrophy')}\n                  id=\"githubProfileTrophy\"\n                  label=\"GitHub Profile Trophy\"\n                  disabled={selectedCount === 0}\n                />\n              </div>\n            </CollapsibleSection>\n          ) : (\n            <div\n              className={`grid gap-3 sm:grid-cols-2 ${selectedCount === 0 ? 'pointer-events-none opacity-50' : ''}`}\n            >\n              <FormCheckbox\n                {...registerProfile('githubStats')}\n                id=\"githubStats\"\n                label=\"GitHub Stats Card\"\n                disabled={selectedCount === 0}\n              />\n              <FormCheckbox\n                {...registerProfile('topLanguages')}\n                id=\"topLanguages\"\n                label=\"Top Languages Card\"\n                disabled={selectedCount === 0}\n              />\n              <FormCheckbox\n                {...registerProfile('streakStats')}\n                id=\"streakStats\"\n                label=\"GitHub Streak Stats\"\n                disabled={selectedCount === 0}\n              />\n              <FormCheckbox\n                {...registerProfile('githubProfileTrophy')}\n                id=\"githubProfileTrophy\"\n                label=\"GitHub Profile Trophy\"\n                disabled={selectedCount === 0}\n              />\n            </div>\n          )}\n        </div>\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/components/sections/social-section.tsx",
    "content": "'use client';\n\nimport { Info } from 'lucide-react';\n\nimport { UseFormRegister, FieldErrors, UseFormWatch } from 'react-hook-form';\nimport { FormInput } from '@/components/forms/form-input';\nimport { FormCheckbox } from '@/components/forms/form-checkbox';\nimport type { SocialFormData } from '@/lib/validations';\n\ninterface SocialSectionProps {\n  register: UseFormRegister<SocialFormData>;\n  errors: FieldErrors<SocialFormData>;\n  watch: UseFormWatch<SocialFormData>;\n}\n\nexport function SocialSection({ register, errors, watch }: SocialSectionProps) {\n  const socialPlatforms = [\n    { key: 'github', label: 'GitHub', icon: '🐙', placeholder: 'username' },\n    { key: 'linkedin', label: 'LinkedIn', icon: '💼', placeholder: 'username' },\n    { key: 'twitter', label: 'Twitter', icon: '🐦', placeholder: 'username' },\n    { key: 'dev', label: 'Dev.to', icon: '📝', placeholder: 'username' },\n    { key: 'stackoverflow', label: 'Stack Overflow', icon: '📚', placeholder: 'userid/username' },\n    { key: 'medium', label: 'Medium', icon: '✍️', placeholder: '@username' },\n    { key: 'youtube', label: 'YouTube', icon: '📺', placeholder: 'channel-id' },\n    { key: 'instagram', label: 'Instagram', icon: '📷', placeholder: 'username' },\n    { key: 'fb', label: 'Facebook', icon: '👤', placeholder: 'username' },\n    { key: 'codepen', label: 'CodePen', icon: '🖊️', placeholder: 'username' },\n    { key: 'codesandbox', label: 'CodeSandbox', icon: '📦', placeholder: 'username' },\n    { key: 'kaggle', label: 'Kaggle', icon: '🔬', placeholder: 'username' },\n    { key: 'leetcode', label: 'LeetCode', icon: '💻', placeholder: 'username' },\n    { key: 'hackerrank', label: 'HackerRank', icon: '🏆', placeholder: 'username' },\n    { key: 'codeforces', label: 'Codeforces', icon: '⚡', placeholder: 'username' },\n    { key: 'codechef', label: 'CodeChef', icon: '👨‍🍳', placeholder: 'username' },\n    { key: 'topcoder', label: 'TopCoder', icon: '🥇', placeholder: 'username' },\n    { key: 'hackerearth', label: 'HackerEarth', icon: '🌍', placeholder: '@username' },\n    { key: 'geeks_for_geeks', label: 'GeeksforGeeks', icon: '🤓', placeholder: 'username' },\n    { key: 'dribbble', label: 'Dribbble', icon: '🎨', placeholder: 'username' },\n    { key: 'behance', label: 'Behance', icon: '🎭', placeholder: 'username' },\n    { key: 'discord', label: 'Discord', icon: '💬', placeholder: 'invite-code' },\n    { key: 'rssurl', label: 'RSS Feed', icon: '📡', placeholder: 'https://...' },\n  ];\n\n  return (\n    <div className=\"space-y-6\">\n      <div className=\"border-border border-b pb-4\">\n        <h2 className=\"text-2xl font-bold\">Social Profiles</h2>\n        <p className=\"text-muted-foreground mt-1 text-sm\">\n          Connect your social media and coding platforms\n        </p>\n      </div>\n\n      {/* Instructions Banner */}\n      <div className=\"border-primary/30 bg-primary/5 rounded-lg border-2 p-4\">\n        <div className=\"flex gap-3\">\n          <div className=\"flex-shrink-0\">\n            <svg\n              className=\"text-primary h-5 w-5\"\n              fill=\"none\"\n              viewBox=\"0 0 24 24\"\n              stroke=\"currentColor\"\n            >\n              <path\n                strokeLinecap=\"round\"\n                strokeLinejoin=\"round\"\n                strokeWidth={2}\n                d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n              />\n            </svg>\n          </div>\n          <div className=\"flex-1\">\n            <h4 className=\"mb-1 text-sm font-semibold\">Enter usernames only, not full URLs</h4>\n            <p className=\"text-muted-foreground mb-2 text-sm\">\n              Just provide your username or handle for each platform. We'll automatically generate\n              the correct URLs.\n            </p>\n            <div className=\"text-muted-foreground space-y-1 text-xs\">\n              <div className=\"flex items-center gap-2\">\n                <span className=\"text-green-600 dark:text-green-400\">✓</span>\n                <span>\n                  <strong>Correct:</strong> johndoe\n                </span>\n              </div>\n              <div className=\"flex items-center gap-2\">\n                <span className=\"text-red-600 dark:text-red-400\">✗</span>\n                <span>\n                  <strong>Incorrect:</strong> https://twitter.com/johndoe\n                </span>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <div className=\"grid gap-4 md:grid-cols-2\">\n        {socialPlatforms.map(({ key, label, icon, placeholder }) => (\n          <FormInput\n            key={key}\n            {...register(key as keyof SocialFormData)}\n            id={key}\n            label={`${icon} ${label}`}\n            placeholder={placeholder}\n            error={errors[key as keyof SocialFormData]?.message}\n          />\n        ))}\n      </div>\n\n      {/* Twitter Badge Option - Show always with disabled state and hint */}\n      <div className=\"border-border mt-6 border-t pt-6\">\n        <div\n          className={`rounded-lg p-4 transition-all ${watch('twitter') ? 'bg-accent/50' : 'bg-muted/30'}`}\n        >\n          <h4 className=\"mb-2 flex items-center gap-2 text-sm font-semibold\">\n            <span>🐦</span>\n            <span>Twitter Enhancement</span>\n          </h4>\n          {!watch('twitter') && (\n            <p className=\"text-muted-foreground mb-3 flex items-center gap-1 text-xs\">\n              <Info className=\"h-3 w-3\" />\n              Enter your Twitter username above to enable this feature\n            </p>\n          )}\n          <div className={!watch('twitter') ? 'pointer-events-none opacity-50' : ''}>\n            <FormCheckbox\n              {...register('twitterBadge')}\n              id=\"twitterBadge\"\n              label=\"Show Twitter follow badge on profile\"\n              disabled={!watch('twitter')}\n            />\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/components/ui/accessibility-menu.tsx",
    "content": "'use client';\n\nimport { useState } from 'react';\nimport { Settings } from 'lucide-react';\nimport { Select } from '@/components/ui/select';\nimport { useThemeStore } from '@/lib/store';\n\nexport function AccessibilityMenu() {\n  const [isOpen, setIsOpen] = useState(false);\n  const { accessibility, setAccessibility } = useThemeStore();\n\n  // Font size options for the select component\n  const fontSizeOptions = [\n    { value: 'small', label: 'Small' },\n    { value: 'medium', label: 'Medium (Default)' },\n    { value: 'large', label: 'Large' },\n  ];\n\n  return (\n    <div className=\"relative\">\n      <button\n        onClick={() => setIsOpen(!isOpen)}\n        className=\"border-border bg-card hover:bg-accent flex h-11 w-11 items-center justify-center rounded-lg border !p-3 transition-colors\"\n        aria-label=\"Accessibility settings\"\n        title=\"Accessibility settings\"\n        aria-expanded={isOpen}\n      >\n        <Settings className=\"h-5 w-5\" />\n      </button>\n\n      {isOpen && (\n        <>\n          {/* Backdrop */}\n          <div className=\"fixed inset-0 z-40\" onClick={() => setIsOpen(false)} aria-hidden=\"true\" />\n\n          {/* Menu */}\n          <div className=\"border-border bg-card absolute top-full right-0 z-50 mt-2 w-72 rounded-lg border p-4 shadow-lg\">\n            <h3 className=\"mb-4 text-sm font-semibold\">Accessibility Settings</h3>\n\n            <div className=\"space-y-4\">\n              {/* High Contrast */}\n              <label className=\"flex cursor-pointer items-center justify-between\">\n                <span className=\"text-sm\">High Contrast Mode</span>\n                <input\n                  type=\"checkbox\"\n                  checked={accessibility.highContrast}\n                  onChange={(e) => setAccessibility({ highContrast: e.target.checked })}\n                  className=\"border-border bg-input text-primary focus:ring-ring h-4 w-4 rounded focus:ring-2\"\n                />\n              </label>\n\n              {/* Font Size */}\n              <div className=\"space-y-2\">\n                <Select\n                  label=\"Font Size\"\n                  value={accessibility.fontSize}\n                  onChange={(value) =>\n                    setAccessibility({ fontSize: value as 'small' | 'medium' | 'large' })\n                  }\n                  options={fontSizeOptions}\n                  id=\"fontSize\"\n                />\n              </div>\n\n              {/* Reduced Motion */}\n              <label className=\"flex cursor-pointer items-center justify-between\">\n                <span className=\"text-sm\">Reduce Motion</span>\n                <input\n                  type=\"checkbox\"\n                  checked={accessibility.reducedMotion}\n                  onChange={(e) => setAccessibility({ reducedMotion: e.target.checked })}\n                  className=\"border-border bg-input text-primary focus:ring-ring h-4 w-4 rounded focus:ring-2\"\n                />\n              </label>\n            </div>\n\n            <p className=\"border-border text-muted-foreground mt-4 border-t pt-3 text-xs\">\n              These settings are saved locally and persist across sessions.\n            </p>\n          </div>\n        </>\n      )}\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/components/ui/buy-me-coffee.tsx",
    "content": "'use client';\n\nimport { useEffect } from 'react';\n\nexport function BuyMeACoffeeWidget() {\n  useEffect(() => {\n    const script = document.createElement('script');\n    script.setAttribute('data-name', 'BMC-Widget');\n    script.src = 'https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js';\n    script.setAttribute('data-id', 'rahuldkjain');\n    script.setAttribute('data-description', 'Support rahuldkjain on Buy me a coffee!');\n    script.setAttribute('data-message', '');\n    script.setAttribute('data-color', '#ffdd00');\n    script.setAttribute('data-position', 'Right');\n    script.setAttribute('data-x_margin', '18');\n    script.setAttribute('data-y_margin', '18');\n    script.async = true;\n\n    script.onload = function () {\n      const event = new CustomEvent('DOMContentLoaded', {\n        bubbles: true,\n        cancelable: true,\n      });\n      window.dispatchEvent(event);\n    };\n\n    document.head.appendChild(script);\n\n    return () => {\n      document.head.removeChild(script);\n      const widget = document.getElementById('bmc-wbtn');\n      if (widget) {\n        document.body.removeChild(widget);\n      }\n    };\n  }, []);\n\n  return null;\n}\n"
  },
  {
    "path": "src/components/ui/collapsible-section.tsx",
    "content": "'use client';\n\nimport { useState } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { ChevronDown } from 'lucide-react';\n\ninterface CollapsibleSectionProps {\n  title: string;\n  description?: string;\n  icon?: string;\n  defaultOpen?: boolean;\n  children: React.ReactNode;\n}\n\nexport function CollapsibleSection({\n  title,\n  description,\n  icon,\n  defaultOpen = false,\n  children,\n}: CollapsibleSectionProps) {\n  const [isOpen, setIsOpen] = useState(defaultOpen);\n\n  return (\n    <div className=\"border-border bg-card rounded-lg border\">\n      <button\n        onClick={() => setIsOpen(!isOpen)}\n        className=\"hover:bg-accent/50 flex w-full items-center justify-between p-4 text-left transition-colors\"\n        aria-expanded={isOpen}\n        aria-label={`${isOpen ? 'Collapse' : 'Expand'} ${title} section`}\n      >\n        <div className=\"flex items-center gap-3\">\n          {icon && <span className=\"text-xl\">{icon}</span>}\n          <div>\n            <h3 className=\"text-sm font-semibold\">{title}</h3>\n            {description && <p className=\"text-muted-foreground mt-0.5 text-xs\">{description}</p>}\n          </div>\n        </div>\n        <motion.div\n          animate={{ rotate: isOpen ? 180 : 0 }}\n          transition={{ duration: 0.2 }}\n          aria-hidden=\"true\"\n        >\n          <ChevronDown className=\"h-5 w-5\" />\n        </motion.div>\n      </button>\n\n      <AnimatePresence initial={false}>\n        {isOpen && (\n          <motion.div\n            initial={{ height: 0, opacity: 0 }}\n            animate={{ height: 'auto', opacity: 1 }}\n            exit={{ height: 0, opacity: 0 }}\n            transition={{ duration: 0.2, ease: 'easeInOut' }}\n            style={{ overflow: 'hidden' }}\n          >\n            <div className=\"border-border border-t p-4\">{children}</div>\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/components/ui/confirm-dialog.tsx",
    "content": "'use client';\n\nimport { useState } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { AlertTriangle, X } from 'lucide-react';\n\ninterface ConfirmDialogProps {\n  isOpen: boolean;\n  onClose: () => void;\n  onConfirm: () => void;\n  title: string;\n  message: string;\n  confirmText?: string;\n  cancelText?: string;\n  variant?: 'danger' | 'warning' | 'info';\n}\n\nexport function ConfirmDialog({\n  isOpen,\n  onClose,\n  onConfirm,\n  title,\n  message,\n  confirmText = 'Confirm',\n  cancelText = 'Cancel',\n  variant = 'danger',\n}: ConfirmDialogProps) {\n  const handleConfirm = () => {\n    onConfirm();\n    onClose();\n  };\n\n  const variantStyles = {\n    danger: {\n      icon: 'text-red-600',\n      confirmButton: 'bg-red-600 hover:bg-red-700 text-white',\n      backdrop: 'bg-red-50',\n    },\n    warning: {\n      icon: 'text-amber-600',\n      confirmButton: 'bg-amber-600 hover:bg-amber-700 text-white',\n      backdrop: 'bg-amber-50',\n    },\n    info: {\n      icon: 'text-blue-600',\n      confirmButton: 'bg-blue-600 hover:bg-blue-700 text-white',\n      backdrop: 'bg-blue-50',\n    },\n  };\n\n  const styles = variantStyles[variant];\n\n  return (\n    <AnimatePresence>\n      {isOpen && (\n        <>\n          {/* Backdrop */}\n          <motion.div\n            initial={{ opacity: 0 }}\n            animate={{ opacity: 1 }}\n            exit={{ opacity: 0 }}\n            className=\"fixed inset-0 z-50 bg-black/50 backdrop-blur-sm\"\n            onClick={onClose}\n            aria-hidden=\"true\"\n          />\n\n          {/* Dialog */}\n          <motion.div\n            initial={{ opacity: 0, scale: 0.95, y: 20 }}\n            animate={{ opacity: 1, scale: 1, y: 0 }}\n            exit={{ opacity: 0, scale: 0.95, y: 20 }}\n            transition={{ type: 'spring', duration: 0.3 }}\n            className=\"fixed top-1/2 left-1/2 z-50 w-full max-w-md -translate-x-1/2 -translate-y-1/2 p-4\"\n            role=\"dialog\"\n            aria-labelledby=\"confirm-dialog-title\"\n            aria-describedby=\"confirm-dialog-description\"\n            aria-modal=\"true\"\n          >\n            <div className=\"bg-card border-border rounded-xl border shadow-2xl\">\n              {/* Header */}\n              <div className=\"flex items-start gap-4 p-6 pb-4\">\n                <div className={`rounded-full p-2 ${styles.backdrop}`}>\n                  <AlertTriangle className={`h-5 w-5 ${styles.icon}`} />\n                </div>\n                <div className=\"flex-1\">\n                  <h3 id=\"confirm-dialog-title\" className=\"text-lg leading-6 font-semibold\">\n                    {title}\n                  </h3>\n                  <p\n                    id=\"confirm-dialog-description\"\n                    className=\"text-muted-foreground mt-2 text-sm leading-relaxed\"\n                  >\n                    {message}\n                  </p>\n                </div>\n                <button\n                  onClick={onClose}\n                  className=\"text-muted-foreground hover:text-foreground rounded-lg p-1 transition-colors\"\n                  aria-label=\"Close dialog\"\n                >\n                  <X className=\"h-4 w-4\" />\n                </button>\n              </div>\n\n              {/* Actions */}\n              <div className=\"flex gap-3 p-6 pt-2\">\n                <button\n                  onClick={onClose}\n                  className=\"border-border hover:bg-accent flex-1 rounded-lg border px-4 py-2 text-sm font-medium transition-colors\"\n                >\n                  {cancelText}\n                </button>\n                <button\n                  onClick={handleConfirm}\n                  className={`flex-1 rounded-lg px-4 py-2 text-sm font-medium transition-colors ${styles.confirmButton}`}\n                >\n                  {confirmText}\n                </button>\n              </div>\n            </div>\n          </motion.div>\n        </>\n      )}\n    </AnimatePresence>\n  );\n}\n\n/**\n * Hook for using confirmation dialogs\n */\nexport function useConfirmDialog() {\n  const [isOpen, setIsOpen] = useState(false);\n  const [config, setConfig] = useState<\n    Omit<ConfirmDialogProps, 'isOpen' | 'onClose' | 'onConfirm'>\n  >({\n    title: '',\n    message: '',\n  });\n  const [confirmCallback, setConfirmCallback] = useState<(() => void) | null>(null);\n\n  const showConfirm = (\n    options: Omit<ConfirmDialogProps, 'isOpen' | 'onClose' | 'onConfirm'> & {\n      onConfirm: () => void;\n    }\n  ) => {\n    const { onConfirm, ...rest } = options;\n    setConfig(rest);\n    setConfirmCallback(() => onConfirm);\n    setIsOpen(true);\n  };\n\n  const closeDialog = () => {\n    setIsOpen(false);\n    // Clear callback after a small delay to prevent race conditions\n    setTimeout(() => {\n      setConfirmCallback(null);\n    }, 100);\n  };\n\n  const handleConfirm = () => {\n    if (confirmCallback) {\n      confirmCallback();\n    }\n    closeDialog();\n  };\n\n  const ConfirmDialogComponent = () => (\n    <ConfirmDialog isOpen={isOpen} onClose={closeDialog} onConfirm={handleConfirm} {...config} />\n  );\n\n  return {\n    showConfirm,\n    ConfirmDialog: ConfirmDialogComponent,\n  };\n}\n"
  },
  {
    "path": "src/components/ui/cookie-consent.tsx",
    "content": "'use client';\n\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { Cookie, ShieldCheck } from 'lucide-react';\nimport { useConsent } from '@/hooks/use-consent';\n\nexport function CookieConsent() {\n  const { showBanner, acceptConsent, rejectConsent } = useConsent();\n\n  return (\n    <AnimatePresence>\n      {showBanner && (\n        <>\n          {/* Backdrop */}\n          <motion.div\n            initial={{ opacity: 0 }}\n            animate={{ opacity: 1 }}\n            exit={{ opacity: 0 }}\n            className=\"fixed inset-0 z-40 bg-black/20 backdrop-blur-sm\"\n            aria-hidden=\"true\"\n          />\n\n          {/* Consent Banner */}\n          <motion.div\n            initial={{ opacity: 0, y: 100, scale: 0.95 }}\n            animate={{ opacity: 1, y: 0, scale: 1 }}\n            exit={{ opacity: 0, y: 100, scale: 0.95 }}\n            transition={{ type: 'spring', duration: 0.5 }}\n            className=\"fixed right-4 bottom-4 left-4 z-50 mx-auto max-w-2xl\"\n            role=\"dialog\"\n            aria-labelledby=\"cookie-consent-title\"\n            aria-describedby=\"cookie-consent-description\"\n          >\n            <div className=\"bg-card border-border rounded-xl border p-6 shadow-2xl\">\n              {/* Header */}\n              <div className=\"mb-4 flex items-start gap-3\">\n                <div className=\"bg-primary/10 text-primary rounded-lg p-2\">\n                  <Cookie className=\"h-5 w-5\" />\n                </div>\n                <div className=\"flex-1\">\n                  <h3 id=\"cookie-consent-title\" className=\"text-lg font-semibold\">\n                    We use cookies to improve your experience\n                  </h3>\n                  <p\n                    id=\"cookie-consent-description\"\n                    className=\"text-muted-foreground mt-1 text-sm leading-relaxed\"\n                  >\n                    We use Google Analytics to understand how you interact with our site and improve\n                    your experience. Your data is anonymized and we don't track personal\n                    information.\n                  </p>\n                </div>\n              </div>\n\n              {/* Privacy Info */}\n              <div className=\"bg-muted/50 mb-4 rounded-lg p-3\">\n                <div className=\"flex items-center gap-2 text-sm\">\n                  <ShieldCheck className=\"h-4 w-4 text-green-600\" />\n                  <span className=\"font-medium\">Privacy-friendly tracking</span>\n                </div>\n                <ul className=\"text-muted-foreground mt-2 space-y-1 text-xs\">\n                  <li>• IP addresses are anonymized</li>\n                  <li>• No personal data is collected</li>\n                  <li>• You can opt-out anytime</li>\n                </ul>\n              </div>\n\n              {/* Actions */}\n              <div className=\"flex flex-col gap-3 sm:flex-row sm:justify-between\">\n                <div className=\"flex gap-2\">\n                  <button\n                    onClick={acceptConsent}\n                    className=\"bg-primary text-primary-foreground hover:bg-primary/90 flex-1 rounded-lg px-4 py-2 text-sm font-medium transition-colors sm:flex-none\"\n                  >\n                    Accept Analytics\n                  </button>\n                  <button\n                    onClick={rejectConsent}\n                    className=\"border-border hover:bg-accent flex-1 rounded-lg border px-4 py-2 text-sm font-medium transition-colors sm:flex-none\"\n                  >\n                    Reject\n                  </button>\n                </div>\n\n                {/* Learn More Link */}\n                <div className=\"flex items-center justify-center text-xs\">\n                  <a\n                    href=\"https://policies.google.com/privacy\"\n                    target=\"_blank\"\n                    rel=\"noopener noreferrer\"\n                    className=\"text-muted-foreground hover:text-foreground underline transition-colors\"\n                  >\n                    Learn about Google's privacy policy\n                  </a>\n                </div>\n              </div>\n            </div>\n          </motion.div>\n        </>\n      )}\n    </AnimatePresence>\n  );\n}\n\n/**\n * Privacy Settings Component (for settings page or footer)\n */\nexport function PrivacySettings() {\n  const { status, resetConsent } = useConsent();\n\n  if (status === 'pending') {\n    return null;\n  }\n\n  return (\n    <div className=\"border-border bg-card rounded-lg border p-4\">\n      <div className=\"flex items-center justify-between\">\n        <div>\n          <h4 className=\"font-medium\">Analytics Cookies</h4>\n          <p className=\"text-muted-foreground text-sm\">\n            Status: {status === 'accepted' ? 'Enabled' : 'Disabled'}\n          </p>\n        </div>\n        <button\n          onClick={resetConsent}\n          className=\"border-border hover:bg-accent rounded-lg border px-3 py-2 text-sm transition-colors\"\n        >\n          Change Settings\n        </button>\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/components/ui/github-stats.tsx",
    "content": "'use client';\n\nimport { useEffect, useState } from 'react';\nimport { motion } from 'framer-motion';\nimport { useErrorToast } from '@/components/ui/toast';\n\ninterface GitHubStats {\n  stars: number;\n  forks: number;\n}\n\nexport function GitHubStats() {\n  const [stats, setStats] = useState<GitHubStats | null>(null);\n  const [isLoading, setIsLoading] = useState(true);\n  const [error, setError] = useState(false);\n  const errorToast = useErrorToast();\n\n  useEffect(() => {\n    // Smart request logic like original\n    const shouldRequestStats = () => {\n      const isFirstRequest = stats === null;\n      const isVisible = typeof window !== 'undefined' && document.visibilityState === 'visible';\n      const hasFocus = typeof window !== 'undefined' && document.hasFocus();\n      return isFirstRequest || (isVisible && hasFocus);\n    };\n\n    const fetchStats = async () => {\n      if (!shouldRequestStats()) return;\n\n      try {\n        const response = await fetch(\n          'https://api.github.com/repos/rahuldkjain/github-profile-readme-generator'\n        );\n\n        if (!response.ok) {\n          if (response.status === 403) {\n            const rateLimitRemaining = response.headers.get('X-RateLimit-Remaining');\n            if (rateLimitRemaining === '0') {\n              console.warn('GitHub API rate limit exceeded for stats');\n              setError(true);\n              setIsLoading(false);\n              return;\n            }\n          }\n          throw new Error(`Failed to fetch stats (${response.status})`);\n        }\n\n        const data = await response.json();\n        setStats({\n          stars: data.stargazers_count || 0,\n          forks: data.forks_count || 0,\n        });\n        setIsLoading(false);\n      } catch (err) {\n        console.error('Error fetching GitHub stats:', err);\n        setError(true);\n        setIsLoading(false);\n\n        // Only show error toast on first load, not on periodic refreshes\n        if (stats === null) {\n          errorToast(\n            'Failed to load GitHub stats',\n            \"Unable to fetch repository statistics. This won't affect the generator functionality.\",\n            {\n              label: 'Retry',\n              onClick: fetchStats,\n            }\n          );\n        }\n      }\n    };\n\n    // Initial fetch\n    fetchStats();\n\n    // Periodic refresh like original (every minute)\n    const interval = setInterval(fetchStats, 60000);\n\n    return () => clearInterval(interval);\n  }, []); // Remove stats dependency to prevent infinite loop\n\n  if (error || isLoading) {\n    return null; // Don't show anything if loading or error\n  }\n\n  if (!stats) {\n    return null;\n  }\n\n  return (\n    <motion.div\n      className=\"hidden items-center gap-3 lg:flex\"\n      initial={{ opacity: 0, y: -10 }}\n      animate={{ opacity: 1, y: 0 }}\n      transition={{ duration: 0.5, ease: 'easeOut' }}\n    >\n      {/* Star Button - Styled like original */}\n      <motion.a\n        href=\"https://github.com/rahuldkjain/github-profile-readme-generator\"\n        target=\"_blank\"\n        rel=\"noopener noreferrer\"\n        className=\"border-foreground bg-muted hover:bg-accent flex items-center gap-1.5 border-2 px-3 py-1.5 text-xs font-medium transition-colors\"\n        title=\"Star rahuldkjain/github-profile-readme-generator on GitHub\"\n        whileHover={{ scale: 1.05 }}\n        whileTap={{ scale: 0.95 }}\n      >\n        <motion.svg\n          className=\"h-4 w-4\"\n          fill=\"currentColor\"\n          viewBox=\"0 0 20 20\"\n          aria-hidden=\"true\"\n          animate={{\n            rotate: [0, 360],\n            scale: [1, 1.1, 1],\n          }}\n          transition={{\n            duration: 2,\n            ease: 'easeInOut',\n            repeat: Infinity,\n            repeatType: 'reverse',\n          }}\n        >\n          <path d=\"M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z\" />\n        </motion.svg>\n        <span>Stars</span>\n        <span className=\"font-bold\">{stats.stars.toLocaleString()}</span>\n      </motion.a>\n\n      {/* Fork Button - Styled like original */}\n      <motion.a\n        href=\"https://github.com/rahuldkjain/github-profile-readme-generator/fork\"\n        target=\"_blank\"\n        rel=\"noopener noreferrer\"\n        className=\"border-foreground bg-muted hover:bg-accent flex items-center gap-1.5 border-2 px-3 py-1.5 text-xs font-medium transition-colors\"\n        title=\"Fork rahuldkjain/github-profile-readme-generator on GitHub\"\n        whileHover={{ scale: 1.05 }}\n        whileTap={{ scale: 0.95 }}\n      >\n        <motion.svg\n          className=\"h-4 w-4\"\n          fill=\"currentColor\"\n          viewBox=\"0 0 16 16\"\n          aria-hidden=\"true\"\n          animate={{\n            rotate: [0, 360],\n            scale: [1, 1.1, 1],\n          }}\n          transition={{\n            duration: 2,\n            ease: 'easeInOut',\n            repeat: Infinity,\n            repeatType: 'reverse',\n          }}\n        >\n          <path d=\"M5 3.25a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm0 2.122a2.25 2.25 0 10-1.5 0v.878A2.25 2.25 0 005.75 8.5h1.5v2.128a2.251 2.251 0 101.5 0V8.5h1.5a2.25 2.25 0 002.25-2.25v-.878a2.25 2.25 0 10-1.5 0v.878a.75.75 0 01-.75.75h-4.5A.75.75 0 015 6.25v-.878zm3.75 7.378a.75.75 0 11-1.5 0 .75.75 0 011.5 0zm3-8.75a.75.75 0 100-1.5.75.75 0 000 1.5z\" />\n        </motion.svg>\n        <span>Forks</span>\n        <span className=\"font-bold\">{stats.forks.toLocaleString()}</span>\n      </motion.a>\n    </motion.div>\n  );\n}\n"
  },
  {
    "path": "src/components/ui/markdown-preview.tsx",
    "content": "'use client';\n\nimport { useState, memo, useMemo } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport rehypeRaw from 'rehype-raw';\nimport rehypeSanitize from 'rehype-sanitize';\nimport { trackFileExported } from '@/lib/analytics';\n\ninterface MarkdownPreviewProps {\n  markdown: string;\n  title?: string;\n}\n\nexport const MarkdownPreview = memo(function MarkdownPreview({\n  markdown,\n  title = 'Preview',\n}: MarkdownPreviewProps) {\n  const [viewMode, setViewMode] = useState<'preview' | 'markdown'>('preview');\n  const [copied, setCopied] = useState(false);\n\n  const handleCopy = async () => {\n    try {\n      await navigator.clipboard.writeText(markdown);\n      setCopied(true);\n      setTimeout(() => setCopied(false), 2000);\n\n      // Track copy event\n      trackFileExported('copy', 'markdown');\n    } catch (err) {\n      console.error('Failed to copy:', err);\n    }\n  };\n\n  const handleDownload = () => {\n    const blob = new Blob([markdown], { type: 'text/markdown' });\n    const url = URL.createObjectURL(blob);\n    const a = document.createElement('a');\n    a.href = url;\n    a.download = 'README.md';\n    document.body.appendChild(a);\n    a.click();\n    document.body.removeChild(a);\n    URL.revokeObjectURL(url);\n\n    // Track download event\n    trackFileExported('download', 'markdown');\n  };\n\n  // Memoize custom components to prevent ReactMarkdown re-renders\n  const markdownComponents = useMemo(\n    () => ({\n      // Custom rendering to maintain alignment and styling\n      p: ({ children }: any) => <p className=\"my-2\">{children}</p>,\n      h1: ({ children }: any) => <h1 className=\"mb-4 text-center text-xl font-bold\">{children}</h1>,\n      h3: ({ children }: any) => <h3 className=\"mb-2 text-lg font-semibold\">{children}</h3>,\n      img: ({ src, alt, width }: any) => {\n        // Skill icons have width=40, resize them responsively\n        if (width === '40' || width === 40) {\n          return (\n            <img src={src} alt={alt} className=\"mr-4 mb-4 inline-block h-6 w-6 sm:h-10 sm:w-10\" />\n          );\n        }\n        // Other images (badges, stats, etc.) keep their original size\n        return <img src={src} alt={alt} className=\"inline-block\" />;\n      },\n      a: ({ href, children }: any) => (\n        <a\n          href={href}\n          className=\"text-blue-600 no-underline hover:underline dark:text-blue-400\"\n          target=\"_blank\"\n          rel=\"noreferrer\"\n        >\n          {children}\n        </a>\n      ),\n    }),\n    [] // Empty deps - components never change\n  );\n\n  return (\n    <div className=\"space-y-4\" role=\"region\" aria-label=\"Markdown preview and export\">\n      {/* Header with actions - Aligned layout */}\n      <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n        <h3 className=\"text-lg font-semibold\" id=\"preview-title\">\n          {title}\n        </h3>\n        <div\n          className=\"flex items-center justify-between gap-4\"\n          role=\"toolbar\"\n          aria-label=\"Preview actions\"\n        >\n          {/* View Mode Toggle - With border */}\n          <div\n            className=\"border-border inline-flex rounded-lg border\"\n            role=\"group\"\n            aria-label=\"View mode toggle\"\n          >\n            <button\n              onClick={() => setViewMode('preview')}\n              className={`rounded-l-lg px-3 py-2 text-sm font-medium transition-colors ${\n                viewMode === 'preview' ? 'bg-primary text-primary-foreground' : 'hover:bg-accent'\n              }`}\n              aria-pressed={viewMode === 'preview'}\n              aria-label=\"Show rendered preview\"\n            >\n              Preview\n            </button>\n            <button\n              onClick={() => setViewMode('markdown')}\n              className={`border-border rounded-r-lg border-l px-3 py-2 text-sm font-medium transition-colors ${\n                viewMode === 'markdown' ? 'bg-primary text-primary-foreground' : 'hover:bg-accent'\n              }`}\n              aria-pressed={viewMode === 'markdown'}\n              aria-label=\"Show raw markdown\"\n            >\n              Markdown\n            </button>\n          </div>\n\n          {/* Action buttons - Aligned to end */}\n          <div className=\"flex items-center gap-2\">\n            {/* Copy Button */}\n            <button\n              onClick={handleCopy}\n              className=\"border-border hover:bg-accent rounded-lg border p-2 transition-colors\"\n              aria-label=\"Copy markdown to clipboard\"\n              title=\"Copy markdown to clipboard\"\n            >\n              {copied ? (\n                <svg\n                  className=\"h-4 w-4 text-green-600\"\n                  fill=\"none\"\n                  viewBox=\"0 0 24 24\"\n                  stroke=\"currentColor\"\n                >\n                  <path\n                    strokeLinecap=\"round\"\n                    strokeLinejoin=\"round\"\n                    strokeWidth={2}\n                    d=\"M5 13l4 4L19 7\"\n                  />\n                </svg>\n              ) : (\n                <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n                  <path\n                    strokeLinecap=\"round\"\n                    strokeLinejoin=\"round\"\n                    strokeWidth={2}\n                    d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\"\n                  />\n                </svg>\n              )}\n            </button>\n\n            {/* Download Button */}\n            <button\n              onClick={handleDownload}\n              className=\"bg-primary text-primary-foreground hover:bg-primary/90 rounded-lg p-2 transition-colors\"\n              aria-label=\"Download README.md file\"\n              title=\"Download README.md file\"\n            >\n              <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n                <path\n                  strokeLinecap=\"round\"\n                  strokeLinejoin=\"round\"\n                  strokeWidth={2}\n                  d=\"M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n                />\n              </svg>\n            </button>\n          </div>\n        </div>\n      </div>\n\n      {/* Content */}\n      <div className=\"border-border bg-card min-h-[400px] rounded-lg border p-6\">\n        {/* Copy success announcement for screen readers */}\n        {copied && (\n          <div className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n            Markdown copied to clipboard successfully\n          </div>\n        )}\n\n        {viewMode === 'preview' ? (\n          <div className=\"markdown-preview\" role=\"document\" aria-labelledby=\"preview-title\">\n            <ReactMarkdown\n              remarkPlugins={[remarkGfm]}\n              rehypePlugins={[rehypeRaw, rehypeSanitize]}\n              components={markdownComponents}\n            >\n              {markdown}\n            </ReactMarkdown>\n          </div>\n        ) : (\n          <pre className=\"text-foreground overflow-x-auto text-sm break-words whitespace-pre-wrap\">\n            {markdown}\n          </pre>\n        )}\n      </div>\n    </div>\n  );\n});\n"
  },
  {
    "path": "src/components/ui/select.tsx",
    "content": "'use client';\n\nimport { Fragment, forwardRef } from 'react';\nimport {\n  Listbox,\n  ListboxButton,\n  ListboxOptions,\n  ListboxOption,\n  Transition,\n} from '@headlessui/react';\nimport { ChevronDown, Check } from 'lucide-react';\n\nexport interface SelectOption {\n  value: string;\n  label: string;\n}\n\nexport interface SelectProps {\n  label?: string;\n  error?: string;\n  helperText?: string;\n  placeholder?: string;\n  options: SelectOption[];\n  value?: string;\n  onChange?: (value: string) => void;\n  disabled?: boolean;\n  required?: boolean;\n  id?: string;\n  className?: string;\n}\n\nexport const Select = forwardRef<HTMLButtonElement, SelectProps>(\n  (\n    {\n      label,\n      error,\n      helperText,\n      placeholder = 'Select an option',\n      options,\n      value,\n      onChange,\n      disabled = false,\n      required = false,\n      id,\n      className = '',\n    },\n    ref\n  ) => {\n    const selectedOption = options.find((option) => option.value === value);\n\n    return (\n      <div className={`w-full space-y-2 ${className}`}>\n        {label && (\n          <label htmlFor={id} className=\"text-foreground block text-sm font-medium\">\n            {label}\n            {required && <span className=\"text-destructive ml-1\">*</span>}\n          </label>\n        )}\n\n        <Listbox value={value} onChange={onChange} disabled={disabled}>\n          <div className=\"relative\">\n            <ListboxButton\n              ref={ref}\n              id={id}\n              className={`border-input bg-background text-foreground focus:ring-ring relative w-full cursor-default rounded-lg border py-2 pr-10 pl-4 text-left transition-colors focus:ring-2 focus:outline-none ${\n                error ? 'border-destructive focus:ring-destructive' : ''\n              } ${disabled ? 'cursor-not-allowed opacity-50' : 'hover:bg-accent/50'}`}\n            >\n              <span className=\"block truncate\">\n                {selectedOption ? selectedOption.label : placeholder}\n              </span>\n              <span className=\"pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3\">\n                <ChevronDown className=\"text-muted-foreground h-4 w-4\" aria-hidden=\"true\" />\n              </span>\n            </ListboxButton>\n\n            <Transition\n              as={Fragment}\n              leave=\"transition ease-in duration-100\"\n              leaveFrom=\"opacity-100\"\n              leaveTo=\"opacity-0\"\n            >\n              <ListboxOptions className=\"border-border bg-background text-foreground absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-lg border py-1 shadow-lg focus:outline-none\">\n                {options.map((option) => (\n                  <ListboxOption\n                    key={option.value}\n                    className={({ active }) =>\n                      `relative cursor-default py-2 pr-4 pl-10 transition-colors select-none ${\n                        active ? 'bg-accent text-accent-foreground' : ''\n                      }`\n                    }\n                    value={option.value}\n                  >\n                    {({ selected }) => (\n                      <>\n                        <span\n                          className={`block truncate ${selected ? 'font-medium' : 'font-normal'}`}\n                        >\n                          {option.label}\n                        </span>\n                        {selected ? (\n                          <span className=\"text-primary absolute inset-y-0 left-0 flex items-center pl-3\">\n                            <Check className=\"h-4 w-4\" aria-hidden=\"true\" />\n                          </span>\n                        ) : null}\n                      </>\n                    )}\n                  </ListboxOption>\n                ))}\n              </ListboxOptions>\n            </Transition>\n          </div>\n        </Listbox>\n\n        {error && (\n          <p className=\"text-destructive text-sm\" role=\"alert\">\n            {error}\n          </p>\n        )}\n        {helperText && !error && <p className=\"text-muted-foreground text-sm\">{helperText}</p>}\n      </div>\n    );\n  }\n);\n\nSelect.displayName = 'Select';\n"
  },
  {
    "path": "src/components/ui/theme-toggle.tsx",
    "content": "'use client';\n\nimport { useEffect, useState } from 'react';\nimport { Sun, Moon, Monitor } from 'lucide-react';\nimport { useTheme } from '@/hooks/use-theme';\nimport type { ThemeMode } from '@/types/theme';\n\nexport function ThemeToggle() {\n  const { theme, setTheme } = useTheme();\n  const [mounted, setMounted] = useState(false);\n\n  // Prevent hydration mismatch by only rendering after mount\n  useEffect(() => {\n    setMounted(true);\n  }, []);\n\n  const handleToggle = () => {\n    const modes: ThemeMode[] = ['light', 'dark', 'system'];\n    const currentIndex = modes.indexOf(theme);\n    const nextIndex = (currentIndex + 1) % modes.length;\n    setTheme(modes[nextIndex]);\n  };\n\n  const getIcon = () => {\n    switch (theme) {\n      case 'light':\n        return <Sun className=\"h-5 w-5\" />;\n      case 'dark':\n        return <Moon className=\"h-5 w-5\" />;\n      case 'system':\n        return <Monitor className=\"h-5 w-5\" />;\n    }\n  };\n\n  // Render a skeleton button during SSR to prevent layout shift\n  if (!mounted) {\n    return (\n      <button\n        className=\"border-border bg-card flex h-11 w-11 items-center justify-center rounded-lg border !p-3\"\n        aria-label=\"Toggle theme\"\n        title=\"Toggle theme\"\n        disabled\n      >\n        <Monitor className=\"h-5 w-5\" />\n      </button>\n    );\n  }\n\n  return (\n    <button\n      onClick={handleToggle}\n      className=\"border-border bg-card hover:bg-accent flex h-11 w-11 items-center justify-center rounded-lg border !p-3 transition-colors\"\n      aria-label={`Switch to ${theme === 'light' ? 'dark' : theme === 'dark' ? 'system' : 'light'} mode`}\n      title={`Current: ${theme} mode. Click to switch.`}\n    >\n      {getIcon()}\n    </button>\n  );\n}\n"
  },
  {
    "path": "src/components/ui/toast.tsx",
    "content": "'use client';\n\nimport { createContext, useContext, useState, useCallback, ReactNode } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { CheckCircle, XCircle, AlertTriangle, Info, X, Loader2 } from 'lucide-react';\n\ninterface Toast {\n  id: string;\n  type: 'success' | 'error' | 'warning' | 'info' | 'loading';\n  title: string;\n  description?: string;\n  duration?: number;\n  action?: {\n    label: string;\n    onClick: () => void;\n  };\n  dismissible?: boolean;\n}\n\ninterface ToastContextType {\n  toasts: Toast[];\n  addToast: (toast: Omit<Toast, 'id'>) => void;\n  removeToast: (id: string) => void;\n  updateToast: (id: string, updates: Partial<Toast>) => void;\n  promise: <T>(\n    promise: Promise<T>,\n    options: {\n      loading: string;\n      success: string | ((data: T) => string);\n      error: string | ((error: any) => string);\n    }\n  ) => Promise<T>;\n}\n\nconst ToastContext = createContext<ToastContextType | undefined>(undefined);\n\nexport function ToastProvider({ children }: { children: ReactNode }) {\n  const [toasts, setToasts] = useState<Toast[]>([]);\n\n  const addToast = useCallback((toast: Omit<Toast, 'id'>) => {\n    const id =\n      typeof crypto !== 'undefined' && crypto.randomUUID\n        ? crypto.randomUUID()\n        : Math.random().toString(36).substring(2, 11);\n    const duration = toast.duration ?? (toast.type === 'loading' ? 0 : 5000);\n    const dismissible = toast.dismissible ?? true;\n    const newToast: Toast = {\n      ...toast,\n      id,\n      duration,\n      dismissible,\n    };\n\n    setToasts((prev) => [...prev, newToast]);\n\n    // Auto-remove toast after duration (except loading toasts)\n    if (duration > 0 && toast.type !== 'loading') {\n      setTimeout(() => {\n        removeToast(id);\n      }, duration);\n    }\n\n    return id;\n  }, []);\n\n  const removeToast = useCallback((id: string) => {\n    setToasts((prev) => prev.filter((toast) => toast.id !== id));\n  }, []);\n\n  const updateToast = useCallback((id: string, updates: Partial<Toast>) => {\n    setToasts((prev) => prev.map((toast) => (toast.id === id ? { ...toast, ...updates } : toast)));\n  }, []);\n\n  const promiseToast = useCallback(\n    async <T,>(\n      promise: Promise<T>,\n      options: {\n        loading: string;\n        success: string | ((data: T) => string);\n        error: string | ((error: any) => string);\n      }\n    ): Promise<T> => {\n      const loadingId = addToast({\n        type: 'loading',\n        title: options.loading,\n        duration: 0,\n        dismissible: false,\n      });\n\n      try {\n        const data = await promise;\n\n        // Remove loading toast and show success\n        removeToast(loadingId);\n        addToast({\n          type: 'success',\n          title: typeof options.success === 'function' ? options.success(data) : options.success,\n          duration: 4000,\n        });\n\n        return data;\n      } catch (error) {\n        // Remove loading toast and show error\n        removeToast(loadingId);\n        addToast({\n          type: 'error',\n          title: typeof options.error === 'function' ? options.error(error) : options.error,\n          duration: 6000,\n        });\n\n        throw error;\n      }\n    },\n    [addToast, removeToast]\n  );\n\n  return (\n    <ToastContext.Provider\n      value={{ toasts, addToast, removeToast, updateToast, promise: promiseToast }}\n    >\n      {children}\n      <ToastContainer />\n    </ToastContext.Provider>\n  );\n}\n\nexport function useToast() {\n  const context = useContext(ToastContext);\n  if (context === undefined) {\n    throw new Error('useToast must be used within a ToastProvider');\n  }\n  return context;\n}\n\nfunction ToastContainer() {\n  const { toasts, removeToast } = useToast();\n\n  return (\n    <div className=\"fixed right-4 bottom-4 z-50 flex max-w-sm flex-col gap-2\">\n      <AnimatePresence>\n        {toasts.map((toast) => (\n          <ToastItem key={toast.id} toast={toast} onRemove={removeToast} />\n        ))}\n      </AnimatePresence>\n    </div>\n  );\n}\n\nfunction ToastItem({ toast, onRemove }: { toast: Toast; onRemove: (id: string) => void }) {\n  const getToastStyles = () => {\n    switch (toast.type) {\n      case 'success':\n        return 'bg-green-50 border-green-200 text-green-800 dark:bg-green-900 dark:border-green-700 dark:text-green-100';\n      case 'error':\n        return 'bg-red-50 border-red-200 text-red-800 dark:bg-red-900 dark:border-red-700 dark:text-red-100';\n      case 'warning':\n        return 'bg-yellow-50 border-yellow-200 text-yellow-800 dark:bg-yellow-900 dark:border-yellow-700 dark:text-yellow-100';\n      case 'info':\n        return 'bg-blue-50 border-blue-200 text-blue-800 dark:bg-blue-900 dark:border-blue-700 dark:text-blue-100';\n      case 'loading':\n        return 'bg-gray-50 border-gray-200 text-gray-800 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100';\n      default:\n        return 'bg-card border-border text-foreground';\n    }\n  };\n\n  const getIcon = () => {\n    switch (toast.type) {\n      case 'success':\n        return <CheckCircle className=\"h-5 w-5\" />;\n      case 'error':\n        return <XCircle className=\"h-5 w-5\" />;\n      case 'warning':\n        return <AlertTriangle className=\"h-5 w-5\" />;\n      case 'info':\n        return <Info className=\"h-5 w-5\" />;\n      case 'loading':\n        return <Loader2 className=\"h-5 w-5 animate-spin\" />;\n    }\n  };\n\n  return (\n    <motion.div\n      initial={{ opacity: 0, y: 50, scale: 0.3 }}\n      animate={{ opacity: 1, y: 0, scale: 1 }}\n      exit={{ opacity: 0, y: 20, scale: 0.5 }}\n      transition={{ duration: 0.2 }}\n      className={`relative flex items-start gap-3 rounded-lg border p-4 shadow-lg ${getToastStyles()}`}\n    >\n      <div className=\"flex-shrink-0\">{getIcon()}</div>\n\n      <div className=\"min-w-0 flex-1\">\n        <p className=\"text-sm font-medium\">{toast.title}</p>\n        {toast.description && <p className=\"mt-1 text-sm\">{toast.description}</p>}\n        {toast.action && (\n          <button\n            onClick={toast.action.onClick}\n            className=\"mt-2 text-sm font-medium underline hover:no-underline\"\n          >\n            {toast.action.label}\n          </button>\n        )}\n      </div>\n\n      {toast.dismissible !== false && (\n        <button\n          onClick={() => onRemove(toast.id)}\n          className=\"ml-4 inline-flex flex-shrink-0 text-sm transition-opacity hover:opacity-80\"\n          aria-label=\"Close notification\"\n        >\n          <X className=\"h-4 w-4\" />\n        </button>\n      )}\n    </motion.div>\n  );\n}\n\n// Convenience hooks for different toast types\nexport function useSuccessToast() {\n  const { addToast } = useToast();\n  return useCallback(\n    (title: string, description?: string) => {\n      addToast({ type: 'success', title, description });\n    },\n    [addToast]\n  );\n}\n\nexport function useErrorToast() {\n  const { addToast } = useToast();\n  return useCallback(\n    (title: string, description?: string, action?: Toast['action']) => {\n      addToast({ type: 'error', title, description, action, duration: 8000 });\n    },\n    [addToast]\n  );\n}\n\nexport function useWarningToast() {\n  const { addToast } = useToast();\n  return useCallback(\n    (title: string, description?: string) => {\n      addToast({ type: 'warning', title, description });\n    },\n    [addToast]\n  );\n}\n\nexport function useInfoToast() {\n  const { addToast } = useToast();\n  return useCallback(\n    (title: string, description?: string) => {\n      addToast({ type: 'info', title, description });\n    },\n    [addToast]\n  );\n}\n"
  },
  {
    "path": "src/constants/defaults.ts",
    "content": "import type {\n  ProfilePrefix,\n  ProfileData,\n  ProfileLinks,\n  SocialLinks,\n  SupportLinks,\n} from '@/types/profile';\n\nexport const DEFAULT_PREFIX: ProfilePrefix = {\n  title: \"Hi 👋, I'm\",\n  currentWork: \"🔭 I'm currently working on\",\n  currentLearn: \"🌱 I'm currently learning\",\n  collaborateOn: \"👯 I'm looking to collaborate on\",\n  helpWith: \"🤝 I'm looking for help with\",\n  ama: '💬 Ask me about',\n  contact: '📫 How to reach me',\n  resume: '📄 Know about my experiences',\n  funFact: '⚡ Fun fact',\n  portfolio: '👨‍💻 All of my projects are available at',\n  blog: '📝 I regularly write articles on',\n};\n\nexport const DEFAULT_DATA: ProfileData = {\n  title: '',\n  subtitle: '',\n  currentWork: '',\n  currentLearn: '',\n  collaborateOn: '',\n  helpWith: '',\n  ama: '',\n  contact: '',\n  funFact: '',\n  visitorsBadge: false,\n  badgeStyle: 'flat',\n  badgeColor: '0e75b6',\n  badgeLabel: 'Profile views',\n  githubProfileTrophy: false,\n  githubStats: false,\n  githubStatsOptions: {\n    theme: '',\n    titleColor: '',\n    textColor: '',\n    bgColor: '',\n    hideBorder: false,\n    cacheSeconds: null,\n    locale: 'en',\n  },\n  topLanguages: false,\n  topLanguagesOptions: {\n    theme: '',\n    titleColor: '',\n    textColor: '',\n    bgColor: '',\n    hideBorder: false,\n    cacheSeconds: null,\n    locale: 'en',\n  },\n  streakStats: false,\n  streakStatsOptions: {\n    theme: '',\n  },\n  devDynamicBlogs: false,\n  mediumDynamicBlogs: false,\n  rssDynamicBlogs: false,\n};\n\nexport const DEFAULT_LINK: ProfileLinks = {\n  currentWork: '',\n  collaborateOn: '',\n  helpWith: '',\n  portfolio: '',\n  blog: '',\n  resume: '',\n};\n\nexport const DEFAULT_SOCIAL: SocialLinks = {\n  github: '',\n  dev: '',\n  linkedin: '',\n  codepen: '',\n  stackoverflow: '',\n  kaggle: '',\n  codesandbox: '',\n  fb: '',\n  instagram: '',\n  twitter: '',\n  dribbble: '',\n  behance: '',\n  medium: '',\n  youtube: '',\n  codechef: '',\n  hackerrank: '',\n  codeforces: '',\n  leetcode: '',\n  topcoder: '',\n  hackerearth: '',\n  geeks_for_geeks: '',\n  discord: '',\n  rssurl: '',\n  twitterBadge: false,\n};\n\nexport const DEFAULT_SUPPORT: SupportLinks = {\n  buyMeACoffee: '',\n};\n"
  },
  {
    "path": "src/constants/skills.ts",
    "content": "import type { CategorizedSkills, SkillState } from '@/types/skills';\n\nexport const categorizedSkills: CategorizedSkills = {\n  language: {\n    title: 'Programming Languages',\n    skills: [\n      'c',\n      'cplusplus',\n      'csharp',\n      'go',\n      'java',\n      'javascript',\n      'typescript',\n      'php',\n      'perl',\n      'ruby',\n      'scala',\n      'python',\n      'swift',\n      'objectivec',\n      'clojure',\n      'rust',\n      'haskell',\n      'coffeescript',\n      'elixir',\n      'erlang',\n    ],\n  },\n\n  frontend_dev: {\n    title: 'Frontend Development',\n    skills: [\n      'vuejs',\n      'react',\n      'svelte',\n      'angularjs',\n      'angular',\n      'backbonejs',\n      'bootstrap',\n      'vuetify',\n      'css3',\n      'html5',\n      'pug',\n      'gulp',\n      'sass',\n      'redux',\n      'webpack',\n      'babel',\n      'tailwind',\n      'materialize',\n      'bulma',\n      'gtk',\n      'qt',\n      'ember',\n    ],\n  },\n\n  backend_dev: {\n    title: 'Backend Development',\n    skills: [\n      'nodejs',\n      'spring',\n      'express',\n      'graphql',\n      'kafka',\n      'solr',\n      'rabbitMQ',\n      'hadoop',\n      'nginx',\n      'openresty',\n      'nestjs',\n    ],\n  },\n\n  mobile_dev: {\n    title: 'Mobile App Development',\n    skills: [\n      'android',\n      'flutter',\n      'dart',\n      'kotlin',\n      'nativescript',\n      'xamarin',\n      'reactnative',\n      'ionic',\n      'apachecordova',\n    ],\n  },\n\n  ai: {\n    title: 'AI/ML',\n    skills: [\n      // Core ML Frameworks\n      'tensorflow',\n      'pytorch',\n      'keras',\n      'scikit_learn',\n      'opencv',\n      // Data Science\n      'pandas',\n      'numpy',\n      'matplotlib',\n      'seaborn',\n      'jupyter',\n      'anaconda',\n      // Modern AI Tools\n      'langchain',\n      'huggingface',\n      'ollama',\n      // ML Ops & Deployment\n      'mlflow',\n      'streamlit',\n      'fastapi',\n      'gradio',\n    ],\n  },\n\n  database: {\n    title: 'Database',\n    skills: [\n      'mongodb',\n      'mysql',\n      'postgresql',\n      'redis',\n      'oracle',\n      'cassandra',\n      'couchdb',\n      'hive',\n      'realm',\n      'mariadb',\n      'cockroachdb',\n      'elasticsearch',\n      'sqlite',\n      'mssql',\n    ],\n  },\n\n  data_visualization: {\n    title: 'Data Visualization',\n    skills: ['d3js', 'chartjs', 'canvasjs', 'kibana', 'grafana'],\n  },\n\n  devops: {\n    title: 'Devops',\n    skills: [\n      'aws',\n      'docker',\n      'jenkins',\n      'gcp',\n      'kubernetes',\n      'bash',\n      'azure',\n      'vagrant',\n      'circleci',\n      'travisci',\n    ],\n  },\n\n  baas: {\n    title: 'Backend as a Service(BaaS)',\n    skills: ['firebase', 'appwrite', 'amplify', 'heroku'],\n  },\n\n  framework: {\n    title: 'Framework',\n    skills: [\n      'django',\n      'dotnet',\n      'electron',\n      'symfony',\n      'laravel',\n      'codeigniter',\n      'rails',\n      'flask',\n      'quasar',\n    ],\n  },\n\n  testing: {\n    title: 'Testing',\n    skills: ['cypress', 'selenium', 'jest', 'mocha', 'puppeteer', 'karma', 'jasmine'],\n  },\n\n  software: {\n    title: 'Software',\n    skills: [\n      'illustrator',\n      'photoshop',\n      'xd',\n      'figma',\n      'blender',\n      'sketch',\n      'invision',\n      'framer',\n      'matlab',\n      'postman',\n    ],\n  },\n\n  static_site_generator: {\n    title: 'Static Site Generators',\n    skills: [\n      'gatsby',\n      'gridsome',\n      'hugo',\n      'jekyll',\n      'nextjs',\n      'nuxtjs',\n      '11ty',\n      'scully',\n      'sculpin',\n      'vuepress',\n      'hexo',\n      'middleman',\n    ],\n  },\n\n  game_engines: {\n    title: 'Game Engines',\n    skills: ['unity', 'unreal'],\n  },\n\n  automation: {\n    title: 'Automation',\n    skills: ['zapier', 'ifttt'],\n  },\n\n  other: {\n    title: 'Other',\n    skills: ['linux', 'git', 'arduino'],\n  },\n};\n\n// Get all skills as a flat array\nconst skillsArray = Object.keys(categorizedSkills).map((key) => categorizedSkills[key].skills);\nexport const skills = skillsArray.flat().sort();\n\n// Initialize skill state\nexport const initialSkillState: SkillState = {};\nskills.forEach((skill) => {\n  initialSkillState[skill] = false;\n});\n\n// Export categories\nexport const categories = Object.keys(categorizedSkills);\n"
  },
  {
    "path": "src/hooks/use-consent.ts",
    "content": "'use client';\n\nimport { useState, useEffect } from 'react';\n\nexport type ConsentStatus = 'pending' | 'accepted' | 'rejected';\n\ninterface ConsentState {\n  status: ConsentStatus;\n  showBanner: boolean;\n  acceptConsent: () => void;\n  rejectConsent: () => void;\n  resetConsent: () => void;\n}\n\n/**\n * Hook for managing GDPR cookie consent\n */\nexport function useConsent(): ConsentState {\n  const [status, setStatus] = useState<ConsentStatus>('pending');\n  const [showBanner, setShowBanner] = useState(false);\n\n  // Load consent status from localStorage on mount\n  useEffect(() => {\n    if (typeof window === 'undefined') return;\n\n    try {\n      const savedConsent = localStorage.getItem('analytics-consent');\n      const consentTimestamp = localStorage.getItem('analytics-consent-timestamp');\n\n      if (savedConsent && consentTimestamp) {\n        // Check if consent is still valid (30 days)\n        const consentDate = new Date(consentTimestamp);\n        const thirtyDaysAgo = new Date();\n        thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);\n\n        if (consentDate > thirtyDaysAgo) {\n          setStatus(savedConsent as ConsentStatus);\n          setShowBanner(false);\n        } else {\n          // Consent expired, show banner again\n          setStatus('pending');\n          setShowBanner(true);\n        }\n      } else {\n        // No consent found, show banner\n        setStatus('pending');\n        setShowBanner(true);\n      }\n    } catch (error) {\n      console.warn('Failed to load consent status:', error);\n      setStatus('pending');\n      setShowBanner(true);\n    }\n  }, []);\n\n  const acceptConsent = () => {\n    try {\n      localStorage.setItem('analytics-consent', 'accepted');\n      localStorage.setItem('analytics-consent-timestamp', new Date().toISOString());\n      setStatus('accepted');\n      setShowBanner(false);\n\n      // Reload page to initialize analytics\n      if (typeof window !== 'undefined') {\n        window.location.reload();\n      }\n    } catch (error) {\n      console.warn('Failed to save consent:', error);\n    }\n  };\n\n  const rejectConsent = () => {\n    try {\n      localStorage.setItem('analytics-consent', 'rejected');\n      localStorage.setItem('analytics-consent-timestamp', new Date().toISOString());\n      setStatus('rejected');\n      setShowBanner(false);\n    } catch (error) {\n      console.warn('Failed to save consent rejection:', error);\n    }\n  };\n\n  const resetConsent = () => {\n    try {\n      localStorage.removeItem('analytics-consent');\n      localStorage.removeItem('analytics-consent-timestamp');\n      setStatus('pending');\n      setShowBanner(true);\n    } catch (error) {\n      console.warn('Failed to reset consent:', error);\n    }\n  };\n\n  return {\n    status,\n    showBanner,\n    acceptConsent,\n    rejectConsent,\n    resetConsent,\n  };\n}\n"
  },
  {
    "path": "src/hooks/use-local-storage.ts",
    "content": "'use client';\n\nimport { useState, useEffect, useCallback } from 'react';\n\nexport function useLocalStorage<T>(key: string, initialValue: T) {\n  // State to store our value\n  const [storedValue, setStoredValue] = useState<T>(initialValue);\n  const [isLoaded, setIsLoaded] = useState(false);\n\n  // Load initial value from localStorage\n  useEffect(() => {\n    try {\n      const item = window.localStorage.getItem(key);\n      if (item) {\n        setStoredValue(JSON.parse(item));\n      }\n    } catch (error) {\n      console.error(`Error loading ${key} from localStorage:`, error);\n    } finally {\n      setIsLoaded(true);\n    }\n  }, [key]);\n\n  // Return a wrapped version of useState's setter function that persists the new value to localStorage\n  const setValue = useCallback(\n    (value: T | ((val: T) => T)) => {\n      try {\n        // Allow value to be a function so we have same API as useState\n        const valueToStore = value instanceof Function ? value(storedValue) : value;\n        setStoredValue(valueToStore);\n        window.localStorage.setItem(key, JSON.stringify(valueToStore));\n      } catch (error) {\n        console.error(`Error saving ${key} to localStorage:`, error);\n      }\n    },\n    [key, storedValue]\n  );\n\n  const clearValue = useCallback(() => {\n    try {\n      window.localStorage.removeItem(key);\n      setStoredValue(initialValue);\n    } catch (error) {\n      console.error(`Error clearing ${key} from localStorage:`, error);\n    }\n  }, [key, initialValue]);\n\n  return [storedValue, setValue, clearValue, isLoaded] as const;\n}\n"
  },
  {
    "path": "src/hooks/use-theme.ts",
    "content": "'use client';\n\nimport { useEffect } from 'react';\nimport { useThemeStore } from '@/lib/store';\nimport type { ThemeMode } from '@/types/theme';\n\nexport function useTheme() {\n  const { mode, resolvedTheme, setMode, setResolvedTheme } = useThemeStore();\n\n  useEffect(() => {\n    const root = document.documentElement;\n    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n\n    const updateTheme = () => {\n      const isDark = mode === 'dark' || (mode === 'system' && mediaQuery.matches);\n      const newTheme = isDark ? 'dark' : 'light';\n\n      // Only update if theme actually changed\n      if (resolvedTheme !== newTheme) {\n        setResolvedTheme(newTheme);\n\n        // Temporarily disable transitions for instant theme switch\n        root.classList.add('theme-switching');\n\n        // Use requestAnimationFrame for smoother transitions\n        requestAnimationFrame(() => {\n          // Remove both classes first to avoid conflicts\n          root.classList.remove('dark', 'light');\n\n          // Add the new theme class\n          root.classList.add(newTheme);\n\n          // Re-enable transitions after a short delay (matching CSS transition duration)\n          setTimeout(() => {\n            root.classList.remove('theme-switching');\n          }, 25); // Half of 100ms for optimal timing\n        });\n      }\n    };\n\n    updateTheme();\n\n    const listener = () => {\n      if (mode === 'system') {\n        updateTheme();\n      }\n    };\n\n    mediaQuery.addEventListener('change', listener);\n    return () => mediaQuery.removeEventListener('change', listener);\n  }, [mode, resolvedTheme, setResolvedTheme]);\n\n  const setTheme = (newMode: ThemeMode) => {\n    setMode(newMode);\n  };\n\n  return {\n    theme: mode,\n    resolvedTheme,\n    setTheme,\n  };\n}\n"
  },
  {
    "path": "src/lib/analytics.ts",
    "content": "'use client';\n\n// Analytics utility for GA4 custom event tracking\n// Only tracks events if user has given consent\n\ndeclare global {\n  interface Window {\n    gtag?: (...args: unknown[]) => void;\n  }\n}\n\n/**\n * Check if analytics consent has been given\n */\nexport function hasAnalyticsConsent(): boolean {\n  if (typeof window === 'undefined') return false;\n\n  try {\n    const consent = localStorage.getItem('analytics-consent');\n    return consent === 'accepted';\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Send custom event to GA4 if consent is given\n */\nfunction trackEvent(eventName: string, parameters?: Record<string, unknown>) {\n  // Only track if consent is given and gtag is available\n  if (!hasAnalyticsConsent() || typeof window === 'undefined' || !window.gtag) {\n    return;\n  }\n\n  try {\n    window.gtag('event', eventName, {\n      // Add default parameters\n      timestamp: new Date().toISOString(),\n      page_location: window.location.href,\n      page_title: document.title,\n      // Add custom parameters\n      ...parameters,\n    });\n  } catch (error) {\n    console.warn('Analytics tracking failed:', error);\n  }\n}\n\n/**\n * Track GitHub auto-fill usage\n */\nexport function trackGitHubAutofill(username?: string) {\n  trackEvent('github_autofill_used', {\n    event_category: 'engagement',\n    event_label: 'github_integration',\n    has_username: !!username,\n    // Don't track actual username for privacy\n  });\n}\n\n/**\n * Track README generation completion\n */\nexport function trackReadmeGenerated(data?: {\n  hasSkills?: boolean;\n  hasSocial?: boolean;\n  hasLinks?: boolean;\n  stepCount?: number;\n}) {\n  trackEvent('readme_generated', {\n    event_category: 'conversion',\n    event_label: 'readme_completion',\n    value: 1, // Conversion value\n    has_skills: data?.hasSkills || false,\n    has_social: data?.hasSocial || false,\n    has_links: data?.hasLinks || false,\n    step_count: data?.stepCount || 0,\n  });\n}\n\n/**\n * Track file export/download actions\n */\nexport function trackFileExported(action: 'copy' | 'download' | 'json_export', format?: string) {\n  trackEvent('file_exported', {\n    event_category: 'engagement',\n    event_label: 'file_export',\n    export_action: action,\n    file_format: format || 'markdown',\n    value: action === 'download' ? 2 : 1, // Downloads are more valuable\n  });\n}\n\n/**\n * Initialize analytics with consent\n */\nexport function initializeAnalytics() {\n  if (!hasAnalyticsConsent()) {\n    return;\n  }\n\n  // Configure GA4 for privacy\n  if (typeof window !== 'undefined' && window.gtag) {\n    window.gtag('config', process.env.NEXT_PUBLIC_GA_ID || '', {\n      // Privacy-friendly configuration\n      anonymize_ip: true,\n      allow_google_signals: false,\n      allow_ad_personalization_signals: false,\n      // Custom configuration\n      page_title: document.title,\n      page_location: window.location.href,\n    });\n  }\n}\n\n/**\n * Disable analytics tracking (for opt-out)\n */\nexport function disableAnalytics() {\n  if (typeof window !== 'undefined') {\n    // Set GA4 opt-out flag\n    const gaId = process.env.NEXT_PUBLIC_GA_ID;\n    if (gaId) {\n      (window as unknown as Record<string, boolean>)[`ga-disable-${gaId}`] = true;\n    }\n\n    // Remove consent\n    try {\n      localStorage.removeItem('analytics-consent');\n    } catch {\n      // Ignore localStorage errors\n    }\n  }\n}\n"
  },
  {
    "path": "src/lib/asset-path.ts",
    "content": "/**\n * Get the correct asset path with basePath for GitHub Pages\n * Uses NEXT_PUBLIC_BASE_PATH environment variable if set\n */\n\nexport function getAssetPath(path: string): string {\n  // Ensure path starts with /\n  const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n\n  // Use NEXT_PUBLIC_BASE_PATH if set, otherwise detect based on build\n  const basePath = process.env.NEXT_PUBLIC_BASE_PATH || '';\n\n  return `${basePath}${normalizedPath}`;\n}\n"
  },
  {
    "path": "src/lib/github-api.ts",
    "content": "interface GitHubUser {\n  login: string;\n  name: string | null;\n  bio: string | null;\n  location: string | null;\n  blog: string | null;\n  twitter_username: string | null;\n  public_repos: number;\n  followers: number;\n  following: number;\n  company: string | null;\n  email: string | null;\n}\n\ninterface GitHubRepo {\n  name: string;\n  language: string | null;\n  stargazers_count: number;\n  description: string | null;\n}\n\nexport interface GitHubUserData {\n  username: string;\n  name: string;\n  bio: string;\n  location: string;\n  blog: string;\n  twitter: string;\n  email: string;\n  topLanguages: string[];\n  totalRepos: number;\n  totalStars: number;\n}\n\nexport interface GitHubApiError {\n  message: string;\n  type: 'rate_limit' | 'not_found' | 'network' | 'unknown';\n  retryAfter?: number;\n}\n\nexport async function fetchGitHubUser(username: string): Promise<GitHubUserData | null> {\n  try {\n    // Fetch user data\n    const userResponse = await fetch(`https://api.github.com/users/${username}`);\n\n    if (!userResponse.ok) {\n      // Handle specific error cases\n      if (userResponse.status === 403) {\n        const rateLimitRemaining = userResponse.headers.get('X-RateLimit-Remaining');\n        const rateLimitReset = userResponse.headers.get('X-RateLimit-Reset');\n\n        if (rateLimitRemaining === '0') {\n          const resetTime = rateLimitReset ? new Date(parseInt(rateLimitReset) * 1000) : null;\n          const retryAfter = resetTime\n            ? Math.ceil((resetTime.getTime() - Date.now()) / 1000 / 60)\n            : null;\n\n          const error: GitHubApiError = {\n            message: `GitHub API rate limit exceeded. ${retryAfter ? `Try again in ${retryAfter} minutes.` : 'Please try again later.'}`,\n            type: 'rate_limit',\n            retryAfter: retryAfter || undefined,\n          };\n          throw error;\n        }\n      }\n\n      if (userResponse.status === 404) {\n        const error: GitHubApiError = {\n          message: `GitHub user \"${username}\" not found. Please check the username.`,\n          type: 'not_found',\n        };\n        throw error;\n      }\n\n      // Generic error for other status codes\n      const error: GitHubApiError = {\n        message: `Failed to fetch GitHub user data (${userResponse.status}). Please try again.`,\n        type: 'unknown',\n      };\n      throw error;\n    }\n\n    const user: GitHubUser = await userResponse.json();\n\n    // Fetch user repos to analyze languages\n    const reposResponse = await fetch(\n      `https://api.github.com/users/${username}/repos?sort=updated&per_page=100`\n    );\n\n    let repos: GitHubRepo[] = [];\n    if (reposResponse.ok) {\n      repos = await reposResponse.json();\n    } else if (reposResponse.status === 403) {\n      // Rate limit hit on repos endpoint, continue with user data only\n      console.warn('GitHub API rate limit hit for repos endpoint, continuing with basic user data');\n    }\n\n    // Analyze top languages\n    const languageCounts: Record<string, number> = {};\n    let totalStars = 0;\n\n    repos.forEach((repo) => {\n      if (repo.language) {\n        languageCounts[repo.language] = (languageCounts[repo.language] || 0) + 1;\n      }\n      totalStars += repo.stargazers_count;\n    });\n\n    // Sort languages by frequency\n    const topLanguages = Object.entries(languageCounts)\n      .sort((a, b) => b[1] - a[1])\n      .slice(0, 5)\n      .map(([lang]) => lang.toLowerCase());\n\n    return {\n      username: user.login,\n      name: user.name || user.login,\n      bio: user.bio || '',\n      location: user.location || '',\n      blog: user.blog || '',\n      twitter: user.twitter_username || '',\n      email: user.email || '',\n      topLanguages,\n      totalRepos: user.public_repos,\n      totalStars,\n    };\n  } catch (error) {\n    console.error('Error fetching GitHub user:', error);\n\n    // Re-throw GitHubApiError for proper handling\n    if (error && typeof error === 'object' && 'type' in error) {\n      throw error as GitHubApiError;\n    }\n\n    // Network or other errors\n    const networkError: GitHubApiError = {\n      message: 'Network error occurred. Please check your connection and try again.',\n      type: 'network',\n    };\n    throw networkError;\n  }\n}\n\n// Map GitHub languages to skill IDs in our system\nexport function mapLanguageToSkills(language: string): string[] {\n  const languageMap: Record<string, string[]> = {\n    javascript: ['javascript', 'nodejs', 'react', 'express'],\n    typescript: ['typescript', 'nodejs', 'react'],\n    python: ['python', 'django', 'flask'],\n    java: ['java', 'spring'],\n    go: ['go'],\n    rust: ['rust'],\n    ruby: ['ruby', 'rails'],\n    php: ['php', 'laravel'],\n    swift: ['swift'],\n    kotlin: ['kotlin', 'android'],\n    csharp: ['csharp', 'dotnet'],\n    cpp: ['cplusplus'],\n    c: ['c'],\n    scala: ['scala'],\n    html: ['html5', 'css3'],\n    css: ['css3', 'sass'],\n  };\n\n  return languageMap[language] || [language];\n}\n\n// Generate smart subtitle based on user data\nexport function generateSmartSubtitle(userData: GitHubUserData): string {\n  const { topLanguages, totalRepos } = userData;\n\n  if (topLanguages.length === 0) {\n    return 'A passionate developer from around the world';\n  }\n\n  const primaryLang = topLanguages[0];\n  const langDisplay = primaryLang.charAt(0).toUpperCase() + primaryLang.slice(1);\n\n  if (totalRepos < 5) {\n    return `A budding ${langDisplay} developer`;\n  } else if (totalRepos < 20) {\n    return `A passionate ${langDisplay} developer`;\n  } else if (totalRepos < 50) {\n    return `An experienced ${langDisplay} developer`;\n  } else {\n    return `A seasoned ${langDisplay} developer`;\n  }\n}\n"
  },
  {
    "path": "src/lib/markdown-generator.ts",
    "content": "import type {\n  ProfileFormData,\n  LinksFormData,\n  SocialFormData,\n  SupportFormData,\n} from './validations';\nimport { DEFAULT_PREFIX } from '@/constants/defaults';\n\ninterface GenerateMarkdownOptions {\n  profile: Partial<ProfileFormData>;\n  links: Partial<LinksFormData>;\n  social: Partial<SocialFormData>;\n  support: Partial<SupportFormData>;\n  skills: Record<string, boolean>;\n}\n\nconst socialPlatformUrls: Record<string, (username: string) => string> = {\n  github: (u) => `https://github.com/${u}`,\n  linkedin: (u) => `https://linkedin.com/in/${u}`,\n  twitter: (u) => `https://twitter.com/${u}`,\n  dev: (u) => `https://dev.to/${u}`,\n  stackoverflow: (u) => `https://stackoverflow.com/users/${u}`,\n  kaggle: (u) => `https://kaggle.com/${u}`,\n  fb: (u) => `https://fb.com/${u}`,\n  instagram: (u) => `https://instagram.com/${u}`,\n  dribbble: (u) => `https://dribbble.com/${u}`,\n  behance: (u) => `https://behance.net/${u}`,\n  medium: (u) => `https://medium.com/${u}`,\n  youtube: (u) => `https://youtube.com/${u}`,\n  codepen: (u) => `https://codepen.io/${u}`,\n  codesandbox: (u) => `https://codesandbox.io/${u}`,\n  leetcode: (u) => `https://leetcode.com/${u}`,\n  hackerrank: (u) => `https://hackerrank.com/${u}`,\n  codeforces: (u) => `https://codeforces.com/profile/${u}`,\n  codechef: (u) => `https://codechef.com/users/${u}`,\n  topcoder: (u) => `https://topcoder.com/members/${u}`,\n  hackerearth: (u) => `https://hackerearth.com/${u}`,\n  geeks_for_geeks: (u) => `https://auth.geeksforgeeks.org/user/${u}`,\n  discord: (u) => `https://discord.gg/${u}`,\n};\n\nconst socialIcons: Record<string, string> = {\n  github: 'github.svg',\n  linkedin: 'linked-in-alt.svg',\n  twitter: 'twitter.svg',\n  dev: 'devto.svg',\n  stackoverflow: 'stack-overflow.svg',\n  kaggle: 'kaggle.svg',\n  fb: 'facebook.svg',\n  instagram: 'instagram.svg',\n  dribbble: 'dribbble.svg',\n  behance: 'behance.svg',\n  medium: 'medium.svg',\n  youtube: 'youtube.svg',\n  codepen: 'codepen.svg',\n  codesandbox: 'codesandbox.svg',\n  leetcode: 'leet-code.svg',\n  hackerrank: 'hackerrank.svg',\n  codeforces: 'codeforces.svg',\n  codechef: 'codechef.svg',\n  topcoder: 'topcoder.svg',\n  hackerearth: 'hackerearth.svg',\n  geeks_for_geeks: 'geeks-for-geeks.svg',\n  discord: 'discord.svg',\n};\n\n// Generate skill icon URL - uses skillicons.dev for consistent dark mode support\nexport function getSkillIconUrl(skill: string): string {\n  // Skills that use simple-icons for better brand colors and dark mode support\n  // Using colors that work in both light and dark modes\n  const simpleIconsFallback: Record<string, string> = {\n    // DevOps\n    circleci: 'circleci/555', // CircleCI in medium gray (visible in both modes)\n    travisci: 'travisci', // Travis CI uses teal brand color (works in both modes)\n    // Modern AI/ML Tools\n    langchain: 'langchain/1C3C3C', // LangChain dark color\n    huggingface: 'huggingface', // HuggingFace brand color\n    ollama: 'ollama', // Ollama brand color\n    mlflow: 'mlflow/0194E2', // MLflow blue\n    streamlit: 'streamlit/FF4B4B', // Streamlit red\n    gradio: 'gradio/FF7C00', // Gradio orange\n    // Frontend\n    backbonejs: 'backbonedotjs/0071B5', // Backbone.js blue\n    // Mobile\n    nativescript: 'nativescript/3655FF', // NativeScript blue\n    apachecordova: 'apachecordova/E8E8E8', // Apache Cordova gray\n    // Backend\n    solr: 'apachesolr/D9411E', // Apache Solr red\n    // Database\n    cockroachdb: 'cockroachlabs', // CockroachDB official\n    hive: 'apachehive/FDEE21', // Apache Hive yellow\n    // Data Visualization\n    chartjs: 'chartdotjs/FF6384', // Chart.js pink\n    // Testing\n    puppeteer: 'puppeteer/40B5A4', // Puppeteer teal\n    // Software/Design\n    framer: 'framer', // Framer brand color\n    invision: 'invision/FF3366', // InVision pink\n    // Static Site Generators\n    '11ty': 'eleventy', // Eleventy brand color\n    hexo: 'hexo/0E83CD', // Hexo blue\n    gridsome: 'gridsome', // Gridsome brand color\n    // Automation\n    zapier: 'zapier/FF4A00', // Zapier orange\n    ifttt: 'ifttt', // IFTTT brand color\n  };\n\n  // Check if skill needs simple-icons fallback\n  if (simpleIconsFallback[skill]) {\n    const parts = simpleIconsFallback[skill].split('/');\n    const iconName = parts[0];\n    const color = parts[1] || ''; // Use brand color if specified\n    return `https://cdn.simpleicons.org/${iconName}${color ? `/${color}` : ''}`;\n  }\n\n  // Skills that need devicon fallback (not available on skillicons.dev)\n  const deviconFallback: Record<string, string> = {\n    // Database\n    oracle: 'oracle/oracle-original',\n    realm: 'realm/realm-original',\n    couchdb: 'couchdb/couchdb-original',\n    mssql: 'microsoftsqlserver/microsoftsqlserver-plain',\n    mariadb: 'mysql/mysql-original-wordmark',\n    // Mobile\n    xamarin: 'dot-net/dot-net-plain',\n    ionic: 'ionic/ionic-original',\n    // Programming Languages\n    erlang: 'erlang/erlang-original',\n    // Frontend\n    bulma: 'bulma/bulma-plain',\n    materialize: 'materialui/materialui-original',\n    // Backend\n    openresty: 'nginx/nginx-original',\n    hadoop: 'hadoop/hadoop-original',\n    // AI/ML - Core Data Science\n    keras: 'keras/keras-original',\n    numpy: 'numpy/numpy-original',\n    matplotlib: 'matplotlib/matplotlib-original',\n    jupyter: 'jupyter/jupyter-original-wordmark',\n    pandas: 'pandas/pandas-original',\n    seaborn: 'python/python-original',\n    // Data Visualization\n    canvasjs: 'javascript/javascript-original', // No official icon available\n    kibana: 'kibana/kibana-original',\n    // DevOps\n    vagrant: 'vagrant/vagrant-original',\n    // BaaS\n    amplify: 'amazonwebservices/amazonwebservices-plain-wordmark',\n    // Framework\n    codeigniter: 'codeigniter/codeigniter-plain',\n    quasar: 'quasar/quasar-plain',\n    // Testing\n    mocha: 'mocha/mocha-plain',\n    karma: 'karma/karma-original',\n    jasmine: 'jasmine/jasmine-original',\n    // Software\n    sketch: 'sketch/sketch-original',\n    // Static Site Generators\n    hugo: 'hugo/hugo-original',\n    sculpin: 'php/php-original',\n    vuepress: 'vuejs/vuejs-original', // VuePress doesn't have official icon, using Vue\n    jekyll: 'jekyll/jekyll-original',\n    middleman: 'ruby/ruby-original',\n    // Angular variant\n    scully: 'angularjs/angularjs-original',\n  };\n\n  // Check if skill needs devicon fallback\n  if (deviconFallback[skill]) {\n    return `https://cdn.jsdelivr.net/gh/devicons/devicon/icons/${deviconFallback[skill]}.svg`;\n  }\n\n  // Map skill names to skillicons identifiers\n  const skillIconsMap: Record<string, string> = {\n    // Programming Languages\n    c: 'c',\n    cplusplus: 'cpp',\n    csharp: 'cs',\n    go: 'go',\n    java: 'java',\n    javascript: 'js',\n    typescript: 'ts',\n    php: 'php',\n    perl: 'perl',\n    ruby: 'ruby',\n    scala: 'scala',\n    python: 'py',\n    swift: 'swift',\n    objectivec: 'apple',\n    clojure: 'clojure',\n    rust: 'rust',\n    haskell: 'haskell',\n    coffeescript: 'coffeescript',\n    elixir: 'elixir',\n    erlang: 'erlang',\n    // Frontend\n    vuejs: 'vue',\n    react: 'react',\n    svelte: 'svelte',\n    angularjs: 'angular',\n    angular: 'angular',\n    backbonejs: 'backbone',\n    bootstrap: 'bootstrap',\n    vuetify: 'vuetify',\n    css3: 'css',\n    html5: 'html',\n    pug: 'pug',\n    gulp: 'gulp',\n    sass: 'sass',\n    redux: 'redux',\n    webpack: 'webpack',\n    babel: 'babel',\n    tailwind: 'tailwind',\n    bulma: 'bulma',\n    gtk: 'gtk',\n    qt: 'qt',\n    ember: 'ember',\n    // Backend\n    nodejs: 'nodejs',\n    spring: 'spring',\n    express: 'express',\n    graphql: 'graphql',\n    kafka: 'kafka',\n    rabbitmq: 'rabbitmq',\n    rabbitMQ: 'rabbitmq', // Handle capital MQ variant\n    hadoop: 'hadoop',\n    nginx: 'nginx',\n    nestjs: 'nestjs',\n    // Mobile\n    android: 'androidstudio',\n    flutter: 'flutter',\n    dart: 'dart',\n    kotlin: 'kotlin',\n    reactnative: 'react',\n    ionic: 'ionic',\n    // AI/ML\n    tensorflow: 'tensorflow',\n    pytorch: 'pytorch',\n    opencv: 'opencv',\n    scikit_learn: 'scikitlearn',\n    anaconda: 'anaconda',\n    fastapi: 'fastapi',\n    // Database\n    mongodb: 'mongodb',\n    mysql: 'mysql',\n    postgresql: 'postgres',\n    redis: 'redis',\n    cassandra: 'cassandra',\n    elasticsearch: 'elasticsearch',\n    sqlite: 'sqlite',\n    // Data Visualization\n    d3js: 'd3',\n    grafana: 'grafana',\n    // DevOps\n    aws: 'aws',\n    docker: 'docker',\n    jenkins: 'jenkins',\n    gcp: 'gcp',\n    kubernetes: 'kubernetes',\n    bash: 'bash',\n    azure: 'azure',\n    vagrant: 'vagrant',\n    circleci: 'circleci',\n    travisci: 'travis',\n    // BaaS\n    firebase: 'firebase',\n    appwrite: 'appwrite',\n    heroku: 'heroku',\n    // Framework\n    django: 'django',\n    dotnet: 'dotnet',\n    electron: 'electron',\n    symfony: 'symfony',\n    laravel: 'laravel',\n    codeigniter: 'codeigniter',\n    rails: 'rails',\n    flask: 'flask',\n    quasar: 'quasar',\n    // Testing\n    cypress: 'cypress',\n    selenium: 'selenium',\n    jest: 'jest',\n    mocha: 'mocha',\n    puppeteer: 'puppeteer',\n    karma: 'karma',\n    jasmine: 'jasmine',\n    // Software\n    illustrator: 'illustrator',\n    photoshop: 'photoshop',\n    xd: 'xd',\n    figma: 'figma',\n    blender: 'blender',\n    sketch: 'sketch',\n    invision: 'invision',\n    framer: 'framer',\n    matlab: 'matlab',\n    postman: 'postman',\n    // Static Site Generators\n    gatsby: 'gatsby',\n    hugo: 'hugo',\n    jekyll: 'jekyll',\n    nextjs: 'nextjs',\n    nuxtjs: 'nuxtjs',\n    '11ty': 'eleventy',\n    hexo: 'hexo',\n    // Game Engines\n    unity: 'unity',\n    unreal: 'unreal',\n    // Automation\n    zapier: 'zapier',\n    ifttt: 'ifttt',\n    // Other\n    linux: 'linux',\n    git: 'git',\n    arduino: 'arduino',\n  };\n\n  const iconName = skillIconsMap[skill] || skill;\n\n  // Use skillicons.dev which provides dark-mode compatible icons\n  // This service automatically handles dark mode and provides consistent styling\n  return `https://skillicons.dev/icons?i=${iconName}`;\n}\n\nexport function generateMarkdown(options: GenerateMarkdownOptions): string {\n  const { profile, links, social, support, skills } = options;\n  let markdown = '';\n\n  // Title and Subtitle\n  if (profile.title) {\n    markdown += `# ${DEFAULT_PREFIX.title} ${profile.title}\\n\\n`;\n  }\n\n  if (profile.subtitle) {\n    markdown += `### ${profile.subtitle}\\n\\n`;\n  }\n\n  // Visitor Badge\n  if (profile.visitorsBadge && social.github) {\n    markdown += `<p align=\"left\"> <img src=\"https://komarev.com/ghpvc/?username=${social.github}&label=${profile.badgeLabel || 'Profile views'}&color=${profile.badgeColor || '0e75b6'}&style=${profile.badgeStyle || 'flat'}\" alt=\"${social.github}\" /> </p>\\n\\n`;\n  }\n\n  // GitHub Trophy\n  if (profile.githubProfileTrophy && social.github) {\n    markdown += `<p align=\"left\"> <a href=\"https://github.com/ryo-ma/github-profile-trophy\"><img src=\"https://github-profile-trophy.vercel.app/?username=${social.github}\" alt=\"${social.github}\" /></a> </p>\\n\\n`;\n  }\n\n  // Twitter Badge\n  if (social.twitterBadge && social.twitter) {\n    markdown += `<p align=\"left\"> <a href=\"https://twitter.com/${social.twitter}\" target=\"blank\"><img src=\"https://img.shields.io/twitter/follow/${social.twitter}?logo=twitter&style=for-the-badge\" alt=\"${social.twitter}\" /></a> </p>\\n\\n`;\n  }\n\n  // About sections\n  const aboutSections = [\n    {\n      key: 'currentWork',\n      value: profile.currentWork,\n      prefix: DEFAULT_PREFIX.currentWork,\n      link: links.currentWork,\n    },\n    { key: 'currentLearn', value: profile.currentLearn, prefix: DEFAULT_PREFIX.currentLearn },\n    {\n      key: 'collaborateOn',\n      value: profile.collaborateOn,\n      prefix: DEFAULT_PREFIX.collaborateOn,\n      link: links.collaborateOn,\n    },\n    {\n      key: 'helpWith',\n      value: profile.helpWith,\n      prefix: DEFAULT_PREFIX.helpWith,\n      link: links.helpWith,\n    },\n    { key: 'ama', value: profile.ama, prefix: DEFAULT_PREFIX.ama },\n    { key: 'contact', value: profile.contact, prefix: DEFAULT_PREFIX.contact },\n    { key: 'funFact', value: profile.funFact, prefix: DEFAULT_PREFIX.funFact },\n  ];\n\n  aboutSections.forEach(({ value, prefix, link }) => {\n    if (value) {\n      if (link) {\n        markdown += `- ${prefix} **[${value}](${link})**\\n\\n`;\n      } else {\n        markdown += `- ${prefix} **${value}**\\n\\n`;\n      }\n    }\n  });\n\n  // Portfolio\n  if (links.portfolio) {\n    markdown += `- ${DEFAULT_PREFIX.portfolio} **[${links.portfolio}](${links.portfolio})**\\n\\n`;\n  }\n\n  // Blog\n  if (links.blog) {\n    markdown += `- ${DEFAULT_PREFIX.blog} **[${links.blog}](${links.blog})**\\n\\n`;\n  }\n\n  // Resume\n  if (links.resume) {\n    markdown += `- ${DEFAULT_PREFIX.resume} **[${links.resume}](${links.resume})**\\n\\n`;\n  }\n\n  // Social Connect\n  const socialLinks = Object.entries(social).filter(\n    ([key, value]) =>\n      key !== 'twitterBadge' && value && typeof value === 'string' && value.trim() !== ''\n  );\n  if (socialLinks.length > 0) {\n    markdown += `<h3 align=\"left\">Connect with me:</h3>\\n`;\n    markdown += `<p align=\"left\">\\n`;\n\n    socialLinks.forEach(([platform, username]) => {\n      const icon = socialIcons[platform];\n      const url = socialPlatformUrls[platform];\n      if (icon && url && username) {\n        markdown += `<a href=\"${url(username as string)}\" target=\"blank\"><img align=\"center\" src=\"https://raw.githubusercontent.com/rahuldkjain/github-profile-readme-generator/master/src/images/icons/Social/${icon}\" alt=\"${username as string}\" height=\"30\" width=\"40\" /></a>\\n`;\n      }\n    });\n\n    markdown += `</p>\\n\\n`;\n  }\n\n  // Skills\n  const selectedSkills = Object.entries(skills).filter(([_, selected]) => selected);\n  if (selectedSkills.length > 0) {\n    markdown += `<h3 align=\"left\">Languages and Tools:</h3>\\n`;\n    markdown += `<p align=\"left\">`;\n\n    selectedSkills.forEach(([skill]) => {\n      const iconUrl = getSkillIconUrl(skill);\n      markdown += ` <a href=\"https://developer.mozilla.org/en-US/docs/Web/${skill}\" target=\"_blank\" rel=\"noreferrer\"> <img src=\"${iconUrl}\" alt=\"${skill}\" width=\"40\" height=\"40\"/> </a>`;\n    });\n\n    markdown += `</p>\\n\\n`;\n  }\n\n  // Support\n  if (support.buyMeACoffee) {\n    markdown += `<h3 align=\"left\">Support:</h3>\\n`;\n    markdown += `<p><a href=\"https://www.buymeacoffee.com/${support.buyMeACoffee}\"> <img align=\"left\" src=\"https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png\" height=\"50\" width=\"210\" alt=\"${support.buyMeACoffee}\" /></a></p><br><br>\\n\\n`;\n  }\n\n  // GitHub Stats\n  if (profile.githubStats && social.github) {\n    markdown += `<p><img align=\"left\" src=\"https://github-readme-stats.vercel.app/api/top-langs?username=${social.github}&show_icons=true&locale=en&layout=compact\" alt=\"${social.github}\" /></p>\\n\\n`;\n    markdown += `<p>&nbsp;<img align=\"center\" src=\"https://github-readme-stats.vercel.app/api?username=${social.github}&show_icons=true&locale=en\" alt=\"${social.github}\" /></p>\\n\\n`;\n  }\n\n  // Streak Stats\n  if (profile.streakStats && social.github) {\n    markdown += `<p><img align=\"center\" src=\"https://github-readme-streak-stats.herokuapp.com/?user=${social.github}&\" alt=\"${social.github}\" /></p>\\n\\n`;\n  }\n\n  return markdown;\n}\n\nexport function generateTitle(profile: Partial<ProfileFormData>): string {\n  return profile.title || 'My GitHub Profile';\n}\n"
  },
  {
    "path": "src/lib/storage.ts",
    "content": "import type { ProfileFormData, LinksFormData, SocialFormData, SupportFormData } from './validations';\n\nexport interface SavedFormData {\n  profile: Partial<ProfileFormData>;\n  links: Partial<LinksFormData>;\n  social: Partial<SocialFormData>;\n  support: Partial<SupportFormData>;\n  skills: Record<string, boolean>;\n  lastSaved: string;\n}\n\nconst STORAGE_KEY = 'github-profile-generator';\n\nexport function saveFormData(data: SavedFormData): void {\n  try {\n    const dataToSave = {\n      ...data,\n      lastSaved: new Date().toISOString(),\n    };\n    console.log('💾 storage.ts - saveFormData called with:', dataToSave);\n    const jsonString = JSON.stringify(dataToSave);\n    console.log('💾 storage.ts - JSON string length:', jsonString.length);\n    localStorage.setItem(STORAGE_KEY, jsonString);\n    console.log('✅ storage.ts - Successfully saved to localStorage');\n  } catch (error) {\n    console.error('❌ storage.ts - Error saving form data:', error);\n  }\n}\n\nexport function loadFormData(): SavedFormData | null {\n  try {\n    console.log('📂 storage.ts - loadFormData called');\n    const saved = localStorage.getItem(STORAGE_KEY);\n    console.log('📂 storage.ts - Raw data from localStorage:', saved ? `${saved.length} bytes` : 'null');\n    if (saved) {\n      const parsed = JSON.parse(saved);\n      console.log('✅ storage.ts - Successfully parsed data:', parsed);\n      return parsed;\n    }\n    console.log('⚠️ storage.ts - No data found in localStorage');\n  } catch (error) {\n    console.error('❌ storage.ts - Error loading form data:', error);\n  }\n  return null;\n}\n\nexport function clearFormData(): void {\n  try {\n    localStorage.removeItem(STORAGE_KEY);\n  } catch (error) {\n    console.error('Error clearing form data:', error);\n  }\n}\n\nexport function hasFormData(): boolean {\n  try {\n    const hasData = localStorage.getItem(STORAGE_KEY) !== null;\n    console.log('🔍 storage.ts - hasFormData:', hasData);\n    return hasData;\n  } catch (error) {\n    console.error('❌ storage.ts - Error checking form data:', error);\n    return false;\n  }\n}\n"
  },
  {
    "path": "src/lib/store.ts",
    "content": "import { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\nimport type { ThemeMode, ResolvedTheme, AccessibilitySettings } from '@/types/theme';\n\ninterface ThemeState {\n  mode: ThemeMode;\n  resolvedTheme: ResolvedTheme;\n  accessibility: AccessibilitySettings;\n  setMode: (mode: ThemeMode) => void;\n  setResolvedTheme: (theme: ResolvedTheme) => void;\n  setAccessibility: (settings: Partial<AccessibilitySettings>) => void;\n}\n\nexport const useThemeStore = create<ThemeState>()(\n  persist(\n    (set) => ({\n      mode: 'system',\n      resolvedTheme: 'light',\n      accessibility: {\n        highContrast: false,\n        fontSize: 'medium',\n        reducedMotion: false,\n      },\n      setMode: (mode) => set({ mode }),\n      setResolvedTheme: (resolvedTheme) => set({ resolvedTheme }),\n      setAccessibility: (settings) =>\n        set((state) => ({\n          accessibility: { ...state.accessibility, ...settings },\n        })),\n    }),\n    {\n      name: 'theme-storage',\n      partialize: (state) => ({ mode: state.mode, accessibility: state.accessibility }),\n    }\n  )\n);\n"
  },
  {
    "path": "src/lib/validations.ts",
    "content": "import { z } from 'zod';\n\n// Profile validation schema\nexport const profileSchema = z.object({\n  // Basic Information\n  title: z.string().min(1, 'Name is required').max(100, 'Name is too long'),\n  subtitle: z.string().max(200, 'Subtitle is too long'),\n\n  // About sections\n  currentWork: z.string().max(200),\n  currentLearn: z.string().max(200),\n  collaborateOn: z.string().max(200),\n  helpWith: z.string().max(200),\n  ama: z.string().max(200),\n  contact: z.string().email('Invalid email').or(z.string().max(100)),\n  funFact: z.string().max(200),\n\n  // Badges\n  visitorsBadge: z.boolean(),\n  badgeStyle: z.enum(['flat', 'flat-square', 'plastic', 'for-the-badge']),\n  badgeColor: z.string().regex(/^[0-9a-fA-F]{6}$/, 'Invalid color hex'),\n  badgeLabel: z.string().max(50),\n\n  // GitHub Stats\n  githubProfileTrophy: z.boolean(),\n  githubStats: z.boolean(),\n  githubStatsOptions: z.object({\n    theme: z.string(),\n    titleColor: z.string(),\n    textColor: z.string(),\n    bgColor: z.string(),\n    hideBorder: z.boolean(),\n    cacheSeconds: z.number().nullable(),\n    locale: z.string(),\n  }),\n\n  // Top Languages\n  topLanguages: z.boolean(),\n  topLanguagesOptions: z.object({\n    theme: z.string(),\n    titleColor: z.string(),\n    textColor: z.string(),\n    bgColor: z.string(),\n    hideBorder: z.boolean(),\n    cacheSeconds: z.number().nullable(),\n    locale: z.string(),\n  }),\n\n  // Streak Stats\n  streakStats: z.boolean(),\n  streakStatsOptions: z.object({\n    theme: z.string(),\n  }),\n\n  // Blog Integration\n  devDynamicBlogs: z.boolean(),\n  mediumDynamicBlogs: z.boolean(),\n  rssDynamicBlogs: z.boolean(),\n});\n\n// Links validation schema\nexport const linksSchema = z.object({\n  currentWork: z.string().url('Invalid URL').or(z.literal('')),\n  collaborateOn: z.string().url('Invalid URL').or(z.literal('')),\n  helpWith: z.string().url('Invalid URL').or(z.literal('')),\n  portfolio: z.string().url('Invalid URL').or(z.literal('')),\n  blog: z.string().url('Invalid URL').or(z.literal('')),\n  resume: z.string().url('Invalid URL').or(z.literal('')),\n});\n\n// Social links validation schema\nexport const socialSchema = z.object({\n  github: z.string().max(100),\n  dev: z.string().max(100),\n  linkedin: z.string().max(100),\n  codepen: z.string().max(100),\n  stackoverflow: z.string().max(100),\n  kaggle: z.string().max(100),\n  codesandbox: z.string().max(100),\n  fb: z.string().max(100),\n  instagram: z.string().max(100),\n  twitter: z.string().max(100),\n  dribbble: z.string().max(100),\n  behance: z.string().max(100),\n  medium: z.string().max(100),\n  youtube: z.string().max(100),\n  codechef: z.string().max(100),\n  hackerrank: z.string().max(100),\n  codeforces: z.string().max(100),\n  leetcode: z.string().max(100),\n  topcoder: z.string().max(100),\n  hackerearth: z.string().max(100),\n  geeks_for_geeks: z.string().max(100),\n  discord: z.string().max(100),\n  rssurl: z.string().url('Invalid URL').or(z.literal('')),\n\n  // Twitter Badge Enhancement\n  twitterBadge: z.boolean(),\n});\n\n// Support validation schema\nexport const supportSchema = z.object({\n  buyMeACoffee: z.string().max(100),\n});\n\n// Complete form schema\nexport const completeFormSchema = z.object({\n  profile: profileSchema,\n  links: linksSchema,\n  social: socialSchema,\n  support: supportSchema,\n  skills: z.record(z.string(), z.boolean()),\n});\n\nexport type ProfileFormData = z.infer<typeof profileSchema>;\nexport type LinksFormData = z.infer<typeof linksSchema>;\nexport type SocialFormData = z.infer<typeof socialSchema>;\nexport type SupportFormData = z.infer<typeof supportSchema>;\nexport type CompleteFormData = z.infer<typeof completeFormSchema>;\n"
  },
  {
    "path": "src/markdown-pages/about.md",
    "content": "---\nslug: '/about'\ndate: '2019-05-04'\ntitle: '👨‍💻 About'\n---\n\n<a href=\"https://github.com/rahuldkjain/github-profile-readme-generator/blob/master/LICENSE\" target=\"blank\">\n<img src=\"https://img.shields.io/github/license/rahuldkjain/github-profile-readme-generator?style=flat-square\" alt=\"github-profile-readme-generator license\" />\n</a>\n\n**GitHub Profile README Generator** is an OSS(Open Source Software) that provides a cool interface to generate GitHub profile README in markdown.\n\nThe tool aims to provide hassle-free experience to add trending addons like profile **visitors count**, **github-stats**, **dynamic blog posts** etc.\n\nThe profile should be neat and minimal to give a clear overview of the work. Non-uniform icons, too much content, too much images/gifs distracts visitors to see your actual work.\n\nTo solve this, GitHub Profile README Generator came into existence.\n\nSo many developers contributed to the project and made it more awesome to use. You can contribute too to make it grow even further.\n\n<p align=\"left\">\n<a href=\"https://github.com/rahuldkjain/github-profile-readme-generator/issues\" target=\"blank\">\n<img src=\"https://img.shields.io/github/issues/rahuldkjain/github-profile-readme-generator?style=flat-square\" alt=\"github-profile-readme-generator issues\"/>\n</a>\n<br>\n<a href=\"https://github.com/rahuldkjain/github-profile-readme-generator/pulls\" target=\"blank\">\n<img src=\"https://img.shields.io/github/issues-pr/rahuldkjain/github-profile-readme-generator?style=flat-square\" alt=\"github-profile-readme-generator pull-requests\"/>\n</a>\n</p>\n\n### Contributors 🙏\n\nList of the developers who contributed to the project. A big shout out for them.\n<a href=\"https://github.com/rahuldkjain/github-profile-readme-generator/graphs/contributors\">\n<img src=\"https://contributors-img.web.app/image?repo=rahuldkjain/github-profile-readme-generator\" />\n</a>\n\n<hr/>\n\n## How do I create a profile README?\n\nThe profile README is created by creating a new repository that’s the same name as your username. For example, my GitHub username is **rahuldkjain** so I created a new repository with the name **rahuldkjain**. Note: at the time of this writing, in order to access the profile README feature, the letter-casing must match your GitHub username.\n\n1. Create a new repository with the same name (including casing) as your GitHub username: https://github.com/new\n\n2. Create a README.md file inside the new repo with content (text, GIFs, images, emojis, etc.)\n\n3. Commit your fancy new README!\n   - If you're on GitHub's web interface you can choose to commit directly to the repo's main branch (i.e., master or main) which will make it immediately visible on your profile)\n4. Push changes to GitHub (if you made changes locally i.e., on your computer and not github.com)\n<hr/>\n\n## How to use?\n\nTired of editing profile README(.md) to add new features like visitors-count badge, github-stats etc?\n\nDon't worry. Keep calm, fill the form and let the tool do the work for you\n\n<img src=\"https://raw.githubusercontent.com/rahuldkjain/github-profile-readme-generator/master/src/images/github-profile-readme-generator.gif\"\nalt=\"github profile readme generator\" width=\"320\" /><br/><br/>\n\n<hr/>\n\n## Why visitors count keeps on increasing?\n\nSo many users raised an issue that the counter keeps on increasing everytime the page reloads.\n\nWell it is visitors count not \"unique\" visitors count. The goal of the addon is to provide a good stat of how well the github profile is doing.\n\nProper use or misuse of the addon is the sole responsibility of the user. The developer of the addon is working on it to fix this issue.\n"
  },
  {
    "path": "src/markdown-pages/addons.md",
    "content": "---\nslug: '/addons'\ndate: '2019-05-04'\ntitle: '🚀 Addons'\n---\n\nGitHub Profile README Generator tool uses few open-source addons developed by other developers. Including such features makes the tool useful. The developers of this tool is very grateful to use these awesome addons.\n\n## [GitHub README Stats](https://github.com/anuraghazra/github-readme-stats)\n\n⚡️ Dynamically generated stats for your github readmes\n\n#### GitHub Stats Card\n\n<a href=\"https://github.com/rahuldkjain\" target=\"blank\">\n  <img src=\"https://github-readme-stats.vercel.app/api?username=rahuldkjain&show_icons=true\" width=\"320\" alt=\"Rahul's github stats\"/>\n</a>\n\n#### Top Skills Card\n\n<a href=\"https://github.com/rahuldkjain\" target=\"blank\">\n  <img src=\"https://github-readme-stats.vercel.app/api/top-langs/?username=rahuldkjain&layout=compact&hide=html\" width=\"320\" alt=\"Rahul's github top skills\"/>\n</a>\n\nDeveloped by [Anurag Hazra](https://github.com/anuraghazra).\n\nYou can customize the theme too. See how to customize yours [here](https://github.com/anuraghazra/github-readme-stats)\n\n<br/>\n\n## [GitHub Readme Streak Stats](https://github.com/DenverCoder1/github-readme-streak-stats)\n\nStay motivated while contributing to open source by displaying your current contribution streak\n\n![rahuldkjain](https://github-readme-streak-stats.herokuapp.com/?user=rahuldkjain)\n\nDeveloped by by [Jonah Lawrence](https://github.com/DenverCoder1).\n\nSee how to customize the theme [here](https://github.com/DenverCoder1/github-readme-streak-stats)\n\n<br/>\n\n## [GitHub Profile Views Counter](https://github.com/antonkomarev/github-profile-views-counter)\n\nIt counts how many times your GitHub profile has been viewed. Free cloud micro-service.\n\n![rahuldkjain](https://komarev.com/ghpvc/?username=rahuldkjain&style=flat-square)\n\nDeveloped by by [Anton Komarev](https://github.com/antonkomarev).\n\nYou can customize the color, label and style too. See how to customize [here](https://github.com/antonkomarev/github-profile-views-counter)\n\n<br/>\n\n## [Dynamic Latest Blog Posts](https://github.com/gautamkrishnar/blog-post-workflow)\n\nShow your latest blog posts from any sources(like dev(.)to, medium etc) or StackOverflow activity on your GitHub profile/project readme automatically using the RSS feed.\n\n<img src=\"https://user-images.githubusercontent.com/8397274/88047382-29b8b280-cb6f-11ea-9efb-2af2b10f3e0c.png\" width=\"320\" alt=\"dynamic latest blog example\"/>\n\nDeveloped by [Gautam Krishna R](https://github.com/gautamkrishnar)\n\n### How to use\n\n- Go to your repository\n- Add the following section to your **README.md** file, you can give whatever title you want. Just make sure that you use **<!-- BLOG-POST-LIST:START --><!-- BLOG-POST-LIST:END -->** in your readme. The workflow will replace this comment with the actual blog post list:\n\n```markdown\n# Blog posts\n\n<!-- BLOG-POST-LIST:START -->\n<!-- BLOG-POST-LIST:END -->\n```\n\n- Create a folder named `.github` and create `workflows` folder inside it if it doesn't exist.\n- Create a new file named `blog-post-workflow.yml` with the following contents inside the workflows folder:\n\n```yaml\nname: Latest blog post workflow\non:\n  schedule:\n    # Runs every hour\n    - cron: '0 * * * *'\njobs:\n  update-readme-with-blog:\n    name: Update this repo's README with latest blog posts\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - uses: gautamkrishnar/blog-post-workflow@master\n        with:\n          feed_list: 'https://dev.to/feed/rahuldkjain, https://medium.com/feed/@rahuldkjain'\n```\n\n- Replace the above url list with your own rss feed urls. See [popular-sources](#popular-sources) for a list of common RSS feed urls.\n- Commit and wait for it to run\n\nTo know more, check out the [official github repository](https://github.com/gautamkrishnar/blog-post-workflow)\n"
  },
  {
    "path": "src/markdown-pages/support.md",
    "content": "---\nslug: '/support'\ndate: '2019-05-04'\ntitle: '💵 Support OSS'\n---\n\n> Think of giving not as a duty but as a privilege --John D. Rockefeller Hr.\n\n🚀 GitHub Profile README Generator tool is free and will always be free. Numerous developers has put their time and efforts to make this tool more powerful. However, these developers are doing their full time job along with open-source contributions.\n\nYou can come forward to support the developers by making small donations. You will never know what this support mean to them. If you find the tool really helpful, then it will be very grateful to support the tool 🙇.\n\n<p align=\"left\">\n  <a href=\"https://www.paypal.me/rahuldkjain/10\"><img src=\"https://ionicabizau.github.io/badges/paypal.svg\" alt=\"sponsor github profile readme generator\"/>\n  </a>\n\n<a href='https://ko-fi.com/A0A81XXSX' target='_blank'><img height='23' width=\"100\" src='https://cdn.ko-fi.com/cdn/kofi3.png?v=2' alt='Buy Coffee for rahuldkjain' />\n</a>\n\n<a href=\"https://www.buymeacoffee.com/rahuldkjain\" target=\"_blank\"><img src=\"https://cdn.buymeacoffee.com/buttons/default-orange.png\" alt=\"Buy Me A Coffee\" height=\"23\" width=\"100\" style=\"border-radius:2px\" />\n</a>\n\n</p>\n\n## Social Support 🤝\n\n<a href=\"https://twitter.com/intent/tweet?text=Wow:&url=https%3A%2F%2Frahuldkjain.github.io%2Fgithub-profile-readme-generator\">\n<img src=\"https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Frahuldkjain.github.io%2Fgithub-profile-readme-generator\" alt=\"tweet github profile readme generator\"/>\n</a>\n\nLet the world know how you feel using this tool. Share with others on twitter.\n\n<blockquote class=\"twitter-tweet\" data-dnt=\"true\"><p lang=\"en\" dir=\"ltr\">&quot;How to Use Github&#39;s README Feature to Track Your Stats in One Click&quot; by <a href=\"https://twitter.com/Rahuldkjain?ref_src=twsrc%5Etfw\">@rahuldkjain</a> <a href=\"https://t.co/3dxv0G2sBJ\">https://t.co/3dxv0G2sBJ</a> <a href=\"https://twitter.com/hashtag/repositoriesongithub?src=hash&amp;ref_src=twsrc%5Etfw\">#repositoriesongithub</a> <a href=\"https://twitter.com/hashtag/react?src=hash&amp;ref_src=twsrc%5Etfw\">#react</a></p>&mdash; Hacker Noon (@hackernoon) <a href=\"https://twitter.com/hackernoon/status/1301615959107678215?ref_src=twsrc%5Etfw\">September 3, 2020</a></blockquote> <script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n\n<blockquote class=\"twitter-tweet\" data-dnt=\"true\"><p lang=\"en\" dir=\"ltr\">This is a great tool to generate customized GitHub profile README: <a href=\"https://t.co/dTpnz0iTP2\">https://t.co/dTpnz0iTP2</a> <a href=\"https://t.co/WcEkK2DKz0\">pic.twitter.com/WcEkK2DKz0</a></p>&mdash; Alisher Abdulkhaev (@alisher_ai) <a href=\"https://twitter.com/alisher_ai/status/1298858350885576704?ref_src=twsrc%5Etfw\">August 27, 2020</a></blockquote>\n\n<blockquote class=\"twitter-tweet data-dnt=\"true\"\"><p lang=\"ro\" dir=\"ltr\">github profile readme generator: <a href=\"https://t.co/fQDUBdE0jz\">https://t.co/fQDUBdE0jz</a></p>&mdash; merve (@mervenoyann) <a href=\"https://twitter.com/mervenoyann/status/1301436574475976706?ref_src=twsrc%5Etfw\">September 3, 2020</a></blockquote>\n\n<blockquote class=\"twitter-tweet\" data-dnt=\"true\"><p lang=\"en\" dir=\"ltr\">This is super cool 😎 A Github Profile README Generator.<br><br>👉 Link: <a href=\"https://t.co/KHC4M9vSzw\">https://t.co/KHC4M9vSzw</a> <a href=\"https://t.co/JmrQ3P6Wkp\">pic.twitter.com/JmrQ3P6Wkp</a></p>&mdash; Dat Tran (@datitran) <a href=\"https://twitter.com/datitran/status/1298947006371713024?ref_src=twsrc%5Etfw\">August 27, 2020</a></blockquote>\n\n<blockquote class=\"twitter-tweet data-dnt=\"true\"\"><p lang=\"en\" dir=\"ltr\">Nice GitHub Profile generator, for the relatively new account README:<a href=\"https://t.co/YG3O0Pqy3M\">https://t.co/YG3O0Pqy3M</a><a href=\"https://twitter.com/hashtag/github?src=hash&amp;ref_src=twsrc%5Etfw\">#github</a></p>&mdash; Steve &quot;ardalis&quot; Smith (@ardalis) <a href=\"https://twitter.com/ardalis/status/1300953474868314118?ref_src=twsrc%5Etfw\">September 2, 2020</a></blockquote>\n\n<blockquote class=\"twitter-tweet data-dnt=\"true\"\"><p lang=\"ro\" dir=\"ltr\">Github Profile Readme Generator <a href=\"https://t.co/p20HK5gGHF\">https://t.co/p20HK5gGHF</a> <a href=\"https://t.co/nFyhrO3XjN\">pic.twitter.com/nFyhrO3XjN</a></p>&mdash; Speckyboy (@speckyboy) <a href=\"https://twitter.com/speckyboy/status/1301233718405869568?ref_src=twsrc%5Etfw\">September 2, 2020</a></blockquote>\n\n<blockquote class=\"twitter-tweet\" data-dnt=\"true\"><p lang=\"en\" dir=\"ltr\">I finally updated my github readme <a href=\"https://t.co/8rcyuW1UTM\">https://t.co/8rcyuW1UTM</a> <br>thanks to this generator : <a href=\"https://t.co/c0GHc4n1S6\">https://t.co/c0GHc4n1S6</a> plus some changes.<br><br>Thank you <a href=\"https://twitter.com/Rahuldkjain?ref_src=twsrc%5Etfw\">@Rahuldkjain</a> for this great generator, saved me a lot of time.</p>&mdash; Abir El Halimi (@abiir07) <a href=\"https://twitter.com/abiir07/status/1299013498178076673?ref_src=twsrc%5Etfw\">August 27, 2020</a></blockquote>\n\n<blockquote class=\"twitter-tweet\" data-dnt=\"true\"><p lang=\"en\" dir=\"ltr\">This morning I set up my <a href=\"https://twitter.com/hashtag/github?src=hash&amp;ref_src=twsrc%5Etfw\">#github</a> profile readme, really amazing what great tools the users have already created to make this easier.<br><br>Big shout out to <a href=\"https://twitter.com/Rahuldkjain?ref_src=twsrc%5Etfw\">@rahuldkjain</a>!<a href=\"https://t.co/bL0XwfJ78B\">https://t.co/bL0XwfJ78B</a> <a href=\"https://t.co/xBLVFOJegt\">pic.twitter.com/xBLVFOJegt</a></p>&mdash; Max Schmitt (@maxibanki) <a href=\"https://twitter.com/maxibanki/status/1296408691273498624?ref_src=twsrc%5Etfw\">August 20, 2020</a></blockquote>\n\n<blockquote class=\"twitter-tweet\" data-dnt=\"true\"><p lang=\"en\" dir=\"ltr\">Special thanks to everyone&#39;s repos that are featured in my latest video:<a href=\"https://twitter.com/bathtype?ref_src=twsrc%5Etfw\">@bathtype</a><a href=\"https://twitter.com/anuraghazru?ref_src=twsrc%5Etfw\">@anuraghazru</a><a href=\"https://twitter.com/Shields_io?ref_src=twsrc%5Etfw\">@Shields_io</a><a href=\"https://twitter.com/AlexandreSanlim?ref_src=twsrc%5Etfw\">@AlexandreSanlim</a><a href=\"https://twitter.com/Ileriayooo?ref_src=twsrc%5Etfw\">@Ileriayooo</a><a href=\"https://twitter.com/james_madhacks?ref_src=twsrc%5Etfw\">@james_madhacks</a><a href=\"https://twitter.com/misteranmol?ref_src=twsrc%5Etfw\">@misteranmol</a><a href=\"https://twitter.com/n_moore?ref_src=twsrc%5Etfw\">@n_moore</a><a href=\"https://twitter.com/novatorem?ref_src=twsrc%5Etfw\">@novatorem</a><a href=\"https://twitter.com/Rahuldkjain?ref_src=twsrc%5Etfw\">@Rahuldkjain</a><a href=\"https://twitter.com/geeky_abhiz?ref_src=twsrc%5Etfw\">@geeky_abhiz</a><br><br>These developers are making your GitHub Profiles look awesome! 💪</p>&mdash; 𝚌𝚘𝚍𝚎𝚂𝚃𝙰𝙲𝙺𝚛 ⚡👨‍💻 (@codeSTACKr) <a href=\"https://twitter.com/codeSTACKr/status/1294618297086943232?ref_src=twsrc%5Etfw\">August 15, 2020</a></blockquote> <script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n\n<blockquote class=\"twitter-tweet data-dnt=\"true\"\" data-theme=\"light\"><p lang=\"tr\" dir=\"ltr\">GitHub Profile Readme Generator ile GitHub profilinizi profesyonelleştirin! <a href=\"https://t.co/iaZAdGtf9t\">https://t.co/iaZAdGtf9t</a></p>&mdash; Yazılım Karavanı (@yazilimkaravani) <a href=\"https://twitter.com/yazilimkaravani/status/1301467413591007232?ref_src=twsrc%5Etfw\">September 3, 2020</a></blockquote>\n\n<blockquote class=\"twitter-tweet data-dnt=\"true\"\"><p lang=\"ro\" dir=\"ltr\"><a href=\"https://twitter.com/hashtag/CSS?src=hash&amp;ref_src=twsrc%5Etfw\">#CSS</a> <a href=\"https://twitter.com/hashtag/Automated?src=hash&amp;ref_src=twsrc%5Etfw\">#Automated</a> | Github Profile README Generator <a href=\"https://t.co/CTcrnDuWov\">https://t.co/CTcrnDuWov</a></p>&mdash; Yohan J. Rodríguez (@hasdid) <a href=\"https://twitter.com/hasdid/status/1299070955646586882?ref_src=twsrc%5Etfw\">August 27, 2020</a></blockquote>\n\n<blockquote class=\"twitter-tweet data-dnt=\"true\"\"><p lang=\"en\" dir=\"ltr\">If you are unsure or need to spice up your GitHub README page. Check out this cool Github profile readme Generator by ⁦<a href=\"https://twitter.com/Rahuldkjain?ref_src=twsrc%5Etfw\">@Rahuldkjain</a>⁩. <a href=\"https://twitter.com/hashtag/rstats?src=hash&amp;ref_src=twsrc%5Etfw\">#rstats</a> <a href=\"https://twitter.com/hashtag/github?src=hash&amp;ref_src=twsrc%5Etfw\">#github</a> ⁦<a href=\"https://twitter.com/github?ref_src=twsrc%5Etfw\">@github</a>⁩ <a href=\"https://twitter.com/hashtag/AcademicTwitter?src=hash&amp;ref_src=twsrc%5Etfw\">#AcademicTwitter</a> <a href=\"https://t.co/OMyYJJYmxR\">https://t.co/OMyYJJYmxR</a></p>&mdash; Seevasant Indran (@zeeva85) <a href=\"https://twitter.com/zeeva85/status/1301213068060438528?ref_src=twsrc%5Etfw\">September 2, 2020</a></blockquote>\n\n<blockquote class=\"twitter-tweet data-dnt=\"true\"\"><p lang=\"en\" dir=\"ltr\">Github Profile README Generator<br>By <a href=\"https://twitter.com/Rahuldkjain?ref_src=twsrc%5Etfw\">@Rahuldkjain</a> <br><br>Pretty way to create GitHub profile README with addons.<br><br>Check out on <a href=\"https://twitter.com/ProductHunt?ref_src=twsrc%5Etfw\">@ProductHunt</a> <a href=\"https://t.co/qgxhLmUgV2\">https://t.co/qgxhLmUgV2</a></p>&mdash; Raj Maurya (@codemaurya) <a href=\"https://twitter.com/codemaurya/status/1299700992577957888?ref_src=twsrc%5Etfw\">August 29, 2020</a></blockquote>\n\n<script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n\n## Sponsors 🙇\n\n- [Scott C Wilson](https://github.com/scottcwilson) donated the first ever grant to this tool. A big thanks to him.\n- [Max Schmitt](https://github.com/mxschmitt) loved the tool and showed the support with his donation. Thanks a lot.\n"
  },
  {
    "path": "src/styles/tailwind.css",
    "content": "@tailwind base;\n\n@tailwind components;\n\n@tailwind utilities;\n\n@tailwind @screens;\n\n/* Additional vertical padding used by kbd tag. */\n.py-05 {\n  padding-top: 0.125rem;\n  padding-bottom: 0.125rem;\n}\n\n.markdown {\n  @apply text-gray-900 leading-normal break-words;\n}\n\n.markdown > * + * {\n  @apply mt-0 mb-4;\n}\n\n.markdown li + li {\n  @apply mt-1;\n}\n\n.markdown li > p + p {\n  @apply mt-6;\n}\n\n.markdown strong {\n  @apply font-semibold;\n}\n\n.markdown a {\n  @apply text-blue-600 font-semibold;\n}\n\n.markdown strong a {\n  @apply font-bold;\n}\n\n.markdown h1 {\n  @apply leading-tight border-b text-4xl font-semibold mb-4 mt-6 pb-2;\n}\n\n.markdown h2 {\n  @apply leading-tight border-b text-2xl font-semibold mb-4 mt-6 pb-2;\n}\n\n.markdown h3 {\n  @apply leading-snug text-lg font-semibold mb-4 mt-6;\n}\n\n.markdown h4 {\n  @apply leading-none text-base font-semibold mb-4 mt-6;\n}\n\n.markdown h5 {\n  @apply leading-tight text-sm font-semibold mb-4 mt-6;\n}\n\n.markdown h6 {\n  @apply leading-tight text-sm font-semibold text-gray-600 mb-4 mt-6;\n}\n\n.markdown blockquote {\n  @apply text-base border-l-4 border-gray-300 pl-4 pr-4 text-gray-600;\n}\n\n.markdown code {\n  @apply font-body text-sm inline bg-gray-200 rounded px-1 py-05;\n}\n\n.markdown pre {\n  @apply bg-gray-900 text-white overflow-scroll rounded p-4;\n}\n\n.markdown pre code {\n  @apply block p-0 rounded-none text-white;\n}\n\n.markdown ul {\n  @apply text-base pl-8 list-disc;\n}\n\n.markdown ol {\n  @apply text-base pl-8 list-decimal;\n}\n\n.markdown kbd {\n  @apply text-xs inline-block rounded border px-1 py-05 align-middle font-normal font-body shadow;\n}\n\n.markdown table {\n  @apply text-base border-gray-600;\n}\n\n.markdown th {\n  @apply border py-1 px-3;\n}\n\n.markdown td {\n  @apply border py-1 px-3;\n}\n\n/* Override pygments style background color. */\n.markdown .highlight pre {\n  @apply bg-gray-100 !important;\n}\n"
  },
  {
    "path": "src/test/setup.ts",
    "content": "import '@testing-library/jest-dom';\n\n// Add custom matchers or global test setup here\n"
  },
  {
    "path": "src/types/profile.ts",
    "content": "// Profile data types\nexport interface ProfilePrefix {\n  title: string;\n  currentWork: string;\n  currentLearn: string;\n  collaborateOn: string;\n  helpWith: string;\n  ama: string;\n  contact: string;\n  resume: string;\n  funFact: string;\n  portfolio: string;\n  blog: string;\n}\n\nexport interface GithubStatsOptions {\n  theme: string;\n  titleColor: string;\n  textColor: string;\n  bgColor: string;\n  hideBorder: boolean;\n  cacheSeconds: number | null;\n  locale: string;\n}\n\nexport interface TopLanguagesOptions {\n  theme: string;\n  titleColor: string;\n  textColor: string;\n  bgColor: string;\n  hideBorder: boolean;\n  cacheSeconds: number | null;\n  locale: string;\n}\n\nexport interface StreakStatsOptions {\n  theme: string;\n}\n\nexport interface ProfileData {\n  title: string;\n  subtitle: string;\n  currentWork: string;\n  currentLearn: string;\n  collaborateOn: string;\n  helpWith: string;\n  ama: string;\n  contact: string;\n  funFact: string;\n  visitorsBadge: boolean;\n  badgeStyle: 'flat' | 'flat-square' | 'plastic' | 'for-the-badge';\n  badgeColor: string;\n  badgeLabel: string;\n  githubProfileTrophy: boolean;\n  githubStats: boolean;\n  githubStatsOptions: GithubStatsOptions;\n  topLanguages: boolean;\n  topLanguagesOptions: TopLanguagesOptions;\n  streakStats: boolean;\n  streakStatsOptions: StreakStatsOptions;\n  devDynamicBlogs: boolean;\n  mediumDynamicBlogs: boolean;\n  rssDynamicBlogs: boolean;\n}\n\nexport interface ProfileLinks {\n  currentWork: string;\n  collaborateOn: string;\n  helpWith: string;\n  portfolio: string;\n  blog: string;\n  resume: string;\n}\n\nexport interface SocialLinks {\n  github: string;\n  dev: string;\n  linkedin: string;\n  codepen: string;\n  stackoverflow: string;\n  kaggle: string;\n  codesandbox: string;\n  fb: string;\n  instagram: string;\n  twitter: string;\n  dribbble: string;\n  behance: string;\n  medium: string;\n  youtube: string;\n  codechef: string;\n  hackerrank: string;\n  codeforces: string;\n  leetcode: string;\n  topcoder: string;\n  hackerearth: string;\n  geeks_for_geeks: string;\n  discord: string;\n  rssurl: string;\n  twitterBadge: boolean;\n}\n\nexport interface SupportLinks {\n  buyMeACoffee: string;\n}\n\nexport interface Skills {\n  [key: string]: boolean;\n}\n"
  },
  {
    "path": "src/types/skills.ts",
    "content": "export interface SkillCategory {\n  title: string;\n  skills: string[];\n}\n\nexport interface CategorizedSkills {\n  [key: string]: SkillCategory;\n}\n\nexport interface SkillIcons {\n  [key: string]: string;\n}\n\nexport interface SkillWebsites {\n  [key: string]: string;\n}\n\nexport type SkillState = Record<string, boolean>;\n"
  },
  {
    "path": "src/types/theme.ts",
    "content": "export type ThemeMode = 'light' | 'dark' | 'system';\nexport type ResolvedTheme = 'light' | 'dark';\n\nexport interface AccessibilitySettings {\n  highContrast: boolean;\n  fontSize: 'small' | 'medium' | 'large';\n  reducedMotion: boolean;\n}\n"
  },
  {
    "path": "tailwind.config.js",
    "content": "module.exports = {\n  purge: [],\n  theme: {\n    extend: {},\n    fontSize: {\n      xxs: '.60rem',\n      xs: '.75rem',\n      sm: '.875rem',\n      tiny: '.875rem',\n      base: '1rem',\n      lg: '1.125rem',\n      xl: '1.25rem',\n      '2xl': '1.5rem',\n      '3xl': '1.875rem',\n      '4xl': '2.25rem',\n      '5xl': '3rem',\n      '6xl': '4rem',\n      '7xl': '5rem',\n    },\n    fontFamily: {\n      title: ['Lato', 'sans-serif'],\n      body: ['Roboto Mono', 'monospace'],\n    },\n  },\n  variants: {},\n  plugins: [],\n};\n"
  },
  {
    "path": "tailwind.config.ts",
    "content": "import type { Config } from 'tailwindcss';\n\nconst config: Config = {\n  content: [\n    // Only scan the actual source files we need\n    './src/app/**/*.{js,ts,jsx,tsx}',\n    './src/components/**/*.{js,ts,jsx,tsx}',\n    './src/lib/**/*.{js,ts,jsx,tsx}',\n    // Exclude heavy directories\n    '!./src/constants/**',\n    '!./node_modules/**',\n    '!./old-gatsby-backup/**',\n    '!./out/**',\n  ],\n  theme: {\n    extend: {\n      fontFamily: {\n        sans: ['var(--font-wotfard)', 'system-ui', 'sans-serif'],\n        mono: ['var(--font-roboto-mono)', 'monospace'],\n      },\n      colors: {\n        border: 'hsl(var(--border))',\n        input: 'hsl(var(--input))',\n        ring: 'hsl(var(--ring))',\n        background: 'hsl(var(--background))',\n        foreground: 'hsl(var(--foreground))',\n        primary: {\n          DEFAULT: 'hsl(var(--primary))',\n          foreground: 'hsl(var(--primary-foreground))',\n        },\n        secondary: {\n          DEFAULT: 'hsl(var(--secondary))',\n          foreground: 'hsl(var(--secondary-foreground))',\n        },\n        destructive: {\n          DEFAULT: 'hsl(var(--destructive))',\n          foreground: 'hsl(var(--destructive-foreground))',\n        },\n        muted: {\n          DEFAULT: 'hsl(var(--muted))',\n          foreground: 'hsl(var(--muted-foreground))',\n        },\n        accent: {\n          DEFAULT: 'hsl(var(--accent))',\n          foreground: 'hsl(var(--accent-foreground))',\n        },\n        popover: {\n          DEFAULT: 'hsl(var(--popover))',\n          foreground: 'hsl(var(--popover-foreground))',\n        },\n        card: {\n          DEFAULT: 'hsl(var(--card))',\n          foreground: 'hsl(var(--card-foreground))',\n        },\n      },\n      borderRadius: {\n        lg: 'var(--radius)',\n        md: 'calc(var(--radius) - 2px)',\n        sm: 'calc(var(--radius) - 4px)',\n      },\n      animation: {\n        'fade-in': 'fadeIn 0.3s ease-in-out',\n        'slide-in': 'slideIn 0.3s ease-out',\n        'bounce-in': 'bounceIn 0.6s ease-out',\n      },\n      keyframes: {\n        fadeIn: {\n          '0%': { opacity: '0' },\n          '100%': { opacity: '1' },\n        },\n        slideIn: {\n          '0%': { transform: 'translateY(-10px)', opacity: '0' },\n          '100%': { transform: 'translateY(0)', opacity: '1' },\n        },\n        bounceIn: {\n          '0%, 20%, 40%, 60%, 80%': {\n            transform: 'translateY(0)',\n          },\n          '10%, 30%, 50%, 70%, 90%': {\n            transform: 'translateY(-10px)',\n          },\n        },\n      },\n    },\n  },\n  plugins: [require('@tailwindcss/typography')],\n};\n\nexport default config;\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2017\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"preserve\",\n    \"incremental\": true,\n    \"plugins\": [\n      {\n        \"name\": \"next\"\n      }\n    ],\n    \"paths\": {\n      \"@/*\": [\"./src/*\"]\n    }\n  },\n  \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \".next/types/**/*.ts\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "vitest.config.ts",
    "content": "import { defineConfig } from 'vitest/config';\nimport react from '@vitejs/plugin-react';\nimport path from 'path';\n\nexport default defineConfig({\n  plugins: [react()],\n  test: {\n    environment: 'jsdom',\n    globals: true,\n    setupFiles: ['./src/test/setup.ts'],\n    coverage: {\n      provider: 'v8',\n      reporter: ['text', 'json', 'html'],\n      exclude: [\n        'node_modules/',\n        'src/test/',\n        '**/*.config.ts',\n        '**/*.config.js',\n        '**/*.d.ts',\n        '**/types/',\n      ],\n    },\n  },\n  resolve: {\n    alias: {\n      '@': path.resolve(__dirname, './src'),\n    },\n  },\n});\n"
  }
]