[
  {
    "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_pagefind/"
  },
  {
    "path": ".source/index.ts",
    "content": "// @ts-nocheck -- skip type checking\nimport * as docs_10 from \"../content/docs/extensions/quicksnip.mdx?collection=docs&hash=1765841507830\"\nimport * as docs_9 from \"../content/docs/extensions/quicksnip-vscode.mdx?collection=docs&hash=1765841507830\"\nimport * as docs_8 from \"../content/docs/extensions/quicksnip-raycast.mdx?collection=docs&hash=1765841507830\"\nimport * as docs_7 from \"../content/docs/extensions/quicksnip-cli.mdx?collection=docs&hash=1765841507830\"\nimport * as docs_6 from \"../content/docs/contributing/third-party-apps.mdx?collection=docs&hash=1765841507830\"\nimport * as docs_5 from \"../content/docs/contributing/modifying-snippets.mdx?collection=docs&hash=1765841507830\"\nimport * as docs_4 from \"../content/docs/contributing/how-to-contribute.mdx?collection=docs&hash=1765841507830\"\nimport * as docs_3 from \"../content/docs/contributing/adding-snippets.mdx?collection=docs&hash=1765841507830\"\nimport * as docs_2 from \"../content/docs/installation.mdx?collection=docs&hash=1765841507830\"\nimport * as docs_1 from \"../content/docs/index.mdx?collection=docs&hash=1765841507830\"\nimport * as docs_0 from \"../content/docs/comparison.mdx?collection=docs&hash=1765841507830\"\nimport { _runtime } from \"fumadocs-mdx/runtime/next\"\nimport * as _source from \"../source.config\"\nexport const docs = _runtime.docs<typeof _source.docs>([{ info: {\"path\":\"comparison.mdx\",\"fullPath\":\"content/docs/comparison.mdx\"}, data: docs_0 }, { info: {\"path\":\"index.mdx\",\"fullPath\":\"content/docs/index.mdx\"}, data: docs_1 }, { info: {\"path\":\"installation.mdx\",\"fullPath\":\"content/docs/installation.mdx\"}, data: docs_2 }, { info: {\"path\":\"contributing/adding-snippets.mdx\",\"fullPath\":\"content/docs/contributing/adding-snippets.mdx\"}, data: docs_3 }, { info: {\"path\":\"contributing/how-to-contribute.mdx\",\"fullPath\":\"content/docs/contributing/how-to-contribute.mdx\"}, data: docs_4 }, { info: {\"path\":\"contributing/modifying-snippets.mdx\",\"fullPath\":\"content/docs/contributing/modifying-snippets.mdx\"}, data: docs_5 }, { info: {\"path\":\"contributing/third-party-apps.mdx\",\"fullPath\":\"content/docs/contributing/third-party-apps.mdx\"}, data: docs_6 }, { info: {\"path\":\"extensions/quicksnip-cli.mdx\",\"fullPath\":\"content/docs/extensions/quicksnip-cli.mdx\"}, data: docs_7 }, { info: {\"path\":\"extensions/quicksnip-raycast.mdx\",\"fullPath\":\"content/docs/extensions/quicksnip-raycast.mdx\"}, data: docs_8 }, { info: {\"path\":\"extensions/quicksnip-vscode.mdx\",\"fullPath\":\"content/docs/extensions/quicksnip-vscode.mdx\"}, data: docs_9 }, { info: {\"path\":\"extensions/quicksnip.mdx\",\"fullPath\":\"content/docs/extensions/quicksnip.mdx\"}, data: docs_10 }], [{\"info\":{\"path\":\"meta.json\",\"fullPath\":\"content/docs/meta.json\"},\"data\":{\"title\":\"Docs\",\"pages\":[\"---Introduction---\",\"index.mdx\",\"installation.mdx\",\"comparison.mdx\",\"---Extensions---\",\"...extensions\",\"---Contributing---\",\"...contributing\"],\"root\":true}}, {\"info\":{\"path\":\"contributing/meta.json\",\"fullPath\":\"content/docs/contributing/meta.json\"},\"data\":{\"title\":\"Contributing\",\"pages\":[\"how-to-contribute\",\"adding-snippets\",\"modifying-snippets\",\"third-party-apps\"]}}, {\"info\":{\"path\":\"extensions/meta.json\",\"fullPath\":\"content/docs/extensions/meta.json\"},\"data\":{\"title\":\"Extensions\",\"pages\":[\"quicksnip\",\"quicksnip-cli\",\"quicksnip-vscode\",\"quicksnip-raycast\"]}}])"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to QuickSnip\n\n> THIS FILE NEEDS TO BE REWORKED. IT'S IMPORTED FROM PREVIOUS VERSION FOR TESTING.\n\nHey there! 👋 First off, thanks for taking the time to contribute! ❤️\n\nYou can contribute in two main ways:\n\n- **Improving the code** (like fixing bugs or adding cool new features)\n- **Adding new code snippets** (or improving the existing ones!)\n\n---\n\n## Improving the code\n\n### How to report bugs\n\nIf you spot a bug in the codebase or issues with the documentation, please open up a [GitHub issue](https://github.com/technoph1le/quicksnip/issues) detailing the problem before creating a PR. Once confirmed with maintainers, you can then create a PR.\n\n### How to propose new features\n\nIf you are interested in proposing new features, please open up a new [GitHub discussion](https://github.com/technoph1le/quicksnip/discussions) with details for the proposed feature.\n\nPlease do not create a PR for a new feature without first discussing it with the maintainers. If you create a PR for a new feature without discussing it first, then your PR will be closed.\n\n---\n\n## Snippets Guidelines\n\n### Snippet Tags\n\n- Tags must describe the snippet with simple word.\n\nHere's an example:\n\n```md\n---\ntitle: Convert Number to Currency\ndescription: Converts a number to a currency format with a specific locale.\nauthor: axorax\ntags: number,currency\n---\n```\n\n**Do not use generic keywords or the language itself as a tag `utility` or `javascript`!**\n\n### Snippet Format\n\n**All** snippets should follow the following structure:\n\n- A `code` segment, containing a function with the actual snippet functionnality\n- An `example` segement, containing one or more examples of use\n\nExample in javascript:\n\n```js\nfunction example(x) {\n  return x * 2;\n}\n\n// Usage:\nexample(5); // Returns: 10\n```\n\nIf your function doesn't return anything just show how to use it. If the result of your function is too complicated to be expressed in a single comment, your snippet is probably too complex to begin with.\n\n### Snippet boundaries\n\nTo ensure your snippet isn’t refused, consider these questions:\n\n- **Does the standard library of my language provide an easy way of doing this ?**\n- **Does that snippet not have a real, and practical use case ?**\n- **Could it be split into separate parts to be better understood ?**\n\nIf any answer is yes, then your snippet will most likely get rejected.\n\n---\n\n## Adding Snippets\n\n### Adding a New Snippet\n\n1. **Ensure your snippet match [guidelines](#snippets-guidelines)**\n\n2. **Navigate to the relevant folder:**\n\n   - Go to the `/snippets` folder in the root directory.\n   - Locate the folder for the programming language of your snippet, such as `javascript` or `python`.\n\n3. **Choose the correct category:**\n\n   - Within the language folder, find the relevant category folder for your snippet.\n   - If no suitable category exists, refer to [Adding a New Category](#adding-a-new-category).\n\n4. **Create a markdown file:**\n\n   - Create a new file with a `.md` extension.\n   - Name the file appropriately, keeping it descriptive and concise.\n\n5. **Add your snippet:**\n\n   - Use the following format to structure your snippet:\n\n````md\n---\ntitle: Name of the snippet\ndescription: A short explanation of what the snippet does\ntags: tag1, tag2, tag3\nauthor: your-github-username\n---\n\n```lang\n// Your code here\n```\n````\n\nHere’s an example for JavaScript:\n\n````md\n---\ntitle: Format Date\ndescription: Formats a date in 'YYYY-MM-DD' format.\nauthor: technoph1le\ntags: date,format\n---\n\n```js\nconst formatDate = (date) => date.toISOString().split(\"T\")[0];\n\n// Usage:\nconsole.log(formatDate(new Date())); // Output: '2024-12-10'\n```\n````\n\n6. **Use syntax highlighting:**\n\n   - Enclose your code with triple backticks (```).\n   - Specify the language after the first set of backticks for syntax highlighting.\n\n7. **Test your snippet:**\n\n   - Ensure your code runs as expected. \\\n      To test that your snippets are formatted correctly use the `snippets:check` script:\n\n     ```\n     $ npm run snippets:check\n     ```\n\n     It will return nothing if they are well formatted, otherwise it will tell you what the error is.\n\n     ***\n\n     To preview the snippets, start the vite server using:\n\n     ```\n     $ npm run dev\n     ```\n\n     It will use HMR to update the snippets in the `/public` folder, making them available to the frontend.\n\nExpected file structure:\n\n```md\n/snippets\n|- language\n|- category-name\n|- your-snippet-here.md\n```\n\n> Please do **NOT** add or edit anything in `/public` folder. It will be used for consolidating snippets.\n\n### Editing a Existing Snippet\n\nIf you’d like to refine or improve an existing snippet:\n\n1. **Add a `contributors` field:**\n\n   - Include your GitHub username under the `contributors` field in the metadata section.\n\n````md\n---\ntitle: Name of the snippet\ndescription: A short explanation of what the snippet does\ntags: tag1, tag2, tag3\nauthor: original-author\ncontributors: your-github-username\n---\n\n```\nUpdated code here\n```\n````\n\n2. **Credit all contributors:**\n\n   - If contributors already exist, add your username separated by a comma\n\n```md\ncontributors: contributor1, contributor2, your-github-username\n```\n\n3. **Document changes:**\n\n   - Clearly indicate what you updated and why in your pull request description.\n\n> We want to make sure that original author and contributor(s) are credited for their work.\n\n### Adding a New Category\n\nIf your snippet doesn’t fit into any existing category, you can create a new one! Just make sure it’s unique and doesn’t overlap with others (e.g., don’t create separate categories for “Date” and “Time” when “Date and Time” works).\n\n1. **Create a new category folder:**\n\n   - In the relevant language directory, add a new folder.\n   - Use a lowercase name with hyphens for separation (e.g., `file-handling`).\n\n2. **Add snippets:**\n\n   - Follow the [Adding a New Snippet](#adding-a-new-snippet) instructions.\n\nExample structure:\n\n```md\n/snippets\n|- python\n|- file-handling\n|- list-manipulation\n|- ....\n```\n\n### Adding a New Language\n\nIf you want to introduce a new programming language, here's how to do it:\n\n1. **Create a language folder:**\n\n   - Add a new folder under the `snippets` directory.\n   - Name it after the language in lowercase (e.g., `go`, `ruby`).\n\n2. **Add categories and snippets:**\n\n   - Follow the [Adding a New Snippet](#adding-a-new-snippet) and [Adding a New Category](#adding-a-new-category) guidelines.\n\n3. **Include an icon:**\n\n   - Add an `icon.svg` file (50x50px) in the same language folder.\n   - Use tools like [Resize SVG](https://www.iloveimg.com/resize-image/resize-svg) to ensure the correct size.\n\n4. **Double-check your work:**\n\n   - Verify that everything is structured correctly and displays as intended.\n\n---\n\n## Testing Snippets\n\nTo test that your snippets are formatted correctly use the following script:\n\n```\n$ npm run snippets:check\n```\n\nIt will return nothing if they are well formatted, otherwise it will tell you what the error is.\n\n---\n\nTo preview the snippets, you need to consolidate them, use the following script:\n\n```\n$ npm run snippets:consolidate\n```\n\nIt will update the snippets in the `/public` folder, making them available to the frontend.\n\n## Final Notes\n\nWhether you’re fixing a tiny typo, writing a new snippet, or dreaming up big features, every bit counts! 🛠️\n\nIf you have any questions or need help, feel free to open a new [GitHub discussion](https://github.com/technoph1le/quicksnip/discussions).\n\nHappy coding! 💻✨\n"
  },
  {
    "path": "README.md",
    "content": "# QuickSnip\n\nQuickSnip is an open-source tool designed for developers who want to organize, search, and share code snippets across various programming languages. It provides a centralized platform for managing handy snippets. Built with love and powered by an awesome community. 🚀\n\n<div>\n<a href=\"https://youtu.be/BhRi7fJzPgk?si=z1sVXU7uRS0bkSEt\" target=\"_blank\">\n  <img src=\"https://img.shields.io/static/v1?label=&message=Watch%20on%20YouTube&labelColor=FFFFFF&color=FF0000&style=for-the-badge&logo=youtube&logoColor=FF0000\" alt=\"Watch on YouTube\">\n</a>\n<div>\n\n<br>\n\n![Website preview](/preview.png)\n\n## How to Contribute\n\nWant to help make QuickSnip even better? You can contribute by:\n\n- **Improving the Code**: Fix bugs, suggest new features, or optimize the project.\n- **Adding New Snippets**: Share your favorite snippets to grow the database.\n\nCheck out the [CONTRIBUTING.md](/CONTRIBUTING.md) file for detailed contribution guidelines.\n\n## General Rules\n\nTo keep everything smooth and consistent, please:\n\n- [x] Follow the project’s style and contribution rules.\n- [x] Be kind and respectful to others.\n- [x] If you’re unsure, ask questions.\n\nFollowing these rules helps us build an awesome community. 🚀\n\n## Third-Party\n\nWe love to see the creativity of our community! If you build something using QuickSnip, let us know. Here are some featured examples:\n\n- ⚡️ [**Raycast Extension**](https://www.raycast.com/anders_morille/quicksnip): An extension to browse and use QuickSnip snippets directly from Raycast. (Thanks to the creator: [@lille-morille](https://github.com/lille-morille))\n\nIf you’d like to create your own extension or tool:\n\n- [x] Please ensure it adheres to our project’s licensing and attribution requirements.\n- [x] Please link to the [original QuickSnip repository](https://github.com/technoph1le/quicksnip) in your extension/tool to attribute the source.\n- [x] Share your work with us — we’d be thrilled to feature it!\n\n## Project Vision\n\nFor a detailed look into our goals, future direction, and aspirations, see the [VISION.md](/VISION.md) file.\n\n## License\n\nQuickSnip is licensed under the [MIT License](/LICENSE). Feel free to use and share it as you like.\n\n<a href=\"https://www.producthunt.com/products/quicksnip\" target=\"_blank\" style=\"text-decoration: none;\">\n  <img src=\"https://img.shields.io/static/v1?label=&message=Leave%20a%20Review&labelColor=FFFFFF&color=DA552F&style=for-the-badge&logo=product-hunt&logoColor=DA552F\" alt=\"Leave a Review\">\n</a>\n"
  },
  {
    "path": "components.json",
    "content": "{\n  \"$schema\": \"https://ui.shadcn.com/schema.json\",\n  \"style\": \"new-york\",\n  \"rsc\": true,\n  \"tsx\": true,\n  \"tailwind\": {\n    \"config\": \"\",\n    \"css\": \"src/app/globals.css\",\n    \"baseColor\": \"neutral\",\n    \"cssVariables\": true,\n    \"prefix\": \"\"\n  },\n  \"aliases\": {\n    \"components\": \"@/components\",\n    \"utils\": \"@/lib/utils\",\n    \"ui\": \"@/components/ui\",\n    \"lib\": \"@/lib\",\n    \"hooks\": \"@/hooks\"\n  },\n  \"iconLibrary\": \"lucide\"\n}"
  },
  {
    "path": "content/docs/comparison.mdx",
    "content": "---\ntitle: Comparison\ndescription: Hello World\n---\n\n## This is title\n\nThis is description\n"
  },
  {
    "path": "content/docs/contributing/adding-snippets.mdx",
    "content": "---\ntitle: Adding snippets\ndescription: Hello World\n---\n\n## This is title\n\nThis is description\n"
  },
  {
    "path": "content/docs/contributing/how-to-contribute.mdx",
    "content": "---\ntitle: How to contribute\ndescription: Hello World\n---\n\n## This is title\n\nThis is description\n"
  },
  {
    "path": "content/docs/contributing/meta.json",
    "content": "{\n  \"title\": \"Contributing\",\n  \"pages\": [\n    \"how-to-contribute\",\n    \"adding-snippets\",\n    \"modifying-snippets\",\n    \"third-party-apps\"\n  ]\n}\n"
  },
  {
    "path": "content/docs/contributing/modifying-snippets.mdx",
    "content": "---\ntitle: Modifying snippets\ndescription: Hello World\n---\n\n## This is title\n\nThis is description\n"
  },
  {
    "path": "content/docs/contributing/third-party-apps.mdx",
    "content": "---\ntitle: Third-party apps\ndescription: Hello World\n---\n\n## How to add an extension\n\nThis is description\n"
  },
  {
    "path": "content/docs/extensions/meta.json",
    "content": "{\n  \"title\": \"Extensions\",\n  \"pages\": [\n    \"quicksnip\",\n    \"quicksnip-cli\",\n    \"quicksnip-vscode\",\n    \"quicksnip-raycast\"\n  ]\n}\n"
  },
  {
    "path": "content/docs/extensions/quicksnip-cli.mdx",
    "content": "---\ntitle: QuickSnip CLI\ndescription: Hello World\n---\n\n## This is title\n\nThis is description\n"
  },
  {
    "path": "content/docs/extensions/quicksnip-raycast.mdx",
    "content": "---\ntitle: QuickSnip Raycast\ndescription: Hello World\n---\n\n## This is title\n\nThis is description\n"
  },
  {
    "path": "content/docs/extensions/quicksnip-vscode.mdx",
    "content": "---\ntitle: QuickSnip VS Code\ndescription: Hello World\n---\n\n## This is title\n\nThis is description\n"
  },
  {
    "path": "content/docs/extensions/quicksnip.mdx",
    "content": "---\ntitle: QuickSnip\ndescription: Hello World\n---\n\n## This is title\n\nThis is description\n"
  },
  {
    "path": "content/docs/index.mdx",
    "content": "---\ntitle: Get Started\ndescription: Hello World\n---\n\n## This is title\n\nThis is description\n"
  },
  {
    "path": "content/docs/installation.mdx",
    "content": "---\ntitle: Installation\ndescription: Hello World\n---\n\n## This is title\n\nThis is description\n"
  },
  {
    "path": "content/docs/meta.json",
    "content": "{\n  \"title\": \"Docs\",\n  \"root\": true,\n  \"pages\": [\n    \"---Introduction---\",\n    \"index.mdx\",\n    \"installation.mdx\",\n    \"comparison.mdx\",\n    \"---Extensions---\",\n    \"...extensions\",\n    \"---Contributing---\",\n    \"...contributing\"\n  ]\n}\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\"),\n];\n\nexport default eslintConfig;\n"
  },
  {
    "path": "mdx-components.tsx",
    "content": "import defaultMdxComponents from \"fumadocs-ui/mdx\";\nimport type { MDXComponents } from \"mdx/types\";\n\nexport function getMDXComponents(components?: MDXComponents): MDXComponents {\n  return {\n    ...defaultMdxComponents,\n    ...components,\n  };\n}\n"
  },
  {
    "path": "next.config.ts",
    "content": "import { createMDX } from \"fumadocs-mdx/next\";\n\nconst withMDX = createMDX();\n\n/** @type {import('next').NextConfig} */\nconst config = {\n  reactStrictMode: true,\n  images: {\n    remotePatterns: [\n      new URL(\"https://img.youtube.com/vi/**\"),\n      new URL(\"https://storage.ko-fi.com/cdn/**\"),\n    ],\n  },\n};\n\nexport default withMDX(config);\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"quicksnip\",\n  \"version\": \"2.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"prebuild\": \"tsx scripts/merge-snippets.ts\",\n    \"build\": \"next build\",\n    \"start\": \"next start\",\n    \"lint\": \"next lint\",\n    \"postinstall\": \"fumadocs-mdx\"\n  },\n  \"dependencies\": {\n    \"@radix-ui/react-accordion\": \"^1.2.11\",\n    \"@radix-ui/react-aspect-ratio\": \"^1.1.7\",\n    \"@radix-ui/react-avatar\": \"^1.1.10\",\n    \"@radix-ui/react-dialog\": \"^1.1.15\",\n    \"@radix-ui/react-label\": \"^2.1.7\",\n    \"@radix-ui/react-navigation-menu\": \"^1.2.13\",\n    \"@radix-ui/react-select\": \"^2.2.6\",\n    \"@radix-ui/react-separator\": \"^1.1.7\",\n    \"@radix-ui/react-slot\": \"^1.2.3\",\n    \"@radix-ui/react-switch\": \"^1.2.5\",\n    \"@radix-ui/react-tabs\": \"^1.1.13\",\n    \"@radix-ui/react-tooltip\": \"^1.2.8\",\n    \"@types/mdx\": \"^2.0.13\",\n    \"class-variance-authority\": \"^0.7.1\",\n    \"clsx\": \"^2.1.1\",\n    \"framer-motion\": \"^12.23.12\",\n    \"fumadocs-core\": \"^15.6.9\",\n    \"fumadocs-mdx\": \"^12.0.3\",\n    \"fumadocs-ui\": \"^15.6.9\",\n    \"lucide-react\": \"^0.535.0\",\n    \"next\": \"15.4.10\",\n    \"radix-ui\": \"^1.4.3\",\n    \"react\": \"^19.1.0\",\n    \"react-dom\": \"^19.1.0\",\n    \"react-icons\": \"^5.5.0\",\n    \"react-markdown\": \"^10.1.0\",\n    \"react-syntax-highlighter\": \"^15.6.6\",\n    \"remark-gfm\": \"^4.0.1\",\n    \"tailwind-merge\": \"^3.3.1\",\n    \"zustand\": \"^5.0.8\"\n  },\n  \"devDependencies\": {\n    \"@eslint/eslintrc\": \"^3\",\n    \"@tailwindcss/postcss\": \"^4\",\n    \"@tailwindcss/typography\": \"^0.5.16\",\n    \"@types/node\": \"^20\",\n    \"@types/react\": \"^19\",\n    \"@types/react-dom\": \"^19\",\n    \"@types/react-syntax-highlighter\": \"^15.5.13\",\n    \"eslint\": \"^9\",\n    \"eslint-config-next\": \"15.4.5\",\n    \"pagefind\": \"^1.3.0\",\n    \"tailwindcss\": \"^4\",\n    \"tsx\": \"^4.20.5\",\n    \"tw-animate-css\": \"^1.3.6\",\n    \"typescript\": \"^5\"\n  }\n}\n"
  },
  {
    "path": "postcss.config.mjs",
    "content": "const config = {\n  plugins: [\"@tailwindcss/postcss\"],\n};\n\nexport default config;\n"
  },
  {
    "path": "public/data/snippets/README.md",
    "content": "# IMPORTANT\n\n### This folder is read-only. Do NOT modify this folder!"
  },
  {
    "path": "public/data/snippets/all.json",
    "content": "[\n  {\n    \"id\": \"shuffle-array\",\n    \"category\": \"array-manipulation\",\n    \"title\": \"Shuffle Array\",\n    \"description\": \"Shuffles the items in an array.\",\n    \"languages\": [\n      \"js\"\n    ],\n    \"contributors\": [\n      \"loxt-nixo\"\n    ],\n    \"tags\": [\n      \"array\",\n      \"shuffle\",\n      \"random\"\n    ]\n  },\n  {\n    \"id\": \"add-localstorage\",\n    \"category\": \"data-handling\",\n    \"title\": \"Add Item to localStorage\",\n    \"description\": \"Stores a value in localStorage under the given key.\",\n    \"languages\": [\n      \"js\"\n    ],\n    \"contributors\": [\n      \"technoph1le\"\n    ],\n    \"tags\": [\n      \"localStorage\",\n      \"storage\",\n      \"memory\"\n    ]\n  },\n  {\n    \"id\": \"number-to-currency\",\n    \"category\": \"number-formatting\",\n    \"title\": \"Convert Number to Currency\",\n    \"description\": \"Converts a number to a currency format with a specific locale.\",\n    \"languages\": [\n      \"js\"\n    ],\n    \"contributors\": [\n      \"axorax\"\n    ],\n    \"tags\": [\n      \"number\",\n      \"currency\"\n    ]\n  },\n  {\n    \"id\": \"reverse-string\",\n    \"category\": \"string-manipulation\",\n    \"title\": \"Reverse String\",\n    \"description\": \"Reverses the characters in a string.\",\n    \"languages\": [\n      \"js\",\n      \"cpp\",\n      \"py\"\n    ],\n    \"contributors\": [\n      \"technoph1le\",\n      \"Vaibhav-kesarwani\"\n    ],\n    \"tags\": [\n      \"string\",\n      \"reverse\"\n    ]\n  },\n  {\n    \"id\": \"string-to-camel-case\",\n    \"category\": \"string-manipulation\",\n    \"title\": \"Convert String to Camel Case\",\n    \"description\": \"Converts a given string into camelCase.\",\n    \"languages\": [\n      \"js\",\n      \"java\"\n    ],\n    \"contributors\": [\n      \"aumirza\",\n      \"Mcbencrafter\"\n    ],\n    \"tags\": [\n      \"string\",\n      \"case\"\n    ]\n  },\n  {\n    \"id\": \"string-to-param-case\",\n    \"category\": \"string-manipulation\",\n    \"title\": \"Convert String to Param Case\",\n    \"description\": \"Converts a given string into param-case.\",\n    \"languages\": [\n      \"js\",\n      \"java\"\n    ],\n    \"contributors\": [\n      \"aumirza\",\n      \"Mcbencrafter\"\n    ],\n    \"tags\": [\n      \"string\",\n      \"case\"\n    ]\n  },\n  {\n    \"id\": \"string-to-pascal-case\",\n    \"category\": \"string-manipulation\",\n    \"title\": \"Convert String to Pascal Case\",\n    \"description\": \"Converts a given string into PascalCase.\",\n    \"languages\": [\n      \"js\",\n      \"java\"\n    ],\n    \"contributors\": [\n      \"aumirza\",\n      \"Mcbencrafter\"\n    ],\n    \"tags\": [\n      \"string\",\n      \"case\"\n    ]\n  },\n  {\n    \"id\": \"string-to-snake-case\",\n    \"category\": \"string-manipulation\",\n    \"title\": \"Convert String to Snake Case\",\n    \"description\": \"Converts a given string into snake_case.\",\n    \"languages\": [\n      \"js\",\n      \"java\"\n    ],\n    \"contributors\": [\n      \"axorax\",\n      \"Mcbencrafter\"\n    ],\n    \"tags\": [\n      \"string\",\n      \"case\"\n    ]\n  },\n  {\n    \"id\": \"string-to-title-case\",\n    \"category\": \"string-manipulation\",\n    \"title\": \"Convert String to Title Case\",\n    \"description\": \"Converts a given string into Title Case.\",\n    \"languages\": [\n      \"js\"\n    ],\n    \"contributors\": [\n      \"aumirza\"\n    ],\n    \"tags\": [\n      \"string\",\n      \"case\"\n    ]\n  },\n  {\n    \"id\": \"truncate-sring\",\n    \"category\": \"string-manipulation\",\n    \"title\": \"Truncate String\",\n    \"description\": \"Truncates a string after a specified length.\",\n    \"languages\": [\n      \"js\",\n      \"java\",\n      \"py\"\n    ],\n    \"contributors\": [\n      \"realvishalrana\",\n      \"Mcbencrafter\",\n      \"axorax\",\n      \"MinerMinerMods\"\n    ],\n    \"tags\": [\n      \"string\",\n      \"truncate\",\n      \"mask\",\n      \"hide\"\n    ]\n  }\n]"
  },
  {
    "path": "public/data/snippets/array-manipulation/shuffle-array.json",
    "content": "{\n  \"id\": \"shuffle-array\",\n  \"category\": \"array-manipulation\",\n  \"title\": \"Shuffle Array\",\n  \"description\": \"Shuffles the items in an array.\",\n  \"languages\": [\n    \"js\"\n  ],\n  \"contributors\": [\n    \"loxt-nixo\"\n  ],\n  \"tags\": [\n    \"array\",\n    \"shuffle\",\n    \"random\"\n  ],\n  \"snippets\": {\n    \"js\": \"function shuffleArray(array) {\\r\\n    for (let i = array.length - 1; i >= 0; i--) {\\r\\n        const j = Math.floor(Math.random() * (i + 1));\\r\\n        [array[i], array[j]] = [array[j], array[i]];\\r\\n    }\\r\\n}\\r\\n\\r\\n// Usage:\\r\\nconst array = [1, 2, 3, 4, 5];\\r\\nshuffleArray(array); // Shuffles `array` in place\"\n  }\n}"
  },
  {
    "path": "public/data/snippets/data-handling/add-localstorage.json",
    "content": "{\n  \"id\": \"add-localstorage\",\n  \"category\": \"data-handling\",\n  \"title\": \"Add Item to localStorage\",\n  \"description\": \"Stores a value in localStorage under the given key.\",\n  \"languages\": [\n    \"js\"\n  ],\n  \"contributors\": [\n    \"technoph1le\"\n  ],\n  \"tags\": [\n    \"localStorage\",\n    \"storage\",\n    \"memory\"\n  ],\n  \"snippets\": {\n    \"js\": \"const addToLocalStorage = (key, value) => {\\r\\n  localStorage.setItem(key, JSON.stringify(value));\\r\\n};\\r\\n\\r\\n// Usage:\\r\\naddToLocalStorage('user', { name: 'John', age: 30 });\"\n  }\n}"
  },
  {
    "path": "public/data/snippets/number-formatting/number-to-currency.json",
    "content": "{\n  \"id\": \"number-to-currency\",\n  \"category\": \"number-formatting\",\n  \"title\": \"Convert Number to Currency\",\n  \"description\": \"Converts a number to a currency format with a specific locale.\",\n  \"languages\": [\n    \"js\"\n  ],\n  \"contributors\": [\n    \"axorax\"\n  ],\n  \"tags\": [\n    \"number\",\n    \"currency\"\n  ],\n  \"snippets\": {\n    \"js\": \"const convertToCurrency = (num, locale = 'en-US', currency = 'USD') => {\\r\\n  return new Intl.NumberFormat(locale, {\\r\\n    style: 'currency',\\r\\n    currency: currency\\r\\n  }).format(num);\\r\\n};\\r\\n\\r\\n// Usage:\\r\\nconvertToCurrency(1234567.89); // Returns: '$1,234,567.89'\\r\\nconvertToCurrency(987654.32, 'de-DE', 'EUR'); // Returns: '987.654,32 €'\"\n  }\n}"
  },
  {
    "path": "public/data/snippets/string-manipulation/reverse-string.json",
    "content": "{\n  \"id\": \"reverse-string\",\n  \"category\": \"string-manipulation\",\n  \"title\": \"Reverse String\",\n  \"description\": \"Reverses the characters in a string.\",\n  \"languages\": [\n    \"js\",\n    \"cpp\",\n    \"py\"\n  ],\n  \"contributors\": [\n    \"technoph1le\",\n    \"Vaibhav-kesarwani\"\n  ],\n  \"tags\": [\n    \"string\",\n    \"reverse\"\n  ],\n  \"snippets\": {\n    \"js\": \"const reverseString = (str) => str.split('').reverse().join('');\\r\\n\\r\\n// Usage:\\r\\nreverseString('hello'); // Returns: 'olleh'\",\n    \"cpp\": \"#include <string>\\r\\n#include <algorithm>\\r\\n\\r\\nstd::string reverseString(const std::string& input) {\\r\\n    std::string reversed = input;\\r\\n    std::reverse(reversed.begin(), reversed.end());\\r\\n    return reversed;\\r\\n}\\r\\n\\r\\n// Usage:\\r\\nreverseString(\\\"quicksnip\\\"); // Returns: \\\"pinskciuq\\\"\",\n    \"py\": \"def reverse_string(s:str) -> str:\\r\\n    return s[::-1]\\r\\n\\r\\n# Usage:\\r\\nreverse_string('hello') # Returns: 'olleh'\"\n  }\n}"
  },
  {
    "path": "public/data/snippets/string-manipulation/string-to-camel-case.json",
    "content": "{\n  \"id\": \"string-to-camel-case\",\n  \"category\": \"string-manipulation\",\n  \"title\": \"Convert String to Camel Case\",\n  \"description\": \"Converts a given string into camelCase.\",\n  \"languages\": [\n    \"js\",\n    \"java\"\n  ],\n  \"contributors\": [\n    \"aumirza\",\n    \"Mcbencrafter\"\n  ],\n  \"tags\": [\n    \"string\",\n    \"case\"\n  ],\n  \"snippets\": {\n    \"js\": \"function toCamelCase(str) {\\r\\n  return str.replace(/\\\\W+(.)/g, (match, chr) => chr.toUpperCase());\\r\\n}\\r\\n\\r\\n// Usage:\\r\\ntoCamelCase('hello world test'); // Returns: 'helloWorldTest'\",\n    \"java\": \"public static String stringToCamelCase(String text) {\\r\\n    String[] words = text.split(\\\"\\\\\\\\s+\\\");\\r\\n    StringBuilder camelCase = new StringBuilder(\\r\\n        words[0].substring(0, 1).toLowerCase() + words[0].substring(1)\\r\\n    );\\r\\n\\r\\n    for (int i = 1; i < words.length; i++) {\\r\\n        camelCase.append(words[i].substring(0, 1).toUpperCase());\\r\\n        camelCase.append(words[i].substring(1));\\r\\n    }\\r\\n\\r\\n    return camelCase.toString();\\r\\n}\\r\\n\\r\\n// Usage:\\r\\nSystem.out.println(stringToCamelCase(\\\"Hello world test\\\")); // \\\"helloWorldTest\\\"\"\n  }\n}"
  },
  {
    "path": "public/data/snippets/string-manipulation/string-to-param-case.json",
    "content": "{\n  \"id\": \"string-to-param-case\",\n  \"category\": \"string-manipulation\",\n  \"title\": \"Convert String to Param Case\",\n  \"description\": \"Converts a given string into param-case.\",\n  \"languages\": [\n    \"js\",\n    \"java\"\n  ],\n  \"contributors\": [\n    \"aumirza\",\n    \"Mcbencrafter\"\n  ],\n  \"tags\": [\n    \"string\",\n    \"case\"\n  ],\n  \"snippets\": {\n    \"js\": \"function toParamCase(str) {\\r\\n  return str.toLowerCase().replace(/\\\\s+/g, '-');\\r\\n}\\r\\n\\r\\n// Usage:\\r\\ntoParamCase('Hello World Test'); // Returns: 'hello-world-test'\",\n    \"java\": \"public static String stringToParamCase(String text) {\\r\\n    return text.toLowerCase().replaceAll(\\\"\\\\\\\\s+\\\", \\\"-\\\");\\r\\n}\\r\\n\\r\\n// Usage:\\r\\nSystem.out.println(stringToParamCase(\\\"Hello World 123\\\")); // \\\"hello-world-123\\\"\"\n  }\n}"
  },
  {
    "path": "public/data/snippets/string-manipulation/string-to-pascal-case.json",
    "content": "{\n  \"id\": \"string-to-pascal-case\",\n  \"category\": \"string-manipulation\",\n  \"title\": \"Convert String to Pascal Case\",\n  \"description\": \"Converts a given string into PascalCase.\",\n  \"languages\": [\n    \"js\",\n    \"java\"\n  ],\n  \"contributors\": [\n    \"aumirza\",\n    \"Mcbencrafter\"\n  ],\n  \"tags\": [\n    \"string\",\n    \"case\"\n  ],\n  \"snippets\": {\n    \"js\": \"function toPascalCase(str) {\\r\\n  return str.replace(/\\\\b\\\\w/g, (s) => s.toUpperCase()).replace(/\\\\W+(.)/g, (match, chr) => chr.toUpperCase());\\r\\n}\\r\\n\\r\\n// Usage:\\r\\ntoPascalCase('hello world test'); // Returns: 'HelloWorldTest'\",\n    \"java\": \"public static String stringToPascalCase(String text) {\\r\\n    String[] words = text.split(\\\"\\\\\\\\s+\\\");\\r\\n    StringBuilder pascalCase = new StringBuilder();\\r\\n\\r\\n    for (String word : words) {\\r\\n        pascalCase.append(word.substring(0, 1).toUpperCase());\\r\\n        pascalCase.append(word.substring(1).toLowerCase());\\r\\n    }\\r\\n\\r\\n    return pascalCase.toString();\\r\\n}\\r\\n\\r\\n// Usage:\\r\\nSystem.out.println(stringToPascalCase(\\\"hello world\\\")); // \\\"HelloWorld\\\"\"\n  }\n}"
  },
  {
    "path": "public/data/snippets/string-manipulation/string-to-snake-case.json",
    "content": "{\n  \"id\": \"string-to-snake-case\",\n  \"category\": \"string-manipulation\",\n  \"title\": \"Convert String to Snake Case\",\n  \"description\": \"Converts a given string into snake_case.\",\n  \"languages\": [\n    \"js\",\n    \"java\"\n  ],\n  \"contributors\": [\n    \"axorax\",\n    \"Mcbencrafter\"\n  ],\n  \"tags\": [\n    \"string\",\n    \"case\"\n  ],\n  \"snippets\": {\n    \"js\": \"function toSnakeCase(str) {\\r\\n  return str.replace(/([a-z])([A-Z])/g, '$1_$2')\\r\\n            .replace(/\\\\s+/g, '_')\\r\\n            .toLowerCase();\\r\\n}\\r\\n\\r\\n// Usage:\\r\\ntoSnakeCase('Hello World Test'); // Returns: 'hello_world_test'\",\n    \"java\": \"public static String stringToSnakeCase(String text) {\\r\\n    return text.toLowerCase().replaceAll(\\\"\\\\\\\\s+\\\", \\\"_\\\");\\r\\n}\\r\\n\\r\\n// Usage:\\r\\nSystem.out.println(stringToSnakeCase(\\\"Hello World 123\\\")); // \\\"hello_world_123\\\"\"\n  }\n}"
  },
  {
    "path": "public/data/snippets/string-manipulation/string-to-title-case.json",
    "content": "{\n  \"id\": \"string-to-title-case\",\n  \"category\": \"string-manipulation\",\n  \"title\": \"Convert String to Title Case\",\n  \"description\": \"Converts a given string into Title Case.\",\n  \"languages\": [\n    \"js\"\n  ],\n  \"contributors\": [\n    \"aumirza\"\n  ],\n  \"tags\": [\n    \"string\",\n    \"case\"\n  ],\n  \"snippets\": {\n    \"js\": \"function toTitleCase(str) {\\r\\n  return str.toLowerCase().replace(/\\\\b\\\\w/g, (s) => s.toUpperCase());\\r\\n}\\r\\n\\r\\n// Usage:\\r\\ntoTitleCase('hello world test'); // Returns: 'Hello World Test'\"\n  }\n}"
  },
  {
    "path": "public/data/snippets/string-manipulation/truncate-sring.json",
    "content": "{\n  \"id\": \"truncate-sring\",\n  \"category\": \"string-manipulation\",\n  \"title\": \"Truncate String\",\n  \"description\": \"Truncates a string after a specified length.\",\n  \"languages\": [\n    \"js\",\n    \"java\",\n    \"py\"\n  ],\n  \"contributors\": [\n    \"realvishalrana\",\n    \"Mcbencrafter\",\n    \"axorax\",\n    \"MinerMinerMods\"\n  ],\n  \"tags\": [\n    \"string\",\n    \"truncate\",\n    \"mask\",\n    \"hide\"\n  ],\n  \"snippets\": {\n    \"js\": \"const truncateText = (text = '', maxLength = 50) => {\\r\\n  return `${text.slice(0, maxLength)}${text.length >= maxLength ? '...' : ''}`;\\r\\n};\\r\\n\\r\\n// Usage:\\r\\nconst title = \\\"Hello, World! This is a Test.\\\";\\r\\ntruncateText(title, 10); // Returns: 'Hello, Wor...'\",\n    \"java\": \"public static String truncate(String text, int length, String suffix) {\\r\\n    if (text.length() <= length)\\r\\n        return text;\\r\\n    \\r\\n    return text.substring(0, length).trim() + (suffix != null ? suffix : \\\"\\\");\\r\\n}\\r\\n\\r\\n// Usage:\\r\\nSystem.out.println(truncate(\\\"hello world\\\", 5, \\\"...\\\")); // \\\"hello...\\\"\",\n    \"py\": \"def truncate(s:str, length:int, suffix:bool = True) -> str :\\r\\n    return (s[:length] + (\\\"...\\\" if suffix else \\\"\\\")) if len(s) > length else s\\r\\n\\r\\n# Usage:\\r\\ntruncate('This is a long string', 10) # Returns: 'This is a ...'\\r\\ntruncate('This is a long string', 10, False) # Returns: 'This is a '\"\n  }\n}"
  },
  {
    "path": "scripts/merge-snippets.ts",
    "content": "import fs from \"fs\";\nimport path from \"path\";\n\nconst SNIPPETS_DIR = path.join(process.cwd(), \"snippets\");\nconst OUTPUT_DIR = path.join(process.cwd(), \"public\", \"data\", \"snippets\");\n\n/**\n * Extracts the code from markdown into a `{ language: code }` object.\n */\nfunction parseMarkdown(mdContent: string) {\n  const regex = /```([a-zA-Z0-9+#-]*)\\s*([\\s\\S]*?)```/g;\n  const snippets: { [lang: string]: string } = {};\n  let match;\n\n  while ((match = regex.exec(mdContent)) !== null) {\n    const lang = match[1];\n    const code = match[2].trim();\n    snippets[lang] = code;\n  }\n\n  return snippets;\n}\n\n/**\n * Loads the `.json` and `.md` file of each snippet, and combines them into one object.\n */\nfunction mergeSnippet(category: string, name: string) {\n  const basePath = path.join(SNIPPETS_DIR, category, name);\n  const mdFile = basePath + \".md\";\n  const jsonFile = basePath + \".json\";\n\n  if (!fs.existsSync(mdFile) || !fs.existsSync(jsonFile)) return null;\n\n  const mdContent = fs.readFileSync(mdFile, \"utf-8\");\n  const meta = JSON.parse(fs.readFileSync(jsonFile, \"utf-8\"));\n  const snippets = parseMarkdown(mdContent);\n\n  return {\n    id: name,\n    category,\n    ...meta,\n    snippets,\n  };\n}\n\n/**\n * Reads all categories inside `/snippets` and merge their snippets.\n */\nfunction scanSnippets(dir: string) {\n  const items = [];\n\n  for (const category of fs.readdirSync(dir)) {\n    const categoryPath = path.join(dir, category);\n    if (!fs.statSync(categoryPath).isDirectory()) continue;\n\n    for (const file of fs.readdirSync(categoryPath)) {\n      if (file.endsWith(\".json\")) {\n        const name = file.replace(\".json\", \"\");\n        const snippet = mergeSnippet(category, name);\n        if (snippet) items.push(snippet);\n      }\n    }\n  }\n\n  return items;\n}\n\n/**\n * Generates JSON output for each snippet and a global all.json.\n */\nfunction buildSnippets() {\n  const allSnippets = scanSnippets(SNIPPETS_DIR);\n\n  // write individual files\n  for (const snippet of allSnippets) {\n    const outDir = path.join(OUTPUT_DIR, snippet.category);\n    if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });\n\n    const outFile = path.join(outDir, `${snippet.id}.json`);\n    fs.writeFileSync(outFile, JSON.stringify(snippet, null, 2));\n  }\n\n  // write all.json (metadata only)\n  const allMeta = allSnippets.map(({ snippets, ...meta }) => meta);\n  fs.writeFileSync(\n    path.join(OUTPUT_DIR, \"all.json\"),\n    JSON.stringify(allMeta, null, 2)\n  );\n\n  console.log(\"✅ Snippets built:\", allSnippets.length);\n}\n\nbuildSnippets();\n"
  },
  {
    "path": "snippets/README.md",
    "content": "\n\n## Markdown Format\n\n````\n```js\n// code here\n```\n\n---\n\n```py\n# code here\n```\n````\n\n\n## JSON Format\n\n```json\n{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"languages\": [\"\"],\n  \"contributors\": [\"\"],\n  \"tags\": [\"\", \"\"]\n}\n```"
  },
  {
    "path": "snippets/array-manipulation/shuffle-array.json",
    "content": "{\n  \"title\": \"Shuffle Array\",\n  \"description\": \"Shuffles the items in an array.\",\n  \"languages\": [\"js\"],\n  \"contributors\": [\"loxt-nixo\"],\n  \"tags\": [\"array\", \"shuffle\", \"random\"]\n}\n"
  },
  {
    "path": "snippets/array-manipulation/shuffle-array.md",
    "content": "```js\nfunction shuffleArray(array) {\n    for (let i = array.length - 1; i >= 0; i--) {\n        const j = Math.floor(Math.random() * (i + 1));\n        [array[i], array[j]] = [array[j], array[i]];\n    }\n}\n\n// Usage:\nconst array = [1, 2, 3, 4, 5];\nshuffleArray(array); // Shuffles `array` in place\n```"
  },
  {
    "path": "snippets/data-handling/add-localstorage.json",
    "content": "{\n  \"title\": \"Add Item to localStorage\",\n  \"description\": \"Stores a value in localStorage under the given key.\",\n  \"languages\": [\"js\"],\n  \"contributors\": [\"technoph1le\"],\n  \"tags\": [\"localStorage\", \"storage\", \"memory\"]\n}\n"
  },
  {
    "path": "snippets/data-handling/add-localstorage.md",
    "content": "```js\nconst addToLocalStorage = (key, value) => {\n  localStorage.setItem(key, JSON.stringify(value));\n};\n\n// Usage:\naddToLocalStorage('user', { name: 'John', age: 30 });\n```"
  },
  {
    "path": "snippets/number-formatting/number-to-currency.json",
    "content": "{\n  \"title\": \"Convert Number to Currency\",\n  \"description\": \"Converts a number to a currency format with a specific locale.\",\n  \"languages\": [\"js\"],\n  \"contributors\": [\"axorax\"],\n  \"tags\": [\"number\", \"currency\"]\n}\n"
  },
  {
    "path": "snippets/number-formatting/number-to-currency.md",
    "content": "```js\nconst convertToCurrency = (num, locale = 'en-US', currency = 'USD') => {\n  return new Intl.NumberFormat(locale, {\n    style: 'currency',\n    currency: currency\n  }).format(num);\n};\n\n// Usage:\nconvertToCurrency(1234567.89); // Returns: '$1,234,567.89'\nconvertToCurrency(987654.32, 'de-DE', 'EUR'); // Returns: '987.654,32 €'\n```"
  },
  {
    "path": "snippets/string-manipulation/reverse-string.json",
    "content": "{\n  \"title\": \"Reverse String\",\n  \"description\": \"Reverses the characters in a string.\",\n  \"languages\": [\"js\", \"cpp\", \"py\"],\n  \"contributors\": [\"technoph1le\", \"Vaibhav-kesarwani\"],\n  \"tags\": [\"string\", \"reverse\"]\n}\n"
  },
  {
    "path": "snippets/string-manipulation/reverse-string.md",
    "content": "```js\nconst reverseString = (str) => str.split('').reverse().join('');\n\n// Usage:\nreverseString('hello'); // Returns: 'olleh'\n```\n\n---\n\n```cpp\n#include <string>\n#include <algorithm>\n\nstd::string reverseString(const std::string& input) {\n    std::string reversed = input;\n    std::reverse(reversed.begin(), reversed.end());\n    return reversed;\n}\n\n// Usage:\nreverseString(\"quicksnip\"); // Returns: \"pinskciuq\"\n```\n\n---\n\n```py\ndef reverse_string(s:str) -> str:\n    return s[::-1]\n\n# Usage:\nreverse_string('hello') # Returns: 'olleh'\n```"
  },
  {
    "path": "snippets/string-manipulation/string-to-camel-case.json",
    "content": "{\n  \"title\": \"Convert String to Camel Case\",\n  \"description\": \"Converts a given string into camelCase.\",\n  \"languages\": [\"js\", \"java\"],\n  \"contributors\": [\"aumirza\", \"Mcbencrafter\"],\n  \"tags\": [\"string\", \"case\"]\n}\n"
  },
  {
    "path": "snippets/string-manipulation/string-to-camel-case.md",
    "content": "```js\nfunction toCamelCase(str) {\n  return str.replace(/\\W+(.)/g, (match, chr) => chr.toUpperCase());\n}\n\n// Usage:\ntoCamelCase('hello world test'); // Returns: 'helloWorldTest'\n```\n\n---\n\n```java\npublic static String stringToCamelCase(String text) {\n    String[] words = text.split(\"\\\\s+\");\n    StringBuilder camelCase = new StringBuilder(\n        words[0].substring(0, 1).toLowerCase() + words[0].substring(1)\n    );\n\n    for (int i = 1; i < words.length; i++) {\n        camelCase.append(words[i].substring(0, 1).toUpperCase());\n        camelCase.append(words[i].substring(1));\n    }\n\n    return camelCase.toString();\n}\n\n// Usage:\nSystem.out.println(stringToCamelCase(\"Hello world test\")); // \"helloWorldTest\"\n```"
  },
  {
    "path": "snippets/string-manipulation/string-to-param-case.json",
    "content": "{\n  \"title\": \"Convert String to Param Case\",\n  \"description\": \"Converts a given string into param-case.\",\n  \"languages\": [\"js\", \"java\"],\n  \"contributors\": [\"aumirza\", \"Mcbencrafter\"],\n  \"tags\": [\"string\", \"case\"]\n}\n"
  },
  {
    "path": "snippets/string-manipulation/string-to-param-case.md",
    "content": "```js\nfunction toParamCase(str) {\n  return str.toLowerCase().replace(/\\s+/g, '-');\n}\n\n// Usage:\ntoParamCase('Hello World Test'); // Returns: 'hello-world-test'\n```\n\n---\n\n```java\npublic static String stringToParamCase(String text) {\n    return text.toLowerCase().replaceAll(\"\\\\s+\", \"-\");\n}\n\n// Usage:\nSystem.out.println(stringToParamCase(\"Hello World 123\")); // \"hello-world-123\"\n```"
  },
  {
    "path": "snippets/string-manipulation/string-to-pascal-case.json",
    "content": "{\n  \"title\": \"Convert String to Pascal Case\",\n  \"description\": \"Converts a given string into PascalCase.\",\n  \"languages\": [\"js\", \"java\"],\n  \"contributors\": [\"aumirza\", \"Mcbencrafter\"],\n  \"tags\": [\"string\", \"case\"]\n}\n"
  },
  {
    "path": "snippets/string-manipulation/string-to-pascal-case.md",
    "content": "```js\nfunction toPascalCase(str) {\n  return str.replace(/\\b\\w/g, (s) => s.toUpperCase()).replace(/\\W+(.)/g, (match, chr) => chr.toUpperCase());\n}\n\n// Usage:\ntoPascalCase('hello world test'); // Returns: 'HelloWorldTest'\n```\n\n---\n\n```java\npublic static String stringToPascalCase(String text) {\n    String[] words = text.split(\"\\\\s+\");\n    StringBuilder pascalCase = new StringBuilder();\n\n    for (String word : words) {\n        pascalCase.append(word.substring(0, 1).toUpperCase());\n        pascalCase.append(word.substring(1).toLowerCase());\n    }\n\n    return pascalCase.toString();\n}\n\n// Usage:\nSystem.out.println(stringToPascalCase(\"hello world\")); // \"HelloWorld\"\n```"
  },
  {
    "path": "snippets/string-manipulation/string-to-snake-case.json",
    "content": "{\n  \"title\": \"Convert String to Snake Case\",\n  \"description\": \"Converts a given string into snake_case.\",\n  \"languages\": [\"js\", \"java\"],\n  \"contributors\": [\"axorax\", \"Mcbencrafter\"],\n  \"tags\": [\"string\", \"case\"]\n}\n"
  },
  {
    "path": "snippets/string-manipulation/string-to-snake-case.md",
    "content": "```js\nfunction toSnakeCase(str) {\n  return str.replace(/([a-z])([A-Z])/g, '$1_$2')\n            .replace(/\\s+/g, '_')\n            .toLowerCase();\n}\n\n// Usage:\ntoSnakeCase('Hello World Test'); // Returns: 'hello_world_test'\n```\n\n---\n\n```java\npublic static String stringToSnakeCase(String text) {\n    return text.toLowerCase().replaceAll(\"\\\\s+\", \"_\");\n}\n\n// Usage:\nSystem.out.println(stringToSnakeCase(\"Hello World 123\")); // \"hello_world_123\"\n```"
  },
  {
    "path": "snippets/string-manipulation/string-to-title-case.json",
    "content": "{\n  \"title\": \"Convert String to Title Case\",\n  \"description\": \"Converts a given string into Title Case.\",\n  \"languages\": [\"js\"],\n  \"contributors\": [\"aumirza\"],\n  \"tags\": [\"string\", \"case\"]\n}\n"
  },
  {
    "path": "snippets/string-manipulation/string-to-title-case.md",
    "content": "```js\nfunction toTitleCase(str) {\n  return str.toLowerCase().replace(/\\b\\w/g, (s) => s.toUpperCase());\n}\n\n// Usage:\ntoTitleCase('hello world test'); // Returns: 'Hello World Test'\n```"
  },
  {
    "path": "snippets/string-manipulation/truncate-sring.json",
    "content": "{\n  \"title\": \"Truncate String\",\n  \"description\": \"Truncates a string after a specified length.\",\n  \"languages\": [\"js\", \"java\", \"py\"],\n  \"contributors\": [\n    \"realvishalrana\",\n    \"Mcbencrafter\",\n    \"axorax\",\n    \"MinerMinerMods\"\n  ],\n  \"tags\": [\"string\", \"truncate\", \"mask\", \"hide\"]\n}\n"
  },
  {
    "path": "snippets/string-manipulation/truncate-sring.md",
    "content": "```js\nconst truncateText = (text = '', maxLength = 50) => {\n  return `${text.slice(0, maxLength)}${text.length >= maxLength ? '...' : ''}`;\n};\n\n// Usage:\nconst title = \"Hello, World! This is a Test.\";\ntruncateText(title, 10); // Returns: 'Hello, Wor...'\n```\n\n---\n\n```java\npublic static String truncate(String text, int length, String suffix) {\n    if (text.length() <= length)\n        return text;\n    \n    return text.substring(0, length).trim() + (suffix != null ? suffix : \"\");\n}\n\n// Usage:\nSystem.out.println(truncate(\"hello world\", 5, \"...\")); // \"hello...\"\n```\n\n---\n\n```py\ndef truncate(s:str, length:int, suffix:bool = True) -> str :\n    return (s[:length] + (\"...\" if suffix else \"\")) if len(s) > length else s\n\n# Usage:\ntruncate('This is a long string', 10) # Returns: 'This is a ...'\ntruncate('This is a long string', 10, False) # Returns: 'This is a '\n```"
  },
  {
    "path": "source.config.ts",
    "content": "import {\n  defineConfig,\n  defineDocs,\n  frontmatterSchema,\n  metaSchema,\n} from \"fumadocs-mdx/config\";\n\n// You can customise Zod schemas for frontmatter and `meta.json` here\n// see https://fumadocs.vercel.app/docs/mdx/collections#define-docs\nexport const docs = defineDocs({\n  docs: {\n    schema: frontmatterSchema,\n  },\n  meta: {\n    schema: metaSchema,\n  },\n});\n\nexport default defineConfig({\n  mdxOptions: {\n    // MDX options\n  },\n});\n"
  },
  {
    "path": "src/app/api/search/route.ts",
    "content": "import { source } from \"@/lib/source\";\nimport { createFromSource } from \"fumadocs-core/search/server\";\n\nexport const { GET } = createFromSource(source, {\n  // https://docs.orama.com/open-source/supported-languages\n  language: \"english\",\n});\n"
  },
  {
    "path": "src/app/community/page.tsx",
    "content": "\"use client\";\n\nimport { AspectRatio } from \"@/components/ui/aspect-ratio\";\nimport { Button } from \"@/components/ui/button\";\nimport { ExternalLink } from \"lucide-react\";\nimport Image from \"next/image\";\nimport Link from \"next/link\";\nimport { motion } from \"framer-motion\";\nimport { DISCORD_URL, GITHUB_URL } from \"@/data/meta\";\nimport { YOUTUBE_VIDEOS } from \"@/data/yt-videos\";\n\nexport default function Communitypage() {\n  return (\n    <>\n      <section>\n        <div className=\"wrapper grid py-20 gap-8 lg:grid-cols-2\">\n          <div className=\"space-y-8 grid justify-items-center\">\n            <motion.div\n              whileHover={{ rotate: \"10deg\", scale: 1.1 }}\n              whileTap={{ scale: 0.9 }}\n              transition={{ type: \"spring\" }}\n            >\n              <Image\n                src=\"/assets/icons/github.svg\"\n                alt=\"GitHub\"\n                width={150}\n                height={150}\n                className=\"shadow-[0_0_5rem_1rem_hsl(225,22%,15%)] rounded-[3rem]\"\n              />\n            </motion.div>\n            <h2 className=\"text-3xl font-bold text-center\">\n              QuickSnip is Open-Source\n            </h2>\n            <Button size=\"lg\" asChild>\n              <Link href={GITHUB_URL} target=\"_blank\" rel=\"noopener noreferrer\">\n                See the code <ExternalLink />\n              </Link>\n            </Button>\n          </div>\n          <div className=\"space-y-8 grid justify-items-center\">\n            <motion.div\n              whileHover={{ rotate: \"-10deg\", scale: 1.1 }}\n              whileTap={{ scale: 0.9 }}\n              transition={{ type: \"spring\" }}\n            >\n              <Image\n                src=\"/assets/icons/discord.svg\"\n                alt=\"Discord\"\n                width={150}\n                height={150}\n                className=\"shadow-[0_0_5rem_1rem_hsl(235,86%,65%,0.5)] rounded-[3rem]\"\n              />\n            </motion.div>\n            <h2 className=\"text-3xl font-bold text-center\">\n              Join our Discord Community\n            </h2>\n            <Button size=\"lg\" asChild>\n              <Link\n                href={DISCORD_URL}\n                target=\"_blank\"\n                rel=\"noopener noreferrer\"\n              >\n                Take me there <ExternalLink />\n              </Link>\n            </Button>\n          </div>\n        </div>\n      </section>\n\n      <section>\n        <div className=\"wrapper pt-8 pb-16 space-y-8\">\n          <h2 className=\"text-xl text-muted-foreground font-bold text-center\">\n            Videos from Technophile\n          </h2>\n          <ul className=\"grid gap-4 sm:grid-cols-2 auto-rows-fr lg:grid-cols-3\">\n            {YOUTUBE_VIDEOS.map((video) => (\n              <li key={video.id}>\n                <Link\n                  href={`https://www.youtube.com/watch?v=${video.id}`}\n                  className=\"block space-y-2\"\n                >\n                  <AspectRatio\n                    ratio={16 / 9}\n                    className=\"bg-muted rounded-lg border-4 border-secondary overflow-hidden\"\n                  >\n                    <Image\n                      src={`https://img.youtube.com/vi/${video.id}/maxresdefault.jpg`}\n                      alt={video.title}\n                      fill\n                      className=\"h-full w-full object-cover\"\n                    />\n                  </AspectRatio>\n                  <h3 className=\"text-lg font-semibold\">{video.title}</h3>\n                </Link>\n              </li>\n            ))}\n          </ul>\n          <Button\n            size=\"lg\"\n            variant=\"secondary\"\n            className=\"flex w-fit mx-auto\"\n            asChild\n          >\n            <Link\n              href=\"https://www.youtube.com/@technoph1le\"\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n            >\n              Let me subscribe <ExternalLink />\n            </Link>\n          </Button>\n        </div>\n      </section>\n    </>\n  );\n}\n\n/**\n * Fetch `CONTRIBUTING.md`\n */\n"
  },
  {
    "path": "src/app/contributing/page.tsx",
    "content": "import fs from \"fs\";\nimport path from \"path\";\nimport remarkGfm from \"remark-gfm\";\nimport Markdown from \"react-markdown\";\nimport { Prism as SyntaxHighlighter } from \"react-syntax-highlighter\";\nimport { oneDark } from \"react-syntax-highlighter/dist/esm/styles/prism\";\n\nexport default function ContributingPage() {\n  const filePath = path.join(process.cwd(), \"CONTRIBUTING.md\");\n  const fileContent = fs.readFileSync(filePath, \"utf-8\");\n\n  return (\n    <article className=\"wrapper-xs py-8 lg:py-16 prose dark:prose-invert\">\n      <Markdown\n        remarkPlugins={[remarkGfm]}\n        components={{\n          code(props) {\n            const { children, className, ...rest } = props;\n            const match = /language-(\\w+)/.exec(className || \"\");\n            return match ? (\n              <SyntaxHighlighter language={match[1]} style={oneDark}>\n                {String(children).replace(/\\n$/, \"\")}\n              </SyntaxHighlighter>\n            ) : (\n              <code {...rest} className={className}>\n                {children}\n              </code>\n            );\n          },\n        }}\n      >\n        {fileContent}\n      </Markdown>\n    </article>\n  );\n}\n"
  },
  {
    "path": "src/app/extensions/page.tsx",
    "content": "import ExtensionItem, {\n  NewExtensionItem,\n} from \"@/components/ui/extension-item\";\nimport { EXTENSIONS } from \"@/data/extensions\";\n\nexport default function ExtensionsPage() {\n  return (\n    <section>\n      <div className=\"wrapper py-8 space-y-8\">\n        <h2 className=\"text-3xl font-bold text-center\">Extensions</h2>\n        <ul className=\"grid gap-4 sm:grid-cols-2 auto-rows-fr lg:grid-cols-3\">\n          {EXTENSIONS.map((extension) => (\n            <ExtensionItem key={extension.name} extension={extension} />\n          ))}\n          <NewExtensionItem />\n        </ul>\n      </div>\n    </section>\n  );\n}\n\n/**\n * 📦 Official Extensions\n\n    VS Code Extension (coming soon)\n\n    QuickSnip CLI (optional later)\n\n🔌 Community Extensions\n\n    ✅ Raycast Extension\n\n    🔜 Vim Plugin\n\n    ⌨️ Obsidian Snippet Sync\n\n    💡 (Form to submit your own tool)\n\n📚 How to Build One\n\n    Short guide: “Build your own extension using QuickSnip API”\n\n    Link to API docs or SDK\n\n    Example template repo\n */\n"
  },
  {
    "path": "src/app/globals.css",
    "content": "@import \"tailwindcss\";\n@import \"tw-animate-css\";\n@import \"fumadocs-ui/css/neutral.css\";\n@import \"fumadocs-ui/css/preset.css\";\n\n@custom-variant dark (&:is(.dark *));\n\n@theme inline {\n  --color-background: var(--background);\n  --color-foreground: var(--foreground);\n  --font-sans: var(--font-geist-sans);\n  --font-mono: var(--font-geist-mono);\n  --color-sidebar-ring: var(--sidebar-ring);\n  --color-sidebar-border: var(--sidebar-border);\n  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);\n  --color-sidebar-accent: var(--sidebar-accent);\n  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);\n  --color-sidebar-primary: var(--sidebar-primary);\n  --color-sidebar-foreground: var(--sidebar-foreground);\n  --color-sidebar: var(--sidebar);\n  --color-chart-5: var(--chart-5);\n  --color-chart-4: var(--chart-4);\n  --color-chart-3: var(--chart-3);\n  --color-chart-2: var(--chart-2);\n  --color-chart-1: var(--chart-1);\n  --color-ring: var(--ring);\n  --color-input: var(--input);\n  --color-border: var(--border);\n  --color-destructive: var(--destructive);\n  --color-accent-foreground: var(--accent-foreground);\n  --color-accent: var(--accent);\n  --color-muted-foreground: var(--muted-foreground);\n  --color-muted: var(--muted);\n  --color-secondary-foreground: var(--secondary-foreground);\n  --color-secondary: var(--secondary);\n  --color-primary-foreground: var(--primary-foreground);\n  --color-primary: var(--primary);\n  --color-popover-foreground: var(--popover-foreground);\n  --color-popover: var(--popover);\n  --color-card-foreground: var(--card-foreground);\n  --color-card: var(--card);\n  --radius-sm: calc(var(--radius) - 4px);\n  --radius-md: calc(var(--radius) - 2px);\n  --radius-lg: var(--radius);\n  --radius-xl: calc(var(--radius) + 4px);\n}\n\n:root {\n  --radius: 0.625rem;\n  --background: hsl(0, 0%, 95%);\n  --foreground: hsl(0, 0%, 16%);\n  --card: hsl(0, 0%, 90%);\n  --card-foreground: hsl(0, 0%, 24%);\n  --popover: hsl(0, 0%, 90%);\n  --popover-foreground: hsl(0, 0%, 24%);\n  --primary: hsl(0, 0%, 95%);\n  --primary-foreground: hsl(0, 0%, 11%);\n  --secondary: hsl(0, 0%, 90%);\n  --secondary-foreground: hsl(0, 0%, 16%);\n  --muted: hsl(0, 0%, 80%);\n  --muted-foreground: hsl(0, 0%, 24%);\n  --accent: hsl(181, 100%, 22%);\n  --accent-foreground: hsl(0, 0%, 11%);\n  --destructive: oklch(0.577 0.245 27.325);\n  --border: oklch(0.922 0 0);\n  --input: oklch(0.922 0 0);\n  --ring: oklch(0.708 0 0);\n  --chart-1: oklch(0.646 0.222 41.116);\n  --chart-2: oklch(0.6 0.118 184.704);\n  --chart-3: oklch(0.398 0.07 227.392);\n  --chart-4: oklch(0.828 0.189 84.429);\n  --chart-5: oklch(0.769 0.188 70.08);\n  --sidebar: oklch(0.985 0 0);\n  --sidebar-foreground: oklch(0.145 0 0);\n  --sidebar-primary: oklch(0.205 0 0);\n  --sidebar-primary-foreground: oklch(0.985 0 0);\n  --sidebar-accent: oklch(0.97 0 0);\n  --sidebar-accent-foreground: oklch(0.205 0 0);\n  --sidebar-border: oklch(0.922 0 0);\n  --sidebar-ring: oklch(0.708 0 0);\n\n  --fd-layout-width: 90rem;\n  --fd-sidebar-margin: 0 2rem;\n  --fd-banner-height: 4rem;\n  /* --fd-nav-height: 4rem; */\n\n  --header-height: 4rem;\n  --footer-height: 4rem;\n}\n\n.dark {\n  --background: hsl(0, 0%, 11%);\n  --foreground: hsl(0, 0%, 90%);\n  --card: hsl(0, 0%, 16%);\n  --card-foreground: hsl(0, 0%, 80%);\n  --popover: hsl(0, 0%, 16%);\n  --popover-foreground: hsl(0, 0%, 80%);\n  --primary: hsl(0, 0%, 11%);\n  --primary-foreground: hsl(0, 0%, 90%);\n  --secondary: hsl(0, 0%, 16%);\n  --secondary-foreground: hsl(0, 0%, 80%);\n  --muted: hsl(0, 0%, 24%);\n  --muted-foreground: hsl(0, 0%, 70%);\n  --accent: hsl(181, 100%, 36%);\n  --accent-foreground: hsl(0, 0%, 11%);\n  --destructive: oklch(0.704 0.191 22.216);\n  --border: oklch(1 0 0 / 10%);\n  --input: oklch(1 0 0 / 15%);\n  --ring: oklch(0.556 0 0);\n  --chart-1: oklch(0.488 0.243 264.376);\n  --chart-2: oklch(0.696 0.17 162.48);\n  --chart-3: oklch(0.769 0.188 70.08);\n  --chart-4: oklch(0.627 0.265 303.9);\n  --chart-5: oklch(0.645 0.246 16.439);\n  --sidebar: hsl(0, 0%, 11%);\n  --sidebar-foreground: hsl(0, 0%, 90%);\n  --sidebar-primary: oklch(0.488 0.243 264.376);\n  --sidebar-primary-foreground: oklch(0.985 0 0);\n  --sidebar-accent: oklch(0.269 0 0);\n  --sidebar-accent-foreground: oklch(0.985 0 0);\n  --sidebar-border: oklch(1 0 0 / 10%);\n  --sidebar-ring: oklch(0.556 0 0);\n}\n\n@layer base {\n  * {\n    @apply border-border outline-ring/50;\n  }\n  body {\n    @apply bg-background text-foreground;\n  }\n}\n\n@layer utilities {\n  .wrapper {\n    @apply max-w-7xl w-full mx-auto px-4;\n  }\n\n  .wrapper-sm {\n    @apply max-w-6xl w-full mx-auto px-4;\n  }\n\n  .wrapper-xs {\n    @apply max-w-4xl w-full mx-auto px-4;\n  }\n\n  .wrapper-2xs {\n    @apply max-w-2xl w-full mx-auto px-4;\n  }\n\n  .wrapper-lg {\n    @apply max-w-[90rem] w-full mx-auto px-4;\n  }\n}\n\n/* #nd-docs-layout {\n  padding: 0 !important;\n}\n\n#nd-page {\n  border: 1px solid green;\n} */\n\n#nd-sidebar {\n  background: var(--background);\n  bottom: var(--footer-height);\n  position: absolute;\n}\n"
  },
  {
    "path": "src/app/guide/[[...slug]]/page.tsx",
    "content": "import { source } from \"@/lib/source\";\nimport {\n  DocsBody,\n  DocsDescription,\n  DocsPage,\n  DocsTitle,\n} from \"fumadocs-ui/page\";\nimport { getGithubLastEdit } from \"fumadocs-core/server\";\nimport { notFound } from \"next/navigation\";\nimport { getMDXComponents } from \"../../../../mdx-components\";\n\nexport default async function Page(props: {\n  params: Promise<{ slug?: string[] }>;\n}) {\n  const params = await props.params;\n\n  const page = source.getPage(params.slug);\n  if (!page) notFound();\n\n  const MDX = page.data.body;\n  const time = await getGithubLastEdit({\n    owner: \"fuma-nama\",\n    repo: \"fumadocs\",\n    path: `content/guide/${page.path}`,\n  });\n\n  return (\n    <DocsPage\n      editOnGithub={{\n        owner: \"quicksnip-dev\",\n        repo: \"quicksnip\",\n        path: `content/guide/${page.path}`,\n      }}\n      lastUpdate={time ? new Date(time) : undefined}\n      full={page.data.full}\n    >\n      <DocsTitle>{page.data.title}</DocsTitle>\n      <DocsDescription>{page.data.description}</DocsDescription>\n      <DocsBody>\n        <MDX components={getMDXComponents()} />\n      </DocsBody>\n    </DocsPage>\n  );\n}\n\nexport async function generateStaticParams() {\n  return source.generateParams();\n}\n\nexport async function generateMetadata(props: {\n  params: Promise<{ slug?: string[] }>;\n}) {\n  const params = await props.params;\n  const page = source.getPage(params.slug);\n  if (!page) notFound();\n\n  return {\n    title: page.data.title,\n    description: page.data.description,\n  };\n}\n"
  },
  {
    "path": "src/app/guide/layout.tsx",
    "content": "import { source } from \"@/lib/source\";\nimport { DocsLayout } from \"fumadocs-ui/layouts/docs\";\nimport type { ReactNode } from \"react\";\nimport { baseOptions } from \"@/app/layout.config\";\n\nexport default function Layout({ children }: { children: ReactNode }) {\n  return (\n    <DocsLayout\n      tree={source.pageTree}\n      {...baseOptions}\n      themeSwitch={{ enabled: false }}\n    >\n      {children}\n    </DocsLayout>\n  );\n}\n"
  },
  {
    "path": "src/app/layout.config.tsx",
    "content": "import { BaseLayoutProps } from \"fumadocs-ui/layouts/shared\";\n\nexport const baseOptions: BaseLayoutProps = {\n  // githubUrl: \"https://github.com/quicksnip-dev/quicksnip\",\n  nav: {\n    enabled: false,\n  },\n};\n"
  },
  {
    "path": "src/app/layout.tsx",
    "content": "import type { Metadata } from \"next\";\nimport { Geist, Geist_Mono } from \"next/font/google\";\nimport { RootProvider } from \"fumadocs-ui/provider\";\nimport \"./globals.css\";\nimport Header from \"@/components/layouts/header\";\nimport Footer from \"@/components/layouts/footer\";\n\nconst geistSans = Geist({\n  variable: \"--font-geist-sans\",\n  subsets: [\"latin\"],\n});\n\nconst geistMono = Geist_Mono({\n  variable: \"--font-geist-mono\",\n  subsets: [\"latin\"],\n});\n\nexport const metadata: Metadata = {\n  title: \"QuickSnip\",\n  description: \"Find code snippets in seconds.\",\n};\n\nexport default function RootLayout({\n  children,\n}: Readonly<{\n  children: React.ReactNode;\n}>) {\n  return (\n    <html lang=\"en\" dir=\"ltr\" suppressHydrationWarning>\n      <body\n        className={`${geistSans.variable} ${geistMono.variable} grid grid-rows-[auto_1fr_auto] min-h-screen antialiased bg-background text-foreground dark`}\n      >\n        <Header />\n        <RootProvider>{children}</RootProvider>\n        <Footer />\n      </body>\n    </html>\n  );\n}\n"
  },
  {
    "path": "src/app/page.tsx",
    "content": "import Features from \"@/components/layouts/features\";\nimport Hero from \"@/components/layouts/hero\";\nimport AvailableFor from \"@/components/layouts/available-for\";\nimport Sponsor from \"@/components/layouts/sponsor\";\n\nexport default function Home() {\n  return (\n    <>\n      <Hero />\n      <Features />\n      <AvailableFor />\n      <Sponsor />\n    </>\n  );\n}\n"
  },
  {
    "path": "src/app/snippets/[category]/[snippet]/page.tsx",
    "content": "\"use client\";\n\nimport { use } from \"react\";\n\nimport { useRouter } from \"next/navigation\";\nimport Link from \"next/link\";\n\nimport { Loader, XIcon } from \"lucide-react\";\n\nimport { FullSnippet } from \"@/types\";\nimport { useFetch } from \"@/hooks/use-fetch\";\nimport { Button } from \"@/components/ui/button\";\nimport CodePreview from \"@/components/layouts/code-preview\";\nimport {\n  Card,\n  CardContent,\n  CardFooter,\n  CardHeader,\n} from \"@/components/ui/card\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/components/ui/avatar\";\n\ninterface Props {\n  params: Promise<{ category: string; snippet: string }>;\n}\n\nexport default function SnippetPage({ params }: Props) {\n  const router = useRouter();\n  const { category, snippet } = use(params);\n  const { data, loading } = useFetch<FullSnippet>(\n    `/data/snippets/${category}/${snippet}.json`\n  );\n\n  const handleCloseModal = () => {\n    /**\n     * If a snippet is visited directly from URL,\n     * it won't have history to go back to.\n     * Thus, fallback to `/snippets/` page.\n     */\n    if (window.history.length > 2) router.back();\n    else router.push(\"/snippets\");\n  };\n\n  if (loading) return <Loader />;\n  if (!data) return null;\n\n  return (\n    <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\">\n      <Card className=\"wrapper-xs\">\n        <CardHeader className=\"flex items-center justify-between gap-4\">\n          <h2 className=\"text-2xl font-bold\">{data.title}</h2>\n          <Button onClick={handleCloseModal} size=\"icon\">\n            <XIcon />\n          </Button>\n        </CardHeader>\n        <CardContent className=\"space-y-4\">\n          <p>{data.description}</p>\n          <CodePreview languages={data.languages} snippets={data.snippets} />\n        </CardContent>\n        <CardFooter className=\"grid gap-4\">\n          <div className=\"flex items-center gap-4\">\n            <p className=\"font-bold\">Contributors: </p>\n            <div className=\"*:data-[slot=avatar]:ring-background flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:grayscale\">\n              {data.contributors.map((contributor) => (\n                <Avatar\n                  key={contributor}\n                  className=\"w-8 h-8\"\n                  title={`@${contributor}`}\n                >\n                  <AvatarImage\n                    src={`https://github.com/${contributor}.png`}\n                    alt={`@${contributor}`}\n                  />\n                  <AvatarFallback>{contributor.slice(0, 2)}</AvatarFallback>\n                </Avatar>\n              ))}\n            </div>\n          </div>\n          <ul className=\"flex items-center flex-wrap gap-2\">\n            {data.tags.map((tag) => (\n              <li key={tag}>\n                <Link\n                  className=\"border border-border font-semibold pt-1 pb-2 px-3 rounded-md leading-tight\"\n                  href={`/snippets/tags/${tag}`}\n                >\n                  {tag}\n                </Link>\n              </li>\n            ))}\n          </ul>\n        </CardFooter>\n      </Card>\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/app/snippets/[category]/page.tsx",
    "content": "\"use client\";\n\nimport SnippetList from \"@/components/layouts/snippet-list\";\nimport { unslugify } from \"@/lib/utils\";\nimport { useSnippetsStore } from \"@/store/useSnippetsStore\";\nimport { use } from \"react\";\n\ninterface Props {\n  params: Promise<{ category: string }>;\n}\n\nexport default function Categories({ params }: Props) {\n  const { snippets } = useSnippetsStore();\n  const { category } = use(params);\n\n  const filteredSnippets = snippets.filter(\n    (snippet) => snippet.category === category\n  );\n\n  return (\n    <section className=\"space-y-4\">\n      <h2 className=\"text-2xl font-bold\">{unslugify(category)}</h2>\n      <SnippetList snippets={filteredSnippets} />\n    </section>\n  );\n}\n"
  },
  {
    "path": "src/app/snippets/layout.tsx",
    "content": "import SnippetHeader from \"@/components/layouts/snippet-header\";\nimport SnippetSidebar from \"@/components/layouts/snippet-sidebar\";\n\nimport { SidebarProvider } from \"@/components/ui/sidebar\";\n\nexport default function SnippetsLayout({\n  children,\n}: {\n  children: React.ReactNode;\n}) {\n  return (\n    <SidebarProvider>\n      <SnippetSidebar />\n      <main className=\"py-4 pl-4 space-y-4 w-full\">\n        <SnippetHeader />\n        {children}\n      </main>\n    </SidebarProvider>\n  );\n}\n"
  },
  {
    "path": "src/app/snippets/page.tsx",
    "content": "\"use client\";\n\nimport SnippetList from \"@/components/layouts/snippet-list\";\nimport { useSnippetsStore } from \"@/store/useSnippetsStore\";\nimport { useEffect } from \"react\";\n\nexport default function SnippetsPage() {\n  const { setSnippets, snippets } = useSnippetsStore();\n\n  useEffect(() => {\n    fetch(\"/data/snippets/all.json\")\n      .then((res) => res.json())\n      .then((data) => setSnippets(data));\n  }, [setSnippets]);\n\n  // This is for showing all the snippets\n  return <SnippetList snippets={snippets} />;\n}\n"
  },
  {
    "path": "src/components/layouts/available-for.tsx",
    "content": "import Link from \"next/link\";\n\nimport { EXTENSIONS } from \"@/data/extensions\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/components/ui/avatar\";\n\nexport default function AvailableFor() {\n  return (\n    <section>\n      <div className=\"wrapper py-8 grid justify-items-center gap-6\">\n        <h2 className=\"text-center text-2xl\">Available for:</h2>\n        <div className=\"flex gap-4 flex-wrap\">\n          {EXTENSIONS.map((extension) => (\n            <Link key={extension.name} href={extension.guide_url}>\n              <Avatar className=\"size-14 bg-secondary p-3 hover:bg-muted\">\n                <AvatarImage src={extension.icon} alt={extension.name} />\n                <AvatarFallback>{extension.name.slice(0, 2)}</AvatarFallback>\n              </Avatar>\n            </Link>\n          ))}\n        </div>\n        <Button variant=\"secondary\" size=\"lg\" asChild>\n          <Link href=\"/extensions\">View more</Link>\n        </Button>\n      </div>\n    </section>\n  );\n}\n"
  },
  {
    "path": "src/components/layouts/code-preview.tsx",
    "content": "import { Prism as SyntaxHighlighter } from \"react-syntax-highlighter\";\nimport { oneDark } from \"react-syntax-highlighter/dist/esm/styles/prism\";\n\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"@/components/ui/tabs\";\n\n// import CopyToClipboard from \"./CopyToClipboard\";\n// import CopyURLButton from \"./CopyURLButton\";\n\ntype Props = {\n  languages: string[];\n  snippets: Record<string, string>;\n};\n\nconst CodePreview = ({ languages, snippets }: Props) => {\n  return (\n    <div className=\"w-full\">\n      <Tabs defaultValue={languages[0]}>\n        <TabsList>\n          {languages.map((language) => (\n            <TabsTrigger key={language} value={language}>\n              {language}\n            </TabsTrigger>\n          ))}\n        </TabsList>\n        {Object.keys(snippets).map((language) => {\n          const code = snippets[language as keyof typeof snippets];\n\n          return (\n            <TabsContent value={language} key={language}>\n              <SyntaxHighlighter\n                language={language}\n                style={oneDark}\n                wrapLines={true}\n                customStyle={{ margin: \"0\", maxHeight: \"22rem\" }}\n              >\n                {code}\n              </SyntaxHighlighter>\n            </TabsContent>\n          );\n        })}\n      </Tabs>\n    </div>\n  );\n};\n\nexport default CodePreview;\n"
  },
  {
    "path": "src/components/layouts/features.tsx",
    "content": "import {\n  Code,\n  Terminal,\n  Paintbrush,\n  Rocket,\n  Book,\n  PlusCircle,\n} from \"lucide-react\";\nimport { Card, CardContent, CardHeader } from \"../ui/card\";\n\nconst features = [\n  {\n    icon: <Code className=\"h-6 w-6\" />,\n    title: \"Developer-Friendly\",\n    desc: \"Tailored for developers to create and iterate fast, with minimal overhead and maximum flexibility.\",\n  },\n  {\n    icon: <Terminal className=\"h-6 w-6\" />,\n    title: \"CLI Support\",\n    desc: \"Command-line interface support for seamless development and workflow integration.\",\n  },\n  {\n    icon: <Paintbrush className=\"h-6 w-6\" />,\n    title: \"Easily Customizable\",\n    desc: \"Every block is built to be editable. From layout to logic, style to structure—make it your own.\",\n  },\n  {\n    icon: <Rocket className=\"h-6 w-6\" />,\n    title: \"v0 Support\",\n    desc: \"Launch fast with confidence. Perfect for MVPs, prototypes, and weekend projects.\",\n  },\n  {\n    icon: <Book className=\"h-6 w-6\" />,\n    title: \"Full Documentation\",\n    desc: \"Comprehensive documentation to understand every feature and maximize your development experience.\",\n  },\n  {\n    icon: <PlusCircle className=\"h-6 w-6\" />,\n    title: \"Contribute Yours\",\n    desc: \"Add your own blocks to the library and become part of the MVPBlocks community.\",\n  },\n];\nexport default function Features() {\n  return (\n    <section className=\"relative py-4 my-6\">\n      <div className=\"wrapper\">\n        <ul className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n          {features.map((item, idx) => (\n            <Card key={idx}>\n              <CardHeader>\n                <div className=\"text-accent w-fit transform-gpu rounded-full bg-background p-4\">\n                  {item.icon}\n                </div>\n              </CardHeader>\n              <CardContent>\n                <h4 className=\"text-lg font-bold\">{item.title}</h4>\n                <p className=\"text-muted-foreground\">{item.desc}</p>\n              </CardContent>\n            </Card>\n          ))}\n        </ul>\n      </div>\n    </section>\n  );\n}\n"
  },
  {
    "path": "src/components/layouts/footer.tsx",
    "content": "import { ExternalLink } from \"lucide-react\";\nimport Link from \"next/link\";\n\nconst NAV_ITEMS = [\n  { name: \"Contribute\", url: \"/contributing\", external: false },\n  {\n    name: \"Changelog\",\n    url: \"https://github.com/quicksnip-dev/quicksnip/releases\",\n    external: true,\n  },\n  {\n    name: \"Sponsor\",\n    url: \"https://ko-fi.com/technoph1le\",\n    external: true,\n  },\n  {\n    name: \"GitHub\",\n    url: \"https://github.com/quicksnip-dev/quicksnip\",\n    external: true,\n  },\n  {\n    name: \"Discord\",\n    url: \"https://discord.com/invite/Nm5K46yUy5\",\n    external: true,\n  },\n];\n\nconst Footer = () => {\n  return (\n    <footer className=\"h-(--footer-height) border-t border-secondary text-secondary-foreground\">\n      <div className=\"wrapper-lg py-8 grid gap-8 md:grid-cols-[1fr_auto]\">\n        <p>\n          Released under the{\" \"}\n          <Link\n            href=\"https://github.com/quicksnip-dev/quicksnip/LICENSE\"\n            className=\"text-primary-foreground font-semibold\"\n          >\n            MIT License.\n          </Link>\n          <br />\n          Copyright © 2025\n        </p>\n        <ul className=\"flex md:items-center gap-4 md:gap-8 flex-col md:flex-row flex-wrap\">\n          {NAV_ITEMS.map((item) => (\n            <li key={item.name}>\n              <Link\n                href={item.url}\n                target={item.external ? \"_blank\" : \"_self\"}\n                className=\"flex items-center gap-1 font-semibold\"\n              >\n                {item.name}\n                {item.external ? <ExternalLink size={14} /> : null}\n              </Link>\n            </li>\n          ))}\n        </ul>\n      </div>\n    </footer>\n  );\n};\n\nexport default Footer;\n"
  },
  {
    "path": "src/components/layouts/header.tsx",
    "content": "\"use client\";\n\nimport React, { useState, useEffect } from \"react\";\nimport { motion, AnimatePresence, easeInOut } from \"framer-motion\";\nimport { Menu, X } from \"lucide-react\";\n\nimport Link from \"next/link\";\nimport Image from \"next/image\";\n\nimport Logo from \"@/components/ui/logo\";\nimport DarkModeSwitch from \"@/components/ui/dark-mode-switch\";\n\nimport { DISCORD_URL, GITHUB_URL } from \"@/data/meta\";\n\nconst NAV_ITEMS = [\n  { name: \"Snippets\", url: \"/snippets\" },\n  { name: \"Guide\", url: \"/guide\" },\n  { name: \"Extensions\", url: \"/extensions\" },\n  { name: \"Community\", url: \"/community\" },\n  { name: \"Contributing\", url: \"/contributing\" },\n];\n\nconst SOCIAL_ITEMS = [\n  {\n    icon: \"/assets/icons/github.svg\",\n    name: \"GitHub\",\n    url: GITHUB_URL,\n  },\n  {\n    icon: \"/assets/icons/discord.svg\",\n    name: \"Discord\",\n    url: DISCORD_URL,\n  },\n];\n\nexport default function Header() {\n  const [isScrolled, setIsScrolled] = useState(false);\n  const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);\n\n  useEffect(() => {\n    const handleScroll = () => {\n      setIsScrolled(window.scrollY > 10);\n    };\n    window.addEventListener(\"scroll\", handleScroll);\n    return () => window.removeEventListener(\"scroll\", handleScroll);\n  }, []);\n\n  const itemVariants = {\n    hidden: { opacity: 0, y: -10 },\n    visible: { opacity: 1, y: 0 },\n  };\n\n  const mobileMenuVariants = {\n    closed: {\n      opacity: 0,\n      x: \"100%\",\n      transition: {\n        duration: 0.3,\n        ease: easeInOut,\n      },\n    },\n    open: {\n      opacity: 1,\n      x: 0,\n      transition: {\n        duration: 0.3,\n        ease: easeInOut,\n        staggerChildren: 0.1,\n      },\n    },\n  };\n\n  const mobileItemVariants = {\n    closed: { opacity: 0, x: 20 },\n    open: { opacity: 1, x: 0 },\n  };\n\n  return (\n    <>\n      <div className=\"h-16 w-screen\" />\n      <motion.header\n        className={`fixed top-0 right-0 left-0 z-50 transition-all border-b border-border/50 duration-500 ${\n          isScrolled\n            ? \"bg-background/80 shadow-sm backdrop-blur-md\"\n            : \"bg-transparent\"\n        }`}\n      >\n        <div className=\"wrapper-lg\">\n          <div className=\"flex h-16 items-center justify-between\">\n            <Logo />\n\n            <div className=\"flex gap-4 items-center justify-between\">\n              <nav className=\"hidden items-center gap-8 space-x-1 lg:flex\">\n                {NAV_ITEMS.map((item) => (\n                  <motion.div\n                    key={item.name}\n                    variants={itemVariants}\n                    className=\"relative\"\n                  >\n                    <Link\n                      href={item.url}\n                      className=\"text-foreground/80 hover:text-accent font-medium transition-colors duration-200\"\n                    >\n                      <span>{item.name}</span>\n                    </Link>\n                  </motion.div>\n                ))}\n              </nav>\n\n              <hr className=\"border-0 w-0.5 h-8 bg-secondary\" />\n\n              <DarkModeSwitch />\n\n              <hr className=\"border-0 w-0.5 h-8 bg-secondary\" />\n\n              <motion.div\n                className=\"hidden items-center space-x-3 lg:flex\"\n                variants={itemVariants}\n              >\n                {SOCIAL_ITEMS.map((item) => (\n                  <Link\n                    key={item.name}\n                    href={item.url}\n                    title={item.name}\n                    className=\"\"\n                  >\n                    <Image\n                      src={item.icon}\n                      alt={item.name}\n                      width={24}\n                      height={24}\n                    />\n                  </Link>\n                ))}\n              </motion.div>\n\n              <motion.button\n                className=\"text-foreground hover:bg-muted rounded-lg p-2 transition-colors duration-200 lg:hidden\"\n                onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}\n                variants={itemVariants}\n                whileTap={{ scale: 0.95 }}\n              >\n                {isMobileMenuOpen ? (\n                  <X className=\"h-6 w-6\" />\n                ) : (\n                  <Menu className=\"h-6 w-6\" />\n                )}\n              </motion.button>\n            </div>\n          </div>\n        </div>\n      </motion.header>\n\n      {/* Mobile menu */}\n      <AnimatePresence>\n        {isMobileMenuOpen && (\n          <>\n            <motion.div\n              className=\"fixed inset-0 z-40 bg-black/20 backdrop-blur-sm lg:hidden\"\n              initial={{ opacity: 0 }}\n              animate={{ opacity: 1 }}\n              exit={{ opacity: 0 }}\n              onClick={() => setIsMobileMenuOpen(false)}\n            />\n            <motion.div\n              className=\"border-border bg-background fixed top-16 right-4 z-50 w-80 overflow-hidden rounded-2xl border shadow-2xl lg:hidden\"\n              variants={mobileMenuVariants}\n              initial=\"closed\"\n              animate=\"open\"\n              exit=\"closed\"\n            >\n              <div className=\"space-y-6 p-6\">\n                <div className=\"space-y-1\">\n                  {NAV_ITEMS.map((item) => (\n                    <motion.div key={item.name} variants={mobileItemVariants}>\n                      <Link\n                        href={item.url}\n                        className=\"text-foreground hover:bg-muted block rounded-lg px-4 py-3 font-medium transition-colors duration-200\"\n                        onClick={() => setIsMobileMenuOpen(false)}\n                      >\n                        {item.name}\n                      </Link>\n                    </motion.div>\n                  ))}\n                </div>\n\n                <motion.div\n                  className=\"border-border space-y-3 border-t pt-6\"\n                  variants={mobileItemVariants}\n                >\n                  <Link\n                    href=\"/login\"\n                    className=\"text-foreground hover:bg-muted block w-full rounded-lg py-3 text-center font-medium transition-colors duration-200\"\n                    onClick={() => setIsMobileMenuOpen(false)}\n                  >\n                    Sign In\n                  </Link>\n                  <Link\n                    href=\"/signup\"\n                    className=\"bg-foreground text-background hover:bg-foreground/90 block w-full rounded-lg py-3 text-center font-medium transition-all duration-200\"\n                    onClick={() => setIsMobileMenuOpen(false)}\n                  >\n                    Get Started\n                  </Link>\n                </motion.div>\n              </div>\n            </motion.div>\n          </>\n        )}\n      </AnimatePresence>\n    </>\n  );\n}\n"
  },
  {
    "path": "src/components/layouts/hero.tsx",
    "content": "import Link from \"next/link\";\nimport { Button } from \"../ui/button\";\nimport { GITHUB_URL } from \"@/data/meta\";\n\nconst Hero = () => {\n  return (\n    <section>\n      <div className=\"wrapper grid md:grid-cols-2\">\n        <article className=\"space-y-6 py-12\">\n          <Link\n            className=\"block bg-secondary px-4 py-2 rounded-md w-fit text-lg font-semibold hover:bg-muted transition-colors duration-200 leading-none\"\n            href=\"https://github.com/quicksnip-dev/quicksnip\"\n          >\n            v2.3.1\n          </Link>\n          <h1 className=\"text-4xl lg:text-7xl font-bold\">\n            A collection of <span className=\"text-accent\">&lt;code&gt;</span>{\" \"}\n            snippets\n          </h1>\n          <p className=\"text-2xl font-semibold text-muted-foreground\">\n            Made by the community.\n          </p>\n          <div className=\"flex flex-wrap gap-2\">\n            <Button asChild size=\"lg\" className=\" rounded-full\">\n              <Link href=\"/snippets\">View all snippets</Link>\n            </Button>\n            <Button\n              asChild\n              size=\"lg\"\n              variant=\"secondary\"\n              className=\" rounded-full\"\n            >\n              <Link href=\"/snippets\">Get Started</Link>\n            </Button>\n            <Button\n              asChild\n              size=\"lg\"\n              variant=\"secondary\"\n              className=\" rounded-full\"\n            >\n              <Link href={GITHUB_URL} target=\"_blank\" rel=\"noopener noreferrer\">\n                GitHub\n              </Link>\n            </Button>\n          </div>\n        </article>\n        <div className=\"p-8\">\n          <div className=\"w-full h-full bg-secondary rounded-2xl border-2 border-muted shadow-xl shadow-neutral-900\"></div>\n        </div>\n      </div>\n    </section>\n  );\n};\n\nexport default Hero;\n"
  },
  {
    "path": "src/components/layouts/snippet-header.tsx",
    "content": "import { Search } from \"lucide-react\";\n\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n} from \"@/components/ui/select\";\nimport { SidebarTrigger } from \"@/components/ui/sidebar\";\nimport {\n  InputGroup,\n  InputGroupAddon,\n  InputGroupInput,\n} from \"@/components/ui/input-group\";\n\nexport default function SnippetHeader() {\n  return (\n    <section className=\"grid gap-4 items-center md:grid-cols-[auto_1fr_auto_auto]\">\n      <SidebarTrigger />\n      <InputGroup>\n        <InputGroupInput placeholder=\"Search 875 snippets...\" />\n        <InputGroupAddon>\n          <Search size={16} />\n        </InputGroupAddon>\n      </InputGroup>\n      <Select>\n        <SelectTrigger className=\"w-[10rem]\">\n          <SelectValue placeholder=\"Sort by\" />\n        </SelectTrigger>\n        <SelectContent>\n          <SelectItem value=\"relevance\">Relevance</SelectItem>\n          <SelectItem value=\"popularity\">Popularity</SelectItem>\n          <SelectItem value=\"recent\">Most recent</SelectItem>\n          <SelectItem value=\"oldest\">The oldest</SelectItem>\n        </SelectContent>\n      </Select>\n      <Select>\n        <SelectTrigger className=\"w-[15rem]\">\n          <SelectValue placeholder=\"Filter by language\" />\n        </SelectTrigger>\n        <SelectContent>\n          <SelectItem value=\"js\">JavaScript</SelectItem>\n          <SelectItem value=\"py\">Python</SelectItem>\n          <SelectItem value=\"cplusplus\">C++</SelectItem>\n        </SelectContent>\n      </Select>\n    </section>\n  );\n}\n"
  },
  {
    "path": "src/components/layouts/snippet-list.tsx",
    "content": "import SnippetItem from \"../ui/snippet-item\";\n\nimport type { SnippetType } from \"@/types\";\n\ninterface SnippetListProps {\n  snippets: SnippetType[];\n}\n\nexport default function SnippetList({ snippets }: SnippetListProps) {\n  return (\n    <ul className=\"grid gap-4 sm:grid-cols-3 md:grid-cols-3\">\n      {snippets.map((snippet) => (\n        <SnippetItem key={snippet.id} snippet={snippet} />\n      ))}\n    </ul>\n  );\n}\n"
  },
  {
    "path": "src/components/layouts/snippet-sidebar.tsx",
    "content": "\"use client\";\n\nimport {\n  Sidebar,\n  SidebarContent,\n  SidebarGroup,\n  SidebarMenu,\n  SidebarMenuButton,\n  SidebarMenuItem,\n  SidebarMenuSub,\n  SidebarMenuSubButton,\n  SidebarMenuSubItem,\n  SidebarRail,\n} from \"@/components/ui/sidebar\";\nimport { unslugify } from \"@/lib/utils\";\nimport { useSnippetsStore } from \"@/store/useSnippetsStore\";\nimport Link from \"next/link\";\n\n// const categories = [\n//   {\n//     title: \"Routing\",\n//     url: \"/routing\",\n//     count: 23,\n//   },\n//   {\n//     title: \"Data Fetching\",\n//     url: \"#\",\n//     isActive: true,\n//     count: 86,\n//   },\n//   {\n//     title: \"Rendering\",\n//     url: \"#\",\n//     count: 34,\n//   },\n//   {\n//     title: \"Caching\",\n//     url: \"#\",\n//     count: 64,\n//   },\n//   {\n//     title: \"Styling\",\n//     url: \"#\",\n//     count: 98,\n//   },\n//   {\n//     title: \"Optimizing\",\n//     url: \"#\",\n//     count: 45,\n//   },\n//   {\n//     title: \"Configuring\",\n//     url: \"#\",\n//     count: 123,\n//   },\n//   {\n//     title: \"Testing\",\n//     url: \"#\",\n//     count: 56,\n//   },\n//   {\n//     title: \"Authentication\",\n//     url: \"#\",\n//     count: 87,\n//   },\n//   {\n//     title: \"Deploying\",\n//     url: \"#\",\n//     count: 234,\n//   },\n//   {\n//     title: \"Upgrading\",\n//     url: \"#\",\n//     count: 12,\n//   },\n//   {\n//     title: \"Examples\",\n//     url: \"#\",\n//     count: 56,\n//   },\n// ];\n\nexport default function SnippetSidebar() {\n  const { setCategory, categories } = useSnippetsStore();\n  const cats = categories();\n\n  return (\n    <Sidebar className=\"z-40 border-r border-border\">\n      <SidebarContent>\n        <SidebarGroup>\n          <SidebarMenu>\n            <SidebarMenuItem>\n              <SidebarMenuButton asChild>\n                <Link href=\"/snippets\" onClick={() => setCategory(\"All\")}>\n                  All\n                </Link>\n              </SidebarMenuButton>\n            </SidebarMenuItem>\n            <SidebarMenuItem>\n              <SidebarMenuButton asChild>\n                <Link href=\"/snippets/categories\">Categories</Link>\n              </SidebarMenuButton>\n              {cats.length ? (\n                <SidebarMenuSub>\n                  {cats.map((item) => (\n                    <SidebarMenuSubItem key={item.name}>\n                      <SidebarMenuSubButton\n                        className=\"py-4\"\n                        asChild\n                        isActive={item.name === \"current\"}\n                      >\n                        <Link\n                          href={`/snippets/${item.name}`}\n                          onClick={() => setCategory(item.name)}\n                          className=\"flex items-center justify-between\"\n                        >\n                          <span>{unslugify(item.name)}</span>\n                          <span className=\"text-muted-foreground\">\n                            {item.count}\n                          </span>\n                        </Link>\n                      </SidebarMenuSubButton>\n                    </SidebarMenuSubItem>\n                  ))}\n                </SidebarMenuSub>\n              ) : null}\n            </SidebarMenuItem>\n          </SidebarMenu>\n        </SidebarGroup>\n      </SidebarContent>\n      <SidebarRail />\n    </Sidebar>\n  );\n}\n"
  },
  {
    "path": "src/components/layouts/sponsor.tsx",
    "content": "import Image from \"next/image\";\nimport Link from \"next/link\";\nimport {\n  Card,\n  CardDescription,\n  CardFooter,\n  CardHeader,\n  CardTitle,\n} from \"@/components/ui/card\";\nimport { SPONSOR_URL } from \"@/data/meta\";\n\nexport default function Sponsor() {\n  return (\n    <div className=\"wrapper-xs pt-4 pb-12\">\n      <Card className=\"grid md:grid-cols-[1fr_auto]\">\n        <CardHeader>\n          <CardTitle className=\"text-xl font-bold\">\n            Support the project\n          </CardTitle>\n          <CardDescription>\n            And get a special <strong>💖 Prime Supporter</strong> role in our\n            Discord server.\n          </CardDescription>\n        </CardHeader>\n        <CardFooter>\n          <Link href={SPONSOR_URL} target=\"_blank\">\n            <Image\n              width={200}\n              height={80}\n              className=\"mx-auto\"\n              src=\"/assets/images/kofi-button.png\"\n              alt=\"Buy Me a Coffee at ko-fi.com\"\n            />\n          </Link>\n        </CardFooter>\n      </Card>\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/components/ui/accordion.tsx",
    "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\"\nimport { ChevronDownIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Accordion({\n  ...props\n}: React.ComponentProps<typeof AccordionPrimitive.Root>) {\n  return <AccordionPrimitive.Root data-slot=\"accordion\" {...props} />\n}\n\nfunction AccordionItem({\n  className,\n  ...props\n}: React.ComponentProps<typeof AccordionPrimitive.Item>) {\n  return (\n    <AccordionPrimitive.Item\n      data-slot=\"accordion-item\"\n      className={cn(\"border-b last:border-b-0\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction AccordionTrigger({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {\n  return (\n    <AccordionPrimitive.Header className=\"flex\">\n      <AccordionPrimitive.Trigger\n        data-slot=\"accordion-trigger\"\n        className={cn(\n          \"focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180\",\n          className\n        )}\n        {...props}\n      >\n        {children}\n        <ChevronDownIcon className=\"text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200\" />\n      </AccordionPrimitive.Trigger>\n    </AccordionPrimitive.Header>\n  )\n}\n\nfunction AccordionContent({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof AccordionPrimitive.Content>) {\n  return (\n    <AccordionPrimitive.Content\n      data-slot=\"accordion-content\"\n      className=\"data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm\"\n      {...props}\n    >\n      <div className={cn(\"pt-0 pb-4\", className)}>{children}</div>\n    </AccordionPrimitive.Content>\n  )\n}\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent }\n"
  },
  {
    "path": "src/components/ui/aspect-ratio.tsx",
    "content": "\"use client\"\n\nimport * as AspectRatioPrimitive from \"@radix-ui/react-aspect-ratio\"\n\nfunction AspectRatio({\n  ...props\n}: React.ComponentProps<typeof AspectRatioPrimitive.Root>) {\n  return <AspectRatioPrimitive.Root data-slot=\"aspect-ratio\" {...props} />\n}\n\nexport { AspectRatio }\n"
  },
  {
    "path": "src/components/ui/avatar.tsx",
    "content": "\"use client\";\n\nimport * as React from \"react\";\nimport * as AvatarPrimitive from \"@radix-ui/react-avatar\";\n\nimport { cn } from \"@/lib/utils\";\n\nfunction Avatar({\n  className,\n  ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Root>) {\n  return (\n    <AvatarPrimitive.Root\n      data-slot=\"avatar\"\n      className={cn(\n        \"relative flex shrink-0 overflow-hidden rounded-full\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction AvatarImage({\n  className,\n  ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Image>) {\n  return (\n    <AvatarPrimitive.Image\n      data-slot=\"avatar-image\"\n      className={cn(\"aspect-square size-full\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction AvatarFallback({\n  className,\n  ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {\n  return (\n    <AvatarPrimitive.Fallback\n      data-slot=\"avatar-fallback\"\n      className={cn(\n        \"bg-muted flex size-full items-center justify-center rounded-full\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nexport { Avatar, AvatarImage, AvatarFallback };\n"
  },
  {
    "path": "src/components/ui/button.tsx",
    "content": "import * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst buttonVariants = cva(\n  \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n  {\n    variants: {\n      variant: {\n        default:\n          \"bg-accent rounded-full font-semibold text-accent-foreground shadow-xs hover:bg-accent/70\",\n        destructive:\n          \"bg-destructive rounded-full text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n        outline:\n          \"border font-semibold rounded-full bg-background shadow-xs hover:bg-accent dark:bg-input/30 dark:border-input dark:hover:bg-secondary/50\",\n        secondary:\n          \"bg-secondary font-semibold rounded-full text-secondary-foreground shadow-xs hover:bg-secondary/80\",\n        ghost:\n          \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n        link: \"text-primary font-semibold underline-offset-4 hover:underline\",\n      },\n      size: {\n        default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n        sm: \"h-8 rounded-full gap-1.5 px-3 has-[>svg]:px-2.5\",\n        lg: \"h-10 rounded-full px-6 has-[>svg]:px-4\",\n        icon: \"size-9\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n);\n\nfunction Button({\n  className,\n  variant,\n  size,\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"button\"> &\n  VariantProps<typeof buttonVariants> & {\n    asChild?: boolean;\n  }) {\n  const Comp = asChild ? Slot : \"button\";\n\n  return (\n    <Comp\n      data-slot=\"button\"\n      className={cn(buttonVariants({ variant, size, className }))}\n      {...props}\n    />\n  );\n}\n\nexport { Button, buttonVariants };\n"
  },
  {
    "path": "src/components/ui/card.tsx",
    "content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Card({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card\"\n      className={cn(\n        \"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-header\"\n      className={cn(\n        \"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-title\"\n      className={cn(\"leading-none font-semibold\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-description\"\n      className={cn(\"text-muted-foreground text-sm\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-action\"\n      className={cn(\n        \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-content\"\n      className={cn(\"px-6\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"card-footer\"\n      className={cn(\"flex items-center px-6 [.border-t]:pt-6\", className)}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Card,\n  CardHeader,\n  CardFooter,\n  CardTitle,\n  CardAction,\n  CardDescription,\n  CardContent,\n}\n"
  },
  {
    "path": "src/components/ui/dark-mode-switch.tsx",
    "content": "\"use client\";\n\nimport { useId, useState } from \"react\";\nimport { MoonIcon, SunIcon } from \"lucide-react\";\n\nimport { Label } from \"@/components/ui/label\";\nimport { Switch } from \"@/components/ui/switch\";\n\nexport default function DarkModeSwitch() {\n  const id = useId();\n  const [checked, setChecked] = useState<boolean>(true);\n\n  return (\n    <div>\n      <div className=\"relative inline-grid h-7 grid-cols-[1fr_1fr] items-center text-sm font-medium\">\n        <Switch\n          id={id}\n          checked={checked}\n          onCheckedChange={setChecked}\n          className=\"peer data-[state=checked]:bg-input/50 data-[state=unchecked]:bg-input/50 absolute inset-0 h-[inherit] w-auto [&_span]:h-full [&_span]:w-1/2 [&_span]:transition-transform [&_span]:duration-300 [&_span]:ease-[cubic-bezier(0.16,1,0.3,1)] [&_span]:data-[state=checked]:translate-x-full [&_span]:data-[state=checked]:rtl:-translate-x-full\"\n        />\n        <span className=\"peer-data-[state=checked]:text-muted-foreground/70 pointer-events-none relative ms-0.5 flex min-w-7 items-center justify-center text-center\">\n          <MoonIcon size={16} aria-hidden=\"true\" />\n        </span>\n        <span className=\"peer-data-[state=unchecked]:text-muted-foreground/70 pointer-events-none relative me-0.5 flex min-w-7 items-center justify-center text-center\">\n          <SunIcon size={16} aria-hidden=\"true\" />\n        </span>\n      </div>\n      <Label htmlFor={id} className=\"sr-only\">\n        Dark mode toggle switch\n      </Label>\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/components/ui/extension-item.tsx",
    "content": "import Link from \"next/link\";\nimport Image from \"next/image\";\nimport type { ExtensionType } from \"@/types\";\nimport {\n  Card,\n  CardAction,\n  CardContent,\n  CardDescription,\n  CardFooter,\n  CardHeader,\n  CardTitle,\n} from \"./card\";\nimport { Button } from \"./button\";\nimport { FUTURE_EXTENSIONS } from \"@/data/extensions\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"./avatar\";\n\nexport default function ExtensionItem({\n  extension,\n}: {\n  extension: ExtensionType;\n}) {\n  return (\n    <Card className=\"justify-start gap-4\">\n      <CardHeader className=\"grid grid-cols-[auto_1fr] items-center gap-4\">\n        <div className=\"bg-primary p-4 rounded-lg\">\n          <Image\n            src={extension.icon}\n            alt=\"\"\n            aria-hidden=\"true\"\n            width={40}\n            height={40}\n          />\n        </div>\n        <div className=\"space-y-1\">\n          <CardTitle className=\"text-2xl font-bold\">{extension.name}</CardTitle>\n          <p className=\"text-muted-foreground\">\n            <strong>Downloads: </strong>\n            {new Intl.NumberFormat().format(extension.downloads)}\n          </p>\n        </div>\n      </CardHeader>\n      <CardContent className=\"flex-1\">\n        <CardDescription className=\"text-base\">\n          {extension.description}\n        </CardDescription>\n      </CardContent>\n      <CardFooter>\n        <CardAction className=\"flex flex-wrap gap-4\">\n          <Button asChild>\n            <Link href={extension.guide_url}>Guide</Link>\n          </Button>\n          <Button asChild variant=\"outline\">\n            <Link\n              href={extension.source_url}\n              target=\"_blank\"\n              rel=\"noopener noreferrer\"\n            >\n              Source\n            </Link>\n          </Button>\n        </CardAction>\n      </CardFooter>\n    </Card>\n  );\n}\n\nexport function NewExtensionItem() {\n  return (\n    <Link\n      href=\"/guide/extensions\"\n      className=\"bg-transparent h-full outline-2 outline-secondary transition-colors duration-200 hover:outline-muted space-y-4 p-6 rounded-lg grid gap-4 place-content-center justify-items-center text-secondary-foreground\"\n    >\n      <ExtensionsAvatarGroup />\n      <span className=\"text-lg font-semibold\">Add your extension here...</span>\n    </Link>\n  );\n}\n\nfunction ExtensionsAvatarGroup() {\n  return (\n    <div className=\"flex -space-x-4\">\n      {FUTURE_EXTENSIONS.map((extension) => (\n        <Avatar key={extension.name} className=\"size-14 bg-secondary p-3\">\n          <AvatarImage src={extension.icon} alt={extension.name} />\n          <AvatarFallback>{extension.shortcut_name}</AvatarFallback>\n        </Avatar>\n      ))}\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/components/ui/input-group.tsx",
    "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\nimport { Input } from \"@/components/ui/input\"\nimport { Textarea } from \"@/components/ui/textarea\"\n\nfunction InputGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"input-group\"\n      role=\"group\"\n      className={cn(\n        \"group/input-group border-input dark:bg-input/30 relative flex w-full items-center rounded-md border shadow-xs transition-[color,box-shadow] outline-none\",\n        \"h-9 min-w-0 has-[>textarea]:h-auto\",\n\n        // Variants based on alignment.\n        \"has-[>[data-align=inline-start]]:[&>input]:pl-2\",\n        \"has-[>[data-align=inline-end]]:[&>input]:pr-2\",\n        \"has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3\",\n        \"has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3\",\n\n        // Focus state.\n        \"has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot=input-group-control]:focus-visible]:ring-[3px]\",\n\n        // Error state.\n        \"has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40\",\n\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nconst inputGroupAddonVariants = cva(\n  \"text-muted-foreground flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium select-none [&>svg:not([class*='size-'])]:size-4 [&>kbd]:rounded-[calc(var(--radius)-5px)] group-data-[disabled=true]/input-group:opacity-50\",\n  {\n    variants: {\n      align: {\n        \"inline-start\":\n          \"order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]\",\n        \"inline-end\":\n          \"order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]\",\n        \"block-start\":\n          \"order-first w-full justify-start px-3 pt-3 [.border-b]:pb-3 group-has-[>input]/input-group:pt-2.5\",\n        \"block-end\":\n          \"order-last w-full justify-start px-3 pb-3 [.border-t]:pt-3 group-has-[>input]/input-group:pb-2.5\",\n      },\n    },\n    defaultVariants: {\n      align: \"inline-start\",\n    },\n  }\n)\n\nfunction InputGroupAddon({\n  className,\n  align = \"inline-start\",\n  ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof inputGroupAddonVariants>) {\n  return (\n    <div\n      role=\"group\"\n      data-slot=\"input-group-addon\"\n      data-align={align}\n      className={cn(inputGroupAddonVariants({ align }), className)}\n      onClick={(e) => {\n        if ((e.target as HTMLElement).closest(\"button\")) {\n          return\n        }\n        e.currentTarget.parentElement?.querySelector(\"input\")?.focus()\n      }}\n      {...props}\n    />\n  )\n}\n\nconst inputGroupButtonVariants = cva(\n  \"text-sm shadow-none flex gap-2 items-center\",\n  {\n    variants: {\n      size: {\n        xs: \"h-6 gap-1 px-2 rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-3.5 has-[>svg]:px-2\",\n        sm: \"h-8 px-2.5 gap-1.5 rounded-md has-[>svg]:px-2.5\",\n        \"icon-xs\":\n          \"size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0\",\n        \"icon-sm\": \"size-8 p-0 has-[>svg]:p-0\",\n      },\n    },\n    defaultVariants: {\n      size: \"xs\",\n    },\n  }\n)\n\nfunction InputGroupButton({\n  className,\n  type = \"button\",\n  variant = \"ghost\",\n  size = \"xs\",\n  ...props\n}: Omit<React.ComponentProps<typeof Button>, \"size\"> &\n  VariantProps<typeof inputGroupButtonVariants>) {\n  return (\n    <Button\n      type={type}\n      data-size={size}\n      variant={variant}\n      className={cn(inputGroupButtonVariants({ size }), className)}\n      {...props}\n    />\n  )\n}\n\nfunction InputGroupText({ className, ...props }: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      className={cn(\n        \"text-muted-foreground flex items-center gap-2 text-sm [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction InputGroupInput({\n  className,\n  ...props\n}: React.ComponentProps<\"input\">) {\n  return (\n    <Input\n      data-slot=\"input-group-control\"\n      className={cn(\n        \"flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction InputGroupTextarea({\n  className,\n  ...props\n}: React.ComponentProps<\"textarea\">) {\n  return (\n    <Textarea\n      data-slot=\"input-group-control\"\n      className={cn(\n        \"flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport {\n  InputGroup,\n  InputGroupAddon,\n  InputGroupButton,\n  InputGroupText,\n  InputGroupInput,\n  InputGroupTextarea,\n}\n"
  },
  {
    "path": "src/components/ui/input.tsx",
    "content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Input({ className, type, ...props }: React.ComponentProps<\"input\">) {\n  return (\n    <input\n      type={type}\n      data-slot=\"input\"\n      className={cn(\n        \"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n        \"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]\",\n        \"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { Input }\n"
  },
  {
    "path": "src/components/ui/label.tsx",
    "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Label as LabelPrimitive } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Label({\n  className,\n  ...props\n}: React.ComponentProps<typeof LabelPrimitive.Root>) {\n  return (\n    <LabelPrimitive.Root\n      data-slot=\"label\"\n      className={cn(\n        \"text-foreground text-sm leading-4 font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { Label }\n"
  },
  {
    "path": "src/components/ui/language-icons.tsx",
    "content": "import { FaJs, FaPython, FaJava } from \"react-icons/fa\";\nimport { SiTypescript, SiNextdotjs, SiReact } from \"react-icons/si\";\n\nexport const languageIcons: Record<\n  string,\n  React.ComponentType<{ size?: number }>\n> = {\n  js: FaJs,\n  ts: SiTypescript,\n  py: FaPython,\n  java: FaJava,\n  nextjs: SiNextdotjs,\n  react: SiReact,\n};\n"
  },
  {
    "path": "src/components/ui/logo.tsx",
    "content": "import Link from \"next/link\";\n\nexport const LogoIcon = () => (\n  <svg\n    width=\"43\"\n    height=\"30\"\n    viewBox=\"0 0 43 30\"\n    fill=\"none\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    role=\"img\"\n    aria-labelledby=\"qs-logo-title qs-logo-description\"\n  >\n    <title id=\"qs-logo-title\">QuickSnip Logo</title>\n    <desc id=\"qs-logo-description\">\n      A light blue logo with a thunderbolt in brackets\n    </desc>\n    <path\n      d=\"M11.0123 3.81725C8.81785 3.81725 7.7866 4.47726 7.9186 5.79726L8.4136 10.871C8.4301 11.0195 8.43835 11.234 8.43835 11.5145C8.43835 12.3065 8.2486 12.917 7.8691 13.346C7.4896 13.7585 6.90385 14.039 6.11185 14.1875C6.92035 14.336 7.5061 14.6165 7.8691 15.029C8.2486 15.425 8.43835 16.0273 8.43835 16.8358C8.43835 17.1163 8.4301 17.339 8.4136 17.504L7.9186 22.5778C7.8526 23.3038 8.1001 23.8153 8.6611 24.1123C9.2221 24.4093 10.0058 24.5578 11.0123 24.5578V26.216C9.52735 26.216 8.3146 25.9603 7.3741 25.4488C6.4336 24.9373 5.96335 24.071 5.96335 22.85C5.96335 22.6355 5.9716 22.4705 5.9881 22.355L6.50785 17.6525C6.52435 17.537 6.5326 17.372 6.5326 17.1575C6.5326 16.4315 6.26035 15.8953 5.71585 15.5488C5.17135 15.2023 4.18135 15.029 2.74585 15.029V13.346C4.18135 13.346 5.17135 13.181 5.71585 12.851C6.26035 12.5045 6.5326 11.9683 6.5326 11.2423C6.5326 11.0443 6.52435 10.8875 6.50785 10.772L5.9881 6.02001C5.9716 5.90451 5.96335 5.73951 5.96335 5.525C5.96335 4.304 6.4336 3.43775 7.3741 2.92625C8.3146 2.41476 9.52735 2.15901 11.0123 2.15901V3.81725Z\"\n      fill=\"#00b5b8\"\n    />\n    <path\n      d=\"M30.6782 13.2235L18.41 25.8383C18.0691 26.1878 17.5037 25.7829 17.7253 25.3482L22.0922 16.7309C22.1252 16.6659 22.1411 16.5935 22.1381 16.5206C22.1352 16.4477 22.1136 16.3767 22.0754 16.3146C22.0372 16.2524 21.9836 16.2011 21.9199 16.1656C21.8562 16.13 21.7844 16.1114 21.7114 16.1116H12.5259C12.442 16.1115 12.36 16.0867 12.2902 16.0402C12.2203 15.9937 12.1658 15.9277 12.1333 15.8503C12.1008 15.7729 12.0919 15.6877 12.1077 15.6053C12.1235 15.5229 12.1632 15.447 12.2219 15.3871L23.6008 3.85901C23.9304 3.52517 24.4787 3.89169 24.2955 4.32496L21.0324 12.0174C21.0048 12.0827 20.9938 12.1537 21.0006 12.2242C21.0073 12.2947 21.0315 12.3625 21.071 12.4213C21.1105 12.4801 21.164 12.5281 21.2267 12.561C21.2894 12.5939 21.3593 12.6107 21.4302 12.6098L30.3671 12.499C30.4514 12.4977 30.5343 12.5214 30.6051 12.5671C30.676 12.6129 30.7317 12.6786 30.7651 12.7561C30.7986 12.8335 30.8083 12.9191 30.7931 13.0021C30.7779 13.085 30.7384 13.1616 30.6796 13.2221L30.6782 13.2235Z\"\n      stroke=\"#00b5b8\"\n      strokeWidth=\"1.65\"\n    />\n    <path\n      d=\"M31.7378 2.15901C33.2228 2.15901 34.4355 2.41476 35.376 2.92625C36.3165 3.43775 36.7868 4.304 36.7868 5.525C36.7868 5.73951 36.7785 5.90451 36.762 6.02001L36.2423 10.772C36.2258 10.8545 36.2175 10.9783 36.2175 11.1433C36.2175 11.8858 36.5063 12.4385 37.0838 12.8015C37.6778 13.1645 38.6513 13.346 40.0043 13.346V15.029C38.6348 15.029 37.6613 15.2105 37.0838 15.5735C36.5063 15.9365 36.2175 16.4975 36.2175 17.2565C36.2175 17.4215 36.2258 17.5535 36.2423 17.6525L36.762 22.355C36.7785 22.4705 36.7868 22.6355 36.7868 22.85C36.7868 24.071 36.3165 24.9373 35.376 25.4488C34.4355 25.9603 33.2228 26.216 31.7378 26.216V24.5578C32.7443 24.5578 33.528 24.4093 34.089 24.1123C34.65 23.8153 34.8975 23.3038 34.8315 22.5778L34.3365 17.504C34.3035 17.174 34.287 16.9513 34.287 16.8358C34.287 16.0108 34.4933 15.4003 34.9058 15.0043C35.3183 14.6083 35.9865 14.3443 36.9105 14.2123C36.0195 14.0473 35.3595 13.7585 34.9305 13.346C34.518 12.917 34.3118 12.2983 34.3118 11.4898C34.3118 11.2258 34.32 11.0195 34.3365 10.871L34.8315 5.79726C34.9635 4.47726 33.9323 3.81725 31.7378 3.81725V2.15901Z\"\n      fill=\"#00b5b8\"\n    />\n  </svg>\n);\n\nconst Logo = () => {\n  return (\n    <Link href=\"/\" className=\"flex items-center gap-2\">\n      <LogoIcon />\n      <span className=\"font-bold text-lg\">QuickSnip</span>\n    </Link>\n  );\n};\n\nexport default Logo;\n"
  },
  {
    "path": "src/components/ui/navigation-menu.tsx",
    "content": "import * as React from \"react\"\nimport * as NavigationMenuPrimitive from \"@radix-ui/react-navigation-menu\"\nimport { cva } from \"class-variance-authority\"\nimport { ChevronDownIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction NavigationMenu({\n  className,\n  children,\n  viewport = true,\n  ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {\n  viewport?: boolean\n}) {\n  return (\n    <NavigationMenuPrimitive.Root\n      data-slot=\"navigation-menu\"\n      data-viewport={viewport}\n      className={cn(\n        \"group/navigation-menu relative flex max-w-max flex-1 items-center justify-center\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n      {viewport && <NavigationMenuViewport />}\n    </NavigationMenuPrimitive.Root>\n  )\n}\n\nfunction NavigationMenuList({\n  className,\n  ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {\n  return (\n    <NavigationMenuPrimitive.List\n      data-slot=\"navigation-menu-list\"\n      className={cn(\n        \"group flex flex-1 list-none items-center justify-center gap-1\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction NavigationMenuItem({\n  className,\n  ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {\n  return (\n    <NavigationMenuPrimitive.Item\n      data-slot=\"navigation-menu-item\"\n      className={cn(\"relative\", className)}\n      {...props}\n    />\n  )\n}\n\nconst navigationMenuTriggerStyle = cva(\n  \"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1\"\n)\n\nfunction NavigationMenuTrigger({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {\n  return (\n    <NavigationMenuPrimitive.Trigger\n      data-slot=\"navigation-menu-trigger\"\n      className={cn(navigationMenuTriggerStyle(), \"group\", className)}\n      {...props}\n    >\n      {children}{\" \"}\n      <ChevronDownIcon\n        className=\"relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180\"\n        aria-hidden=\"true\"\n      />\n    </NavigationMenuPrimitive.Trigger>\n  )\n}\n\nfunction NavigationMenuContent({\n  className,\n  ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {\n  return (\n    <NavigationMenuPrimitive.Content\n      data-slot=\"navigation-menu-content\"\n      className={cn(\n        \"data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 w-full p-2 pr-2.5 md:absolute md:w-auto\",\n        \"group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction NavigationMenuViewport({\n  className,\n  ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {\n  return (\n    <div\n      className={cn(\n        \"absolute top-full left-0 isolate z-50 flex justify-center\"\n      )}\n    >\n      <NavigationMenuPrimitive.Viewport\n        data-slot=\"navigation-menu-viewport\"\n        className={cn(\n          \"origin-top-center bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border shadow md:w-[var(--radix-navigation-menu-viewport-width)]\",\n          className\n        )}\n        {...props}\n      />\n    </div>\n  )\n}\n\nfunction NavigationMenuLink({\n  className,\n  ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {\n  return (\n    <NavigationMenuPrimitive.Link\n      data-slot=\"navigation-menu-link\"\n      className={cn(\n        \"data-[active=true]:focus:bg-accent data-[active=true]:hover:bg-accent data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:ring-ring/50 [&_svg:not([class*='text-'])]:text-muted-foreground flex flex-col gap-1 rounded-sm p-2 text-sm transition-all outline-none focus-visible:ring-[3px] focus-visible:outline-1 [&_svg:not([class*='size-'])]:size-4\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction NavigationMenuIndicator({\n  className,\n  ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {\n  return (\n    <NavigationMenuPrimitive.Indicator\n      data-slot=\"navigation-menu-indicator\"\n      className={cn(\n        \"data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden\",\n        className\n      )}\n      {...props}\n    >\n      <div className=\"bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md\" />\n    </NavigationMenuPrimitive.Indicator>\n  )\n}\n\nexport {\n  NavigationMenu,\n  NavigationMenuList,\n  NavigationMenuItem,\n  NavigationMenuContent,\n  NavigationMenuTrigger,\n  NavigationMenuLink,\n  NavigationMenuIndicator,\n  NavigationMenuViewport,\n  navigationMenuTriggerStyle,\n}\n"
  },
  {
    "path": "src/components/ui/select.tsx",
    "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as SelectPrimitive from \"@radix-ui/react-select\"\nimport { CheckIcon, ChevronDownIcon, ChevronUpIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Select({\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Root>) {\n  return <SelectPrimitive.Root data-slot=\"select\" {...props} />\n}\n\nfunction SelectGroup({\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Group>) {\n  return <SelectPrimitive.Group data-slot=\"select-group\" {...props} />\n}\n\nfunction SelectValue({\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Value>) {\n  return <SelectPrimitive.Value data-slot=\"select-value\" {...props} />\n}\n\nfunction SelectTrigger({\n  className,\n  size = \"default\",\n  children,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {\n  size?: \"sm\" | \"default\"\n}) {\n  return (\n    <SelectPrimitive.Trigger\n      data-slot=\"select-trigger\"\n      data-size={size}\n      className={cn(\n        \"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n      <SelectPrimitive.Icon asChild>\n        <ChevronDownIcon className=\"size-4 opacity-50\" />\n      </SelectPrimitive.Icon>\n    </SelectPrimitive.Trigger>\n  )\n}\n\nfunction SelectContent({\n  className,\n  children,\n  position = \"popper\",\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Content>) {\n  return (\n    <SelectPrimitive.Portal>\n      <SelectPrimitive.Content\n        data-slot=\"select-content\"\n        className={cn(\n          \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md\",\n          position === \"popper\" &&\n            \"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1\",\n          className\n        )}\n        position={position}\n        {...props}\n      >\n        <SelectScrollUpButton />\n        <SelectPrimitive.Viewport\n          className={cn(\n            \"p-1\",\n            position === \"popper\" &&\n              \"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1\"\n          )}\n        >\n          {children}\n        </SelectPrimitive.Viewport>\n        <SelectScrollDownButton />\n      </SelectPrimitive.Content>\n    </SelectPrimitive.Portal>\n  )\n}\n\nfunction SelectLabel({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Label>) {\n  return (\n    <SelectPrimitive.Label\n      data-slot=\"select-label\"\n      className={cn(\"text-muted-foreground px-2 py-1.5 text-xs\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SelectItem({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Item>) {\n  return (\n    <SelectPrimitive.Item\n      data-slot=\"select-item\"\n      className={cn(\n        \"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2\",\n        className\n      )}\n      {...props}\n    >\n      <span className=\"absolute right-2 flex size-3.5 items-center justify-center\">\n        <SelectPrimitive.ItemIndicator>\n          <CheckIcon className=\"size-4\" />\n        </SelectPrimitive.ItemIndicator>\n      </span>\n      <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n    </SelectPrimitive.Item>\n  )\n}\n\nfunction SelectSeparator({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Separator>) {\n  return (\n    <SelectPrimitive.Separator\n      data-slot=\"select-separator\"\n      className={cn(\"bg-border pointer-events-none -mx-1 my-1 h-px\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SelectScrollUpButton({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {\n  return (\n    <SelectPrimitive.ScrollUpButton\n      data-slot=\"select-scroll-up-button\"\n      className={cn(\n        \"flex cursor-default items-center justify-center py-1\",\n        className\n      )}\n      {...props}\n    >\n      <ChevronUpIcon className=\"size-4\" />\n    </SelectPrimitive.ScrollUpButton>\n  )\n}\n\nfunction SelectScrollDownButton({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {\n  return (\n    <SelectPrimitive.ScrollDownButton\n      data-slot=\"select-scroll-down-button\"\n      className={cn(\n        \"flex cursor-default items-center justify-center py-1\",\n        className\n      )}\n      {...props}\n    >\n      <ChevronDownIcon className=\"size-4\" />\n    </SelectPrimitive.ScrollDownButton>\n  )\n}\n\nexport {\n  Select,\n  SelectContent,\n  SelectGroup,\n  SelectItem,\n  SelectLabel,\n  SelectScrollDownButton,\n  SelectScrollUpButton,\n  SelectSeparator,\n  SelectTrigger,\n  SelectValue,\n}\n"
  },
  {
    "path": "src/components/ui/separator.tsx",
    "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as SeparatorPrimitive from \"@radix-ui/react-separator\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Separator({\n  className,\n  orientation = \"horizontal\",\n  decorative = true,\n  ...props\n}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {\n  return (\n    <SeparatorPrimitive.Root\n      data-slot=\"separator\"\n      decorative={decorative}\n      orientation={orientation}\n      className={cn(\n        \"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { Separator }\n"
  },
  {
    "path": "src/components/ui/sheet.tsx",
    "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as SheetPrimitive from \"@radix-ui/react-dialog\"\nimport { XIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {\n  return <SheetPrimitive.Root data-slot=\"sheet\" {...props} />\n}\n\nfunction SheetTrigger({\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {\n  return <SheetPrimitive.Trigger data-slot=\"sheet-trigger\" {...props} />\n}\n\nfunction SheetClose({\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Close>) {\n  return <SheetPrimitive.Close data-slot=\"sheet-close\" {...props} />\n}\n\nfunction SheetPortal({\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Portal>) {\n  return <SheetPrimitive.Portal data-slot=\"sheet-portal\" {...props} />\n}\n\nfunction SheetOverlay({\n  className,\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {\n  return (\n    <SheetPrimitive.Overlay\n      data-slot=\"sheet-overlay\"\n      className={cn(\n        \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction SheetContent({\n  className,\n  children,\n  side = \"right\",\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Content> & {\n  side?: \"top\" | \"right\" | \"bottom\" | \"left\"\n}) {\n  return (\n    <SheetPortal>\n      <SheetOverlay />\n      <SheetPrimitive.Content\n        data-slot=\"sheet-content\"\n        className={cn(\n          \"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500\",\n          side === \"right\" &&\n            \"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm\",\n          side === \"left\" &&\n            \"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm\",\n          side === \"top\" &&\n            \"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b\",\n          side === \"bottom\" &&\n            \"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t\",\n          className\n        )}\n        {...props}\n      >\n        {children}\n        <SheetPrimitive.Close className=\"ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none\">\n          <XIcon className=\"size-4\" />\n          <span className=\"sr-only\">Close</span>\n        </SheetPrimitive.Close>\n      </SheetPrimitive.Content>\n    </SheetPortal>\n  )\n}\n\nfunction SheetHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"sheet-header\"\n      className={cn(\"flex flex-col gap-1.5 p-4\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SheetFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"sheet-footer\"\n      className={cn(\"mt-auto flex flex-col gap-2 p-4\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SheetTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Title>) {\n  return (\n    <SheetPrimitive.Title\n      data-slot=\"sheet-title\"\n      className={cn(\"text-foreground font-semibold\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction SheetDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof SheetPrimitive.Description>) {\n  return (\n    <SheetPrimitive.Description\n      data-slot=\"sheet-description\"\n      className={cn(\"text-muted-foreground text-sm\", className)}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Sheet,\n  SheetTrigger,\n  SheetClose,\n  SheetContent,\n  SheetHeader,\n  SheetFooter,\n  SheetTitle,\n  SheetDescription,\n}\n"
  },
  {
    "path": "src/components/ui/sidebar.tsx",
    "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, VariantProps } from \"class-variance-authority\";\nimport { PanelLeftIcon } from \"lucide-react\";\n\nimport { useIsMobile } from \"@/hooks/use-mobile\";\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Separator } from \"@/components/ui/separator\";\nimport {\n  Sheet,\n  SheetContent,\n  SheetDescription,\n  SheetHeader,\n  SheetTitle,\n} from \"@/components/ui/sheet\";\nimport { Skeleton } from \"@/components/ui/skeleton\";\nimport {\n  Tooltip,\n  TooltipContent,\n  TooltipProvider,\n  TooltipTrigger,\n} from \"@/components/ui/tooltip\";\n\nconst SIDEBAR_COOKIE_NAME = \"sidebar_state\";\nconst SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;\nconst SIDEBAR_WIDTH = \"16rem\";\nconst SIDEBAR_WIDTH_MOBILE = \"18rem\";\nconst SIDEBAR_WIDTH_ICON = \"3rem\";\nconst SIDEBAR_KEYBOARD_SHORTCUT = \"b\";\n\ntype SidebarContextProps = {\n  state: \"expanded\" | \"collapsed\";\n  open: boolean;\n  setOpen: (open: boolean) => void;\n  openMobile: boolean;\n  setOpenMobile: (open: boolean) => void;\n  isMobile: boolean;\n  toggleSidebar: () => void;\n};\n\nconst SidebarContext = React.createContext<SidebarContextProps | null>(null);\n\nfunction useSidebar() {\n  const context = React.useContext(SidebarContext);\n  if (!context) {\n    throw new Error(\"useSidebar must be used within a SidebarProvider.\");\n  }\n\n  return context;\n}\n\nfunction SidebarProvider({\n  defaultOpen = true,\n  open: openProp,\n  onOpenChange: setOpenProp,\n  className,\n  style,\n  children,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  defaultOpen?: boolean;\n  open?: boolean;\n  onOpenChange?: (open: boolean) => void;\n}) {\n  const isMobile = useIsMobile();\n  const [openMobile, setOpenMobile] = React.useState(false);\n\n  // This is the internal state of the sidebar.\n  // We use openProp and setOpenProp for control from outside the component.\n  const [_open, _setOpen] = React.useState(defaultOpen);\n  const open = openProp ?? _open;\n  const setOpen = React.useCallback(\n    (value: boolean | ((value: boolean) => boolean)) => {\n      const openState = typeof value === \"function\" ? value(open) : value;\n      if (setOpenProp) {\n        setOpenProp(openState);\n      } else {\n        _setOpen(openState);\n      }\n\n      // This sets the cookie to keep the sidebar state.\n      document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;\n    },\n    [setOpenProp, open]\n  );\n\n  // Helper to toggle the sidebar.\n  const toggleSidebar = React.useCallback(() => {\n    return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);\n  }, [isMobile, setOpen, setOpenMobile]);\n\n  // Adds a keyboard shortcut to toggle the sidebar.\n  React.useEffect(() => {\n    const handleKeyDown = (event: KeyboardEvent) => {\n      if (\n        event.key === SIDEBAR_KEYBOARD_SHORTCUT &&\n        (event.metaKey || event.ctrlKey)\n      ) {\n        event.preventDefault();\n        toggleSidebar();\n      }\n    };\n\n    window.addEventListener(\"keydown\", handleKeyDown);\n    return () => window.removeEventListener(\"keydown\", handleKeyDown);\n  }, [toggleSidebar]);\n\n  // We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n  // This makes it easier to style the sidebar with Tailwind classes.\n  const state = open ? \"expanded\" : \"collapsed\";\n\n  const contextValue = React.useMemo<SidebarContextProps>(\n    () => ({\n      state,\n      open,\n      setOpen,\n      isMobile,\n      openMobile,\n      setOpenMobile,\n      toggleSidebar,\n    }),\n    [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]\n  );\n\n  return (\n    <SidebarContext.Provider value={contextValue}>\n      <TooltipProvider delayDuration={0}>\n        <div\n          data-slot=\"sidebar-wrapper\"\n          style={\n            {\n              \"--sidebar-width\": SIDEBAR_WIDTH,\n              \"--sidebar-width-icon\": SIDEBAR_WIDTH_ICON,\n              ...style,\n            } as React.CSSProperties\n          }\n          className={cn(\n            \"group/sidebar-wrapper overflow-x-hidden has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full wrapper-lg\",\n            className\n          )}\n          {...props}\n        >\n          {children}\n        </div>\n      </TooltipProvider>\n    </SidebarContext.Provider>\n  );\n}\n\nfunction Sidebar({\n  side = \"left\",\n  variant = \"sidebar\",\n  collapsible = \"offcanvas\",\n  className,\n  children,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  side?: \"left\" | \"right\";\n  variant?: \"sidebar\" | \"floating\" | \"inset\";\n  collapsible?: \"offcanvas\" | \"icon\" | \"none\";\n}) {\n  const { isMobile, state, openMobile, setOpenMobile } = useSidebar();\n\n  if (collapsible === \"none\") {\n    return (\n      <div\n        data-slot=\"sidebar\"\n        className={cn(\n          \"bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col\",\n          className\n        )}\n        {...props}\n      >\n        {children}\n      </div>\n    );\n  }\n\n  if (isMobile) {\n    return (\n      <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>\n        <SheetContent\n          data-sidebar=\"sidebar\"\n          data-slot=\"sidebar\"\n          data-mobile=\"true\"\n          className=\"bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden\"\n          style={\n            {\n              \"--sidebar-width\": SIDEBAR_WIDTH_MOBILE,\n            } as React.CSSProperties\n          }\n          side={side}\n        >\n          <SheetHeader className=\"sr-only\">\n            <SheetTitle>Sidebar</SheetTitle>\n            <SheetDescription>Displays the mobile sidebar.</SheetDescription>\n          </SheetHeader>\n          <div className=\"flex h-full w-full flex-col\">{children}</div>\n        </SheetContent>\n      </Sheet>\n    );\n  }\n\n  return (\n    <div\n      className=\"group relative peer text-sidebar-foreground hidden md:block\"\n      data-state={state}\n      data-collapsible={state === \"collapsed\" ? collapsible : \"\"}\n      data-variant={variant}\n      data-side={side}\n      data-slot=\"sidebar\"\n    >\n      {/* This is what handles the sidebar gap on desktop */}\n      <div\n        data-slot=\"sidebar-gap\"\n        className={cn(\n          \"relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear\",\n          \"group-data-[collapsible=offcanvas]:w-0\",\n          \"group-data-[side=right]:rotate-180\",\n          variant === \"floating\" || variant === \"inset\"\n            ? \"group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]\"\n            : \"group-data-[collapsible=icon]:w-(--sidebar-width-icon)\"\n        )}\n      />\n      <div\n        data-slot=\"sidebar-container\"\n        className={cn(\n          \"absolute inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex\",\n          side === \"left\"\n            ? \"left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]\"\n            : \"right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]\",\n          // Adjust the padding for floating and inset variants.\n          variant === \"floating\" || variant === \"inset\"\n            ? \"p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]\"\n            : \"group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l\",\n          className\n        )}\n        {...props}\n      >\n        <div\n          data-sidebar=\"sidebar\"\n          data-slot=\"sidebar-inner\"\n          className=\"bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm\"\n        >\n          {children}\n        </div>\n      </div>\n    </div>\n  );\n}\n\nfunction SidebarTrigger({\n  className,\n  onClick,\n  ...props\n}: React.ComponentProps<typeof Button>) {\n  const { toggleSidebar } = useSidebar();\n\n  return (\n    <Button\n      data-sidebar=\"trigger\"\n      data-slot=\"sidebar-trigger\"\n      variant=\"ghost\"\n      size=\"icon\"\n      className={cn(\"size-7\", className)}\n      onClick={(event) => {\n        onClick?.(event);\n        toggleSidebar();\n      }}\n      {...props}\n    >\n      <PanelLeftIcon />\n      <span className=\"sr-only\">Toggle Sidebar</span>\n    </Button>\n  );\n}\n\nfunction SidebarRail({ className, ...props }: React.ComponentProps<\"button\">) {\n  const { toggleSidebar } = useSidebar();\n\n  return (\n    <button\n      data-sidebar=\"rail\"\n      data-slot=\"sidebar-rail\"\n      aria-label=\"Toggle Sidebar\"\n      tabIndex={-1}\n      onClick={toggleSidebar}\n      title=\"Toggle Sidebar\"\n      className={cn(\n        \"hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex\",\n        \"in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize\",\n        \"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize\",\n        \"hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full\",\n        \"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2\",\n        \"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarInset({ className, ...props }: React.ComponentProps<\"main\">) {\n  return (\n    <main\n      data-slot=\"sidebar-inset\"\n      className={cn(\n        \"bg-background relative flex w-full flex-1 flex-col\",\n        \"md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarInput({\n  className,\n  ...props\n}: React.ComponentProps<typeof Input>) {\n  return (\n    <Input\n      data-slot=\"sidebar-input\"\n      data-sidebar=\"input\"\n      className={cn(\"bg-background h-8 w-full shadow-none\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"sidebar-header\"\n      data-sidebar=\"header\"\n      className={cn(\"flex flex-col gap-2 p-2\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"sidebar-footer\"\n      data-sidebar=\"footer\"\n      className={cn(\"flex flex-col gap-2 p-2\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarSeparator({\n  className,\n  ...props\n}: React.ComponentProps<typeof Separator>) {\n  return (\n    <Separator\n      data-slot=\"sidebar-separator\"\n      data-sidebar=\"separator\"\n      className={cn(\"bg-sidebar-border mx-2 w-auto\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarContent({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"sidebar-content\"\n      data-sidebar=\"content\"\n      className={cn(\n        \"flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"sidebar-group\"\n      data-sidebar=\"group\"\n      className={cn(\"relative flex w-full min-w-0 flex-col p-2\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarGroupLabel({\n  className,\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"div\"> & { asChild?: boolean }) {\n  const Comp = asChild ? Slot : \"div\";\n\n  return (\n    <Comp\n      data-slot=\"sidebar-group-label\"\n      data-sidebar=\"group-label\"\n      className={cn(\n        \"text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0\",\n        \"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarGroupAction({\n  className,\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"button\"> & { asChild?: boolean }) {\n  const Comp = asChild ? Slot : \"button\";\n\n  return (\n    <Comp\n      data-slot=\"sidebar-group-action\"\n      data-sidebar=\"group-action\"\n      className={cn(\n        \"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0\",\n        // Increases the hit area of the button on mobile.\n        \"after:absolute after:-inset-2 md:after:hidden\",\n        \"group-data-[collapsible=icon]:hidden\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarGroupContent({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"sidebar-group-content\"\n      data-sidebar=\"group-content\"\n      className={cn(\"w-full text-sm\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarMenu({ className, ...props }: React.ComponentProps<\"ul\">) {\n  return (\n    <ul\n      data-slot=\"sidebar-menu\"\n      data-sidebar=\"menu\"\n      className={cn(\"flex w-full min-w-0 flex-col gap-1\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarMenuItem({ className, ...props }: React.ComponentProps<\"li\">) {\n  return (\n    <li\n      data-slot=\"sidebar-menu-item\"\n      data-sidebar=\"menu-item\"\n      className={cn(\"group/menu-item relative\", className)}\n      {...props}\n    />\n  );\n}\n\nconst sidebarMenuButtonVariants = cva(\n  \"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0\",\n  {\n    variants: {\n      variant: {\n        default: \"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground\",\n        outline:\n          \"bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]\",\n      },\n      size: {\n        default: \"h-8 text-sm\",\n        sm: \"h-7 text-xs\",\n        lg: \"h-12 text-sm group-data-[collapsible=icon]:p-0!\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n);\n\nfunction SidebarMenuButton({\n  asChild = false,\n  isActive = false,\n  variant = \"default\",\n  size = \"default\",\n  tooltip,\n  className,\n  ...props\n}: React.ComponentProps<\"button\"> & {\n  asChild?: boolean;\n  isActive?: boolean;\n  tooltip?: string | React.ComponentProps<typeof TooltipContent>;\n} & VariantProps<typeof sidebarMenuButtonVariants>) {\n  const Comp = asChild ? Slot : \"button\";\n  const { isMobile, state } = useSidebar();\n\n  const button = (\n    <Comp\n      data-slot=\"sidebar-menu-button\"\n      data-sidebar=\"menu-button\"\n      data-size={size}\n      data-active={isActive}\n      className={cn(sidebarMenuButtonVariants({ variant, size }), className)}\n      {...props}\n    />\n  );\n\n  if (!tooltip) {\n    return button;\n  }\n\n  if (typeof tooltip === \"string\") {\n    tooltip = {\n      children: tooltip,\n    };\n  }\n\n  return (\n    <Tooltip>\n      <TooltipTrigger asChild>{button}</TooltipTrigger>\n      <TooltipContent\n        side=\"right\"\n        align=\"center\"\n        hidden={state !== \"collapsed\" || isMobile}\n        {...tooltip}\n      />\n    </Tooltip>\n  );\n}\n\nfunction SidebarMenuAction({\n  className,\n  asChild = false,\n  showOnHover = false,\n  ...props\n}: React.ComponentProps<\"button\"> & {\n  asChild?: boolean;\n  showOnHover?: boolean;\n}) {\n  const Comp = asChild ? Slot : \"button\";\n\n  return (\n    <Comp\n      data-slot=\"sidebar-menu-action\"\n      data-sidebar=\"menu-action\"\n      className={cn(\n        \"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0\",\n        // Increases the hit area of the button on mobile.\n        \"after:absolute after:-inset-2 md:after:hidden\",\n        \"peer-data-[size=sm]/menu-button:top-1\",\n        \"peer-data-[size=default]/menu-button:top-1.5\",\n        \"peer-data-[size=lg]/menu-button:top-2.5\",\n        \"group-data-[collapsible=icon]:hidden\",\n        showOnHover &&\n          \"peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarMenuBadge({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"sidebar-menu-badge\"\n      data-sidebar=\"menu-badge\"\n      className={cn(\n        \"text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none\",\n        \"peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground\",\n        \"peer-data-[size=sm]/menu-button:top-1\",\n        \"peer-data-[size=default]/menu-button:top-1.5\",\n        \"peer-data-[size=lg]/menu-button:top-2.5\",\n        \"group-data-[collapsible=icon]:hidden\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarMenuSkeleton({\n  className,\n  showIcon = false,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  showIcon?: boolean;\n}) {\n  // Random width between 50 to 90%.\n  const width = React.useMemo(() => {\n    return `${Math.floor(Math.random() * 40) + 50}%`;\n  }, []);\n\n  return (\n    <div\n      data-slot=\"sidebar-menu-skeleton\"\n      data-sidebar=\"menu-skeleton\"\n      className={cn(\"flex h-8 items-center gap-2 rounded-md px-2\", className)}\n      {...props}\n    >\n      {showIcon && (\n        <Skeleton\n          className=\"size-4 rounded-md\"\n          data-sidebar=\"menu-skeleton-icon\"\n        />\n      )}\n      <Skeleton\n        className=\"h-4 max-w-(--skeleton-width) flex-1\"\n        data-sidebar=\"menu-skeleton-text\"\n        style={\n          {\n            \"--skeleton-width\": width,\n          } as React.CSSProperties\n        }\n      />\n    </div>\n  );\n}\n\nfunction SidebarMenuSub({ className, ...props }: React.ComponentProps<\"ul\">) {\n  return (\n    <ul\n      data-slot=\"sidebar-menu-sub\"\n      data-sidebar=\"menu-sub\"\n      className={cn(\n        \"border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5\",\n        \"group-data-[collapsible=icon]:hidden\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarMenuSubItem({\n  className,\n  ...props\n}: React.ComponentProps<\"li\">) {\n  return (\n    <li\n      data-slot=\"sidebar-menu-sub-item\"\n      data-sidebar=\"menu-sub-item\"\n      className={cn(\"group/menu-sub-item relative\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction SidebarMenuSubButton({\n  asChild = false,\n  size = \"md\",\n  isActive = false,\n  className,\n  ...props\n}: React.ComponentProps<\"a\"> & {\n  asChild?: boolean;\n  size?: \"sm\" | \"md\";\n  isActive?: boolean;\n}) {\n  const Comp = asChild ? Slot : \"a\";\n\n  return (\n    <Comp\n      data-slot=\"sidebar-menu-sub-button\"\n      data-sidebar=\"menu-sub-button\"\n      data-size={size}\n      data-active={isActive}\n      className={cn(\n        \"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0\",\n        \"data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground\",\n        size === \"sm\" && \"text-xs\",\n        size === \"md\" && \"text-sm\",\n        \"group-data-[collapsible=icon]:hidden\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nexport {\n  Sidebar,\n  SidebarContent,\n  SidebarFooter,\n  SidebarGroup,\n  SidebarGroupAction,\n  SidebarGroupContent,\n  SidebarGroupLabel,\n  SidebarHeader,\n  SidebarInput,\n  SidebarInset,\n  SidebarMenu,\n  SidebarMenuAction,\n  SidebarMenuBadge,\n  SidebarMenuButton,\n  SidebarMenuItem,\n  SidebarMenuSkeleton,\n  SidebarMenuSub,\n  SidebarMenuSubButton,\n  SidebarMenuSubItem,\n  SidebarProvider,\n  SidebarRail,\n  SidebarSeparator,\n  SidebarTrigger,\n  useSidebar,\n};\n"
  },
  {
    "path": "src/components/ui/skeleton.tsx",
    "content": "import { cn } from \"@/lib/utils\"\n\nfunction Skeleton({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"skeleton\"\n      className={cn(\"bg-accent animate-pulse rounded-md\", className)}\n      {...props}\n    />\n  )\n}\n\nexport { Skeleton }\n"
  },
  {
    "path": "src/components/ui/snippet-detail.tsx",
    "content": "export default function SnippetDetail() {\n  return (\n    <div>\n      <p>Snippet Detail</p>\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/components/ui/snippet-item.tsx",
    "content": "import { Card, CardContent, CardTitle } from \"./card\";\nimport type { SnippetType } from \"@/types\";\nimport Link from \"next/link\";\nimport { languageIcons } from \"./language-icons\";\n\ninterface SnippetItemProps {\n  snippet: SnippetType;\n}\n\nexport default function SnippetItem({ snippet }: SnippetItemProps) {\n  const { title, languages } = snippet;\n\n  return (\n    <Link href={`/snippets/${snippet.category}/${snippet.id}`}>\n      <Card className=\"py-2 hover:outline-2 hover:outline-border\">\n        <CardContent className=\"space-y-4 px-4\">\n          <CardTitle className=\"text-lg font-bold\">{title}</CardTitle>\n          <ul className=\"flex gap-2 ml-auto w-fit flex-wrap\">\n            {languages.map((language) => {\n              const Icon = languageIcons[language.toLowerCase()];\n              return <li key={language}>{Icon ? <Icon size={24} /> : null}</li>;\n            })}\n          </ul>\n        </CardContent>\n      </Card>\n    </Link>\n  );\n}\n"
  },
  {
    "path": "src/components/ui/snippet-search.tsx",
    "content": "export default function SnippetSearch() {\n  return (\n    <div>\n      <p>Snippet Search</p>\n    </div>\n  );\n}\n"
  },
  {
    "path": "src/components/ui/switch.tsx",
    "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Switch as SwitchPrimitive } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Switch({\n  className,\n  ...props\n}: React.ComponentProps<typeof SwitchPrimitive.Root>) {\n  return (\n    <SwitchPrimitive.Root\n      data-slot=\"switch\"\n      className={cn(\n        \"peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:ring-ring/50 inline-flex h-6 w-10 shrink-0 items-center rounded-full border-2 border-transparent transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50\",\n        className\n      )}\n      {...props}\n    >\n      <SwitchPrimitive.Thumb\n        data-slot=\"switch-thumb\"\n        className={cn(\n          \"bg-background pointer-events-none block size-5 rounded-full shadow-xs ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0 data-[state=checked]:rtl:-translate-x-4\"\n        )}\n      />\n    </SwitchPrimitive.Root>\n  )\n}\n\nexport { Switch }\n"
  },
  {
    "path": "src/components/ui/tabs.tsx",
    "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as TabsPrimitive from \"@radix-ui/react-tabs\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Tabs({\n  className,\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.Root>) {\n  return (\n    <TabsPrimitive.Root\n      data-slot=\"tabs\"\n      className={cn(\"flex flex-col gap-2\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction TabsList({\n  className,\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.List>) {\n  return (\n    <TabsPrimitive.List\n      data-slot=\"tabs-list\"\n      className={cn(\n        \"bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction TabsTrigger({\n  className,\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {\n  return (\n    <TabsPrimitive.Trigger\n      data-slot=\"tabs-trigger\"\n      className={cn(\n        \"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction TabsContent({\n  className,\n  ...props\n}: React.ComponentProps<typeof TabsPrimitive.Content>) {\n  return (\n    <TabsPrimitive.Content\n      data-slot=\"tabs-content\"\n      className={cn(\"flex-1 outline-none\", className)}\n      {...props}\n    />\n  )\n}\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent }\n"
  },
  {
    "path": "src/components/ui/textarea.tsx",
    "content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Textarea({ className, ...props }: React.ComponentProps<\"textarea\">) {\n  return (\n    <textarea\n      data-slot=\"textarea\"\n      className={cn(\n        \"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { Textarea }\n"
  },
  {
    "path": "src/components/ui/tooltip.tsx",
    "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction TooltipProvider({\n  delayDuration = 0,\n  ...props\n}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {\n  return (\n    <TooltipPrimitive.Provider\n      data-slot=\"tooltip-provider\"\n      delayDuration={delayDuration}\n      {...props}\n    />\n  )\n}\n\nfunction Tooltip({\n  ...props\n}: React.ComponentProps<typeof TooltipPrimitive.Root>) {\n  return (\n    <TooltipProvider>\n      <TooltipPrimitive.Root data-slot=\"tooltip\" {...props} />\n    </TooltipProvider>\n  )\n}\n\nfunction TooltipTrigger({\n  ...props\n}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {\n  return <TooltipPrimitive.Trigger data-slot=\"tooltip-trigger\" {...props} />\n}\n\nfunction TooltipContent({\n  className,\n  sideOffset = 0,\n  children,\n  ...props\n}: React.ComponentProps<typeof TooltipPrimitive.Content>) {\n  return (\n    <TooltipPrimitive.Portal>\n      <TooltipPrimitive.Content\n        data-slot=\"tooltip-content\"\n        sideOffset={sideOffset}\n        className={cn(\n          \"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance\",\n          className\n        )}\n        {...props}\n      >\n        {children}\n        <TooltipPrimitive.Arrow className=\"bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]\" />\n      </TooltipPrimitive.Content>\n    </TooltipPrimitive.Portal>\n  )\n}\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }\n"
  },
  {
    "path": "src/data/extensions.ts",
    "content": "import type { ExtensionType } from \"@/types\";\n\nexport const EXTENSIONS: ExtensionType[] = [\n  {\n    icon: \"/assets/extensions/cli.svg\",\n    name: \"CLI\",\n    description: \"CLI extension for QuickSnip.\",\n    guide_url: \"/guide/extensions/quicksnip-cli\",\n    source_url: \"https://github.com\",\n    downloads: 9865,\n  },\n  {\n    icon: \"/assets/extensions/raycast.svg\",\n    name: \"Raycast\",\n    description: \"Raycast extension for QuickSnip.\",\n    guide_url: \"/guide/extensions/quicksnip-raycast\",\n    source_url: \"https://github.com\",\n    downloads: 3580,\n  },\n  {\n    icon: \"/assets/extensions/vscode.svg\",\n    name: \"VS Code\",\n    description: \"VS Code extension for QuickSnip.\",\n    guide_url: \"/guide/extensions/quicksnip-vscode\",\n    source_url: \"https://github.com\",\n    downloads: 8400,\n  },\n];\n\nexport const FUTURE_EXTENSIONS = [\n  {\n    name: \"JetBrains\",\n    icon: \"/assets/extensions/jetbrains.svg\",\n    shortcut_name: \"JB\",\n  },\n  {\n    name: \"NeoVim\",\n    icon: \"/assets/extensions/neovim.svg\",\n    shortcut_name: \"NV\",\n  },\n  {\n    name: \"Vim\",\n    icon: \"/assets/extensions/vim.svg\",\n    shortcut_name: \"VM\",\n  },\n];\n"
  },
  {
    "path": "src/data/meta.ts",
    "content": "export const GITHUB_URL = \"https://github.com/quicksnip-dev/quicksnip\";\nexport const DISCORD_URL = \"https://discord.com/invite/Nm5K46yUy5\";\nexport const SPONSOR_URL = \"https://ko-fi.com/D1D217QALD\";\n"
  },
  {
    "path": "src/data/yt-videos.ts",
    "content": "export const YOUTUBE_VIDEOS = [\n  {\n    id: \"2_AfhnMVuSY\",\n    title: \"We made QuickSnip even better (v1)\",\n  },\n  {\n    id: \"BhRi7fJzPgk\",\n    title: \"I built a library of code snippets for developers\",\n  },\n];\n"
  },
  {
    "path": "src/hooks/use-fetch.ts",
    "content": "import { useEffect, useState } from \"react\";\n\nexport const useFetch = <T>(url: string) => {\n  const [data, setData] = useState<T | null>(null);\n  const [error, setError] = useState<string | null>(null);\n  const [loading, setLoading] = useState<boolean>(true);\n\n  useEffect(() => {\n    const fetchData = async () => {\n      try {\n        const res = await fetch(url);\n        if (!res.ok) {\n          throw new Error(`Failed to fetch data from ${url}`);\n        }\n        const result: T = await res.json();\n        setData(result);\n      } catch (err) {\n        setError((err as Error).message);\n      } finally {\n        setLoading(false);\n      }\n    };\n\n    fetchData();\n  }, [url]);\n\n  return { data, loading, error };\n};\n"
  },
  {
    "path": "src/hooks/use-mobile.ts",
    "content": "import * as React from \"react\"\n\nconst MOBILE_BREAKPOINT = 768\n\nexport function useIsMobile() {\n  const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)\n\n  React.useEffect(() => {\n    const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)\n    const onChange = () => {\n      setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)\n    }\n    mql.addEventListener(\"change\", onChange)\n    setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)\n    return () => mql.removeEventListener(\"change\", onChange)\n  }, [])\n\n  return !!isMobile\n}\n"
  },
  {
    "path": "src/lib/source.ts",
    "content": "// .source folder will be generated when you run `next dev`\nimport { docs } from \"../../.source\";\nimport { loader } from \"fumadocs-core/source\";\n\nexport const source = loader({\n  baseUrl: \"/guide\",\n  source: docs.toFumadocsSource(),\n});\n"
  },
  {
    "path": "src/lib/utils.ts",
    "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport function slugify(string: string, separator = \"-\") {\n  return string\n    .toString() // Cast to string (optional)\n    .toLowerCase() // Convert the string to lowercase letters\n    .trim() // Remove whitespace from both sides of a string (optional)\n    .replace(/\\s+/g, separator) // Replace spaces with {separator}\n    .replace(/[^\\w\\-]+/g, \"\") // Remove all non-word chars\n    .replace(/\\_/g, separator) // Replace _ with {separator}\n    .replace(/\\-\\-+/g, separator) // Replace multiple - with single {separator}\n    .replace(/\\-$/g, \"\"); // Remove trailing -\n}\n\nexport function unslugify(string: string) {\n  return string\n    .trim()\n    .replace(/\\-/g, \" \")\n    .split(\" \")\n    .map((word) => word[0].toUpperCase() + word.slice(1))\n    .join(\" \"); // Replace - with \" \"\n}\n"
  },
  {
    "path": "src/store/useSnippetsStore.ts",
    "content": "import { SnippetType } from \"@/types\";\nimport { create } from \"zustand\";\n\ninterface SnippetsStore {\n  snippets: SnippetType[];\n  selectedCategory: string;\n\n  setSnippets: (snippets: SnippetType[]) => void;\n  setCategory: (category: string) => void;\n\n  categories: () => { name: string; count: number }[];\n}\n\nexport const useSnippetsStore = create<SnippetsStore>((set, get) => ({\n  snippets: [],\n  selectedLanguage: \"\",\n  selectedCategory: \"all\",\n\n  setSnippets: (snippets) => set({ snippets: snippets }),\n  setCategory: (category) => set({ selectedCategory: category }),\n\n  categories: () => {\n    const { snippets } = get();\n    const counts: Record<string, number> = {};\n\n    snippets.forEach((snippet) => {\n      if (counts[snippet.category]) {\n        counts[snippet.category]++;\n      } else {\n        counts[snippet.category] = 1;\n      }\n    });\n\n    return Object.entries(counts).map(([name, count]) => ({ name, count }));\n  },\n}));\n"
  },
  {
    "path": "src/types/index.ts",
    "content": "export type ExtensionType = {\n  icon: string;\n  name: string;\n  description: string;\n  guide_url: string;\n  source_url: string;\n  downloads: number;\n};\n\nexport type SnippetType = {\n  id: string;\n  category: string;\n  title: string;\n  description: string;\n  languages: string[];\n  contributors: string[];\n  tags: string[];\n};\n\nexport type FullSnippet = {\n  id: string;\n  category: string;\n  title: string;\n  description: string;\n  languages: string[];\n  contributors: string[];\n  tags: string[];\n  snippets: Record<string, string>;\n};\n"
  },
  {
    "path": "tailwind.config.mjs",
    "content": "const config = {\n  // content: [\"./app/**/*.{js,ts,jsx,tsx}\", \"./components/**/*.{js,ts,jsx,tsx}\"],\n  theme: { extend: {} },\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"
  }
]