From 15be16cb60f52f9ba3e835cd9c556c70972be2ce Mon Sep 17 00:00:00 2001
From: Minsu Lee <amond@amond.net>
Date: Fri, 28 Nov 2025 16:54:56 +0900
Subject: [PATCH 1/5] fix(layer): resolve UI components from layer directory in
 multi-layer setup

- Fixed shadcn.ts to properly discover UI components from Nuxt layer packages
- Updated shadcn module to search node_modules for @pleaseai/docs-layer when resolving components
- Modified templates to use UiSeparator prefix for component references
- Added missing return type annotations to utils and composables (ESLint compliance)
- Added content components for documentation rendering
- Updated nuxt.config.ts shadcn configuration for layer compatibility
- Fixed process import in utils/git.ts for node environment

This resolves component resolution issues in multi-layer Nuxt setups where UI components
are defined in the layer package but need to be discovered at runtime.
---
 .env.secrets                                  |   4 -
 .idea/misc.xml                                |   1 -
 .idea/vcs.xml                                 |   3 +
 CLAUDE.md                                     |   4 +-
 README.md                                     |   1 +
 apps/docs/.gitignore                          |   4 +
 .../docs/1.getting-started/2.installation.md  |   5 +-
 .../docs/1.getting-started/3.configuration.md |  10 +-
 .../1.getting-started/4.writing-content.md    |   5 +-
 .../content/docs/2.components/1.overview.md   |  18 +-
 .../content/docs/2.components/2.button.md     |  48 ++-
 .../content/docs/2.components/3.separator.md  |   8 +-
 apps/docs/eslint.config.mjs                   |  12 +
 apps/docs/nuxt.config.ts                      |  15 +-
 apps/docs/package.json                        |  10 +-
 bun.lock                                      | 318 +++++++++++++++---
 docs/ref-analysis.md                          |  75 +++--
 eslint.config.mjs                             |   1 +
 package.json                                  |  26 +-
 packages/layer/README.md                      |   3 +-
 packages/layer/app/assets/css/main.css        |  29 +-
 .../layer/app/components/app/AppHeader.vue    |   1 +
 .../layer/app/components/content/Callout.vue  |  36 ++
 .../content/CodeCollapsibleWrapper.vue        |  47 +++
 .../layer/app/components/content/CodeTabs.vue |  14 +
 .../components/content/ComponentPreview.vue   |  64 ++++
 .../app/components/content/ComponentsList.vue |  24 ++
 .../app/components/content/LinkedCard.vue     |  19 ++
 .../layer/app/components/content/ProseA.vue   |  18 +
 .../components/content/ProseBlockQuote.vue    |   8 +
 .../app/components/content/ProseCode.vue      |   8 +
 .../layer/app/components/content/ProseH1.vue  |   7 +
 .../layer/app/components/content/ProseH2.vue  |   8 +
 .../layer/app/components/content/ProseH3.vue  |   9 +
 .../layer/app/components/content/ProseH4.vue  |   9 +
 .../layer/app/components/content/ProseH5.vue  |   7 +
 .../layer/app/components/content/ProseH6.vue  |   7 +
 .../layer/app/components/content/ProseHr.vue  |   6 +
 .../layer/app/components/content/ProseImg.vue |   6 +
 .../layer/app/components/content/ProseLi.vue  |   8 +
 .../layer/app/components/content/ProseOl.vue  |   8 +
 .../layer/app/components/content/ProseP.vue   |  14 +
 .../layer/app/components/content/ProsePre.vue |  82 +++++
 .../app/components/content/ProseStrong.vue    |   8 +
 .../app/components/content/ProseTable.vue     |  26 ++
 .../layer/app/components/content/ProseTd.vue  |   8 +
 .../layer/app/components/content/ProseTh.vue  |   8 +
 .../layer/app/components/content/ProseTr.vue  |   8 +
 .../layer/app/components/content/ProseUl.vue  |   8 +
 .../layer/app/components/content/Step.vue     |  18 +
 .../layer/app/components/content/Steps.vue    |  18 +
 .../layer/app/components/content/Tabs.vue     |  13 +
 .../app/components/content/TabsContent.vue    |  14 +
 .../layer/app/components/content/TabsList.vue |  13 +
 .../app/components/content/TabsTrigger.vue    |  13 +
 .../layer/app/components/docs/DocsSidebar.vue |   3 +-
 .../components/docs/DocsTableOfContents.vue   |   3 +-
 .../layer/app/components/ui/alert/Alert.vue   |  21 ++
 .../components/ui/alert/AlertDescription.vue  |  17 +
 .../app/components/ui/alert/AlertTitle.vue    |  17 +
 .../layer/app/components/ui/alert/index.ts    |  24 ++
 .../layer/app/components/ui/button/Button.vue |  20 +-
 .../layer/app/components/ui/button/index.ts   |  38 +++
 .../app/components/ui/button/variants.ts      |  38 ---
 .../components/ui/collapsible/Collapsible.vue |  19 ++
 .../ui/collapsible/CollapsibleContent.vue     |  15 +
 .../ui/collapsible/CollapsibleTrigger.vue     |  15 +
 .../app/components/ui/collapsible/index.ts    |   3 +
 .../app/components/ui/separator/Separator.vue |  16 +-
 .../app/components/ui/separator/index.ts      |   1 +
 .../layer/app/components/ui/tabs/Tabs.vue     |  24 ++
 .../app/components/ui/tabs/TabsContent.vue    |  21 ++
 .../layer/app/components/ui/tabs/TabsList.vue |  24 ++
 .../app/components/ui/tabs/TabsTrigger.vue    |  26 ++
 .../layer/app/components/ui/tabs/index.ts     |   4 +
 .../layer/app/composables/useNavigation.ts    |   2 +-
 packages/layer/app/lib/utils.ts               |   7 +
 packages/layer/app/pages/[...slug].vue        |  24 +-
 packages/layer/app/pages/index.vue            |   3 +-
 packages/layer/app/plugins/ssr-width.ts       |   5 +
 packages/layer/app/utils/cn.ts                |   7 -
 packages/layer/components.json                |  21 ++
 packages/layer/content.config.ts              |   2 +-
 packages/layer/eslint.config.mjs              |  11 +
 packages/layer/modules/config.ts              |   2 +-
 packages/layer/modules/css.ts                 |   2 +-
 packages/layer/modules/shadcn.ts              | 116 +++++++
 packages/layer/nuxt.config.ts                 |  32 +-
 packages/layer/package.json                   |  34 +-
 packages/layer/utils/git.ts                   |   3 +-
 packages/layer/utils/meta.ts                  |   5 +-
 91 files changed, 1535 insertions(+), 255 deletions(-)
 create mode 100644 apps/docs/.gitignore
 create mode 100644 apps/docs/eslint.config.mjs
 create mode 100644 packages/layer/app/components/content/Callout.vue
 create mode 100644 packages/layer/app/components/content/CodeCollapsibleWrapper.vue
 create mode 100644 packages/layer/app/components/content/CodeTabs.vue
 create mode 100644 packages/layer/app/components/content/ComponentPreview.vue
 create mode 100644 packages/layer/app/components/content/ComponentsList.vue
 create mode 100644 packages/layer/app/components/content/LinkedCard.vue
 create mode 100644 packages/layer/app/components/content/ProseA.vue
 create mode 100644 packages/layer/app/components/content/ProseBlockQuote.vue
 create mode 100644 packages/layer/app/components/content/ProseCode.vue
 create mode 100644 packages/layer/app/components/content/ProseH1.vue
 create mode 100644 packages/layer/app/components/content/ProseH2.vue
 create mode 100644 packages/layer/app/components/content/ProseH3.vue
 create mode 100644 packages/layer/app/components/content/ProseH4.vue
 create mode 100644 packages/layer/app/components/content/ProseH5.vue
 create mode 100644 packages/layer/app/components/content/ProseH6.vue
 create mode 100644 packages/layer/app/components/content/ProseHr.vue
 create mode 100644 packages/layer/app/components/content/ProseImg.vue
 create mode 100644 packages/layer/app/components/content/ProseLi.vue
 create mode 100644 packages/layer/app/components/content/ProseOl.vue
 create mode 100644 packages/layer/app/components/content/ProseP.vue
 create mode 100644 packages/layer/app/components/content/ProsePre.vue
 create mode 100644 packages/layer/app/components/content/ProseStrong.vue
 create mode 100644 packages/layer/app/components/content/ProseTable.vue
 create mode 100644 packages/layer/app/components/content/ProseTd.vue
 create mode 100644 packages/layer/app/components/content/ProseTh.vue
 create mode 100644 packages/layer/app/components/content/ProseTr.vue
 create mode 100644 packages/layer/app/components/content/ProseUl.vue
 create mode 100644 packages/layer/app/components/content/Step.vue
 create mode 100644 packages/layer/app/components/content/Steps.vue
 create mode 100644 packages/layer/app/components/content/Tabs.vue
 create mode 100644 packages/layer/app/components/content/TabsContent.vue
 create mode 100644 packages/layer/app/components/content/TabsList.vue
 create mode 100644 packages/layer/app/components/content/TabsTrigger.vue
 create mode 100644 packages/layer/app/components/ui/alert/Alert.vue
 create mode 100644 packages/layer/app/components/ui/alert/AlertDescription.vue
 create mode 100644 packages/layer/app/components/ui/alert/AlertTitle.vue
 create mode 100644 packages/layer/app/components/ui/alert/index.ts
 create mode 100644 packages/layer/app/components/ui/button/index.ts
 delete mode 100644 packages/layer/app/components/ui/button/variants.ts
 create mode 100644 packages/layer/app/components/ui/collapsible/Collapsible.vue
 create mode 100644 packages/layer/app/components/ui/collapsible/CollapsibleContent.vue
 create mode 100644 packages/layer/app/components/ui/collapsible/CollapsibleTrigger.vue
 create mode 100644 packages/layer/app/components/ui/collapsible/index.ts
 create mode 100644 packages/layer/app/components/ui/separator/index.ts
 create mode 100644 packages/layer/app/components/ui/tabs/Tabs.vue
 create mode 100644 packages/layer/app/components/ui/tabs/TabsContent.vue
 create mode 100644 packages/layer/app/components/ui/tabs/TabsList.vue
 create mode 100644 packages/layer/app/components/ui/tabs/TabsTrigger.vue
 create mode 100644 packages/layer/app/components/ui/tabs/index.ts
 create mode 100644 packages/layer/app/lib/utils.ts
 create mode 100644 packages/layer/app/plugins/ssr-width.ts
 delete mode 100644 packages/layer/app/utils/cn.ts
 create mode 100644 packages/layer/components.json
 create mode 100644 packages/layer/eslint.config.mjs
 create mode 100644 packages/layer/modules/shadcn.ts

diff --git a/.env.secrets b/.env.secrets
index c25c2ddc..21da696e 100644
--- a/.env.secrets
+++ b/.env.secrets
@@ -1,6 +1,2 @@
 # Secrets (will be encrypted with dotenvx)
 # Run: bun x dotenvx encrypt
-
-# Cloudflare deployment credentials
-CLOUDFLARE_API_TOKEN=rGeRpJxv4E3wU_DrDaxihWmAb1DHNFwdaHF72-kD
-CLOUDFLARE_ACCOUNT_ID=20f4dac8c33060fc42fd560d8e90b630
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 07115cdf..ef89d983 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
   <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
     <output url="file://$PROJECT_DIR$/out" />
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 35eb1ddf..8b3e1129 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -2,5 +2,8 @@
 <project version="4">
   <component name="VcsDirectoryMappings">
     <mapping directory="" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$/ref/docus" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$/ref/fumadocs" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$/ref/shadcn-vue" vcs="Git" />
   </component>
 </project>
\ No newline at end of file
diff --git a/CLAUDE.md b/CLAUDE.md
index 334c8699..93c55170 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -72,6 +72,7 @@ packages/layer/
 ### Configuration Schema
 
 Site configuration in `app.config.ts`:
+
 - `docs.title` - Site title
 - `docs.description` - Site description
 - `docs.url` - Site URL
@@ -80,6 +81,7 @@ Site configuration in `app.config.ts`:
 ### Using the Layer
 
 Apps extend the layer via `nuxt.config.ts`:
+
 ```ts
 export default defineNuxtConfig({
   extends: ['@pleaseai/docs-layer'],
@@ -88,4 +90,4 @@ export default defineNuxtConfig({
 
 ## ESLint
 
-Uses `@antfu/eslint-config` with Vue and formatters enabled.
\ No newline at end of file
+Uses `@antfu/eslint-config` with Vue and formatters enabled.
diff --git a/README.md b/README.md
index ff2cfd57..dc591b95 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,7 @@ A documentation system using **shadcn-vue** + **Nuxt Content**, inspired by Docu
 A Nuxt layer for documentation sites. Replaces nuxt-ui with shadcn-vue components.
 
 **Features:**
+
 - shadcn-vue UI components (Button, Separator, etc.)
 - Tailwind CSS v4 with CSS variables (oklch colors)
 - Documentation layout with sidebar navigation
diff --git a/apps/docs/.gitignore b/apps/docs/.gitignore
new file mode 100644
index 00000000..3ee48cb3
--- /dev/null
+++ b/apps/docs/.gitignore
@@ -0,0 +1,4 @@
+/node_modules/
+/.wrangler/
+/.nuxt/
+/.data/
diff --git a/apps/docs/content/docs/1.getting-started/2.installation.md b/apps/docs/content/docs/1.getting-started/2.installation.md
index aa9f7429..70c9fa8c 100644
--- a/apps/docs/content/docs/1.getting-started/2.installation.md
+++ b/apps/docs/content/docs/1.getting-started/2.installation.md
@@ -43,10 +43,11 @@ export default defineNuxtConfig({
 Create a `content` directory and add your first page:
 
 ```md
-<!-- content/index.md -->
----
+## <!-- content/index.md -->
+
 title: Welcome
 description: My documentation site
+
 ---
 
 # Welcome to My Docs
diff --git a/apps/docs/content/docs/1.getting-started/3.configuration.md b/apps/docs/content/docs/1.getting-started/3.configuration.md
index c59ba322..02337d48 100644
--- a/apps/docs/content/docs/1.getting-started/3.configuration.md
+++ b/apps/docs/content/docs/1.getting-started/3.configuration.md
@@ -67,11 +67,11 @@ docs: {
 
 The layer automatically detects environment variables:
 
-| Variable | Description |
-|----------|-------------|
-| `NUXT_SITE_URL` | Site URL |
-| `VERCEL_GIT_REPO_OWNER` | GitHub owner (Vercel) |
-| `GITHUB_REPOSITORY` | GitHub repository (GitHub Actions) |
+| Variable                | Description                        |
+| ----------------------- | ---------------------------------- |
+| `NUXT_SITE_URL`         | Site URL                           |
+| `VERCEL_GIT_REPO_OWNER` | GitHub owner (Vercel)              |
+| `GITHUB_REPOSITORY`     | GitHub repository (GitHub Actions) |
 
 ## Next Steps
 
diff --git a/apps/docs/content/docs/1.getting-started/4.writing-content.md b/apps/docs/content/docs/1.getting-started/4.writing-content.md
index ea6d1a7e..641c7bc7 100644
--- a/apps/docs/content/docs/1.getting-started/4.writing-content.md
+++ b/apps/docs/content/docs/1.getting-started/4.writing-content.md
@@ -30,6 +30,7 @@ Prefix folders and files with numbers to control the order:
 - `1.introduction.md` appears before `2.installation.md`
 
 The numbers are stripped from the URL:
+
 - `content/docs/1.getting-started/1.introduction.md` → `/docs/getting-started/introduction`
 
 ## Frontmatter
@@ -51,7 +52,9 @@ description: A brief description for SEO
 
 ```md
 # H1 - Page Title
+
 ## H2 - Section
+
 ### H3 - Subsection
 ```
 
@@ -85,7 +88,7 @@ const hello = 'world'
 
 ```md
 | Column 1 | Column 2 |
-|----------|----------|
+| -------- | -------- |
 | Cell 1   | Cell 2   |
 ```
 
diff --git a/apps/docs/content/docs/2.components/1.overview.md b/apps/docs/content/docs/2.components/1.overview.md
index 29cd593c..cf77a175 100644
--- a/apps/docs/content/docs/2.components/1.overview.md
+++ b/apps/docs/content/docs/2.components/1.overview.md
@@ -18,6 +18,7 @@ The site header with navigation and dark mode toggle.
 ```
 
 Features:
+
 - Site title/logo
 - Navigation links
 - Dark/light mode toggle
@@ -42,6 +43,7 @@ Navigation sidebar for documentation pages.
 ```
 
 Features:
+
 - Hierarchical navigation
 - Active state highlighting
 - Collapsible sections
@@ -55,6 +57,7 @@ Table of contents for the current page.
 ```
 
 Features:
+
 - Auto-generated from headings
 - Scroll-aware active state
 - Depth-based indentation
@@ -88,15 +91,24 @@ The layer includes shadcn-vue components:
 ### Button
 
 ```vue
-<Button variant="default">Click me</Button>
-<Button variant="outline">Outline</Button>
-<Button variant="ghost">Ghost</Button>
+<Button variant="default">
+Click me
+</Button>
+
+<Button variant="outline">
+Outline
+</Button>
+
+<Button variant="ghost">
+Ghost
+</Button>
 ```
 
 ### Separator
 
 ```vue
 <Separator />
+
 <Separator orientation="vertical" />
 ```
 
diff --git a/apps/docs/content/docs/2.components/2.button.md b/apps/docs/content/docs/2.components/2.button.md
index c57e0508..4163bb67 100644
--- a/apps/docs/content/docs/2.components/2.button.md
+++ b/apps/docs/content/docs/2.components/2.button.md
@@ -24,37 +24,49 @@ import { Button } from '~/components/ui/button'
 ### Default
 
 ```vue
-<Button variant="default">Default</Button>
+<Button variant="default">
+Default
+</Button>
 ```
 
 ### Destructive
 
 ```vue
-<Button variant="destructive">Destructive</Button>
+<Button variant="destructive">
+Destructive
+</Button>
 ```
 
 ### Outline
 
 ```vue
-<Button variant="outline">Outline</Button>
+<Button variant="outline">
+Outline
+</Button>
 ```
 
 ### Secondary
 
 ```vue
-<Button variant="secondary">Secondary</Button>
+<Button variant="secondary">
+Secondary
+</Button>
 ```
 
 ### Ghost
 
 ```vue
-<Button variant="ghost">Ghost</Button>
+<Button variant="ghost">
+Ghost
+</Button>
 ```
 
 ### Link
 
 ```vue
-<Button variant="link">Link</Button>
+<Button variant="link">
+Link
+</Button>
 ```
 
 ## Sizes
@@ -62,19 +74,25 @@ import { Button } from '~/components/ui/button'
 ### Default
 
 ```vue
-<Button size="default">Default</Button>
+<Button size="default">
+Default
+</Button>
 ```
 
 ### Small
 
 ```vue
-<Button size="sm">Small</Button>
+<Button size="sm">
+Small
+</Button>
 ```
 
 ### Large
 
 ```vue
-<Button size="lg">Large</Button>
+<Button size="lg">
+Large
+</Button>
 ```
 
 ### Icon
@@ -87,12 +105,12 @@ import { Button } from '~/components/ui/button'
 
 ## Props
 
-| Prop | Type | Default | Description |
-|------|------|---------|-------------|
-| `variant` | `string` | `'default'` | Button variant |
-| `size` | `string` | `'default'` | Button size |
-| `as` | `string` | `'button'` | Element to render |
-| `asChild` | `boolean` | `false` | Merge props onto child |
+| Prop      | Type      | Default     | Description            |
+| --------- | --------- | ----------- | ---------------------- |
+| `variant` | `string`  | `'default'` | Button variant         |
+| `size`    | `string`  | `'default'` | Button size            |
+| `as`      | `string`  | `'button'`  | Element to render      |
+| `asChild` | `boolean` | `false`     | Merge props onto child |
 
 ## With Icons
 
diff --git a/apps/docs/content/docs/2.components/3.separator.md b/apps/docs/content/docs/2.components/3.separator.md
index 5162c52a..9bfbf7f5 100644
--- a/apps/docs/content/docs/2.components/3.separator.md
+++ b/apps/docs/content/docs/2.components/3.separator.md
@@ -47,10 +47,10 @@ Use `orientation="vertical"` for vertical separators:
 
 ## Props
 
-| Prop | Type | Default | Description |
-|------|------|---------|-------------|
-| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Orientation of the separator |
-| `decorative` | `boolean` | `true` | Whether the separator is decorative |
+| Prop          | Type                         | Default        | Description                         |
+| ------------- | ---------------------------- | -------------- | ----------------------------------- |
+| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Orientation of the separator        |
+| `decorative`  | `boolean`                    | `true`         | Whether the separator is decorative |
 
 ## Styling
 
diff --git a/apps/docs/eslint.config.mjs b/apps/docs/eslint.config.mjs
new file mode 100644
index 00000000..11bac459
--- /dev/null
+++ b/apps/docs/eslint.config.mjs
@@ -0,0 +1,12 @@
+// @ts-check
+import antfu from '@antfu/eslint-config'
+import withNuxt from './.nuxt/eslint.config.mjs'
+
+export default withNuxt(
+    antfu({
+            formatters: false,
+            vue: true,
+            markdown: false,
+            type: 'app',
+        })
+)
\ No newline at end of file
diff --git a/apps/docs/nuxt.config.ts b/apps/docs/nuxt.config.ts
index e06a0fd2..a2b4329b 100644
--- a/apps/docs/nuxt.config.ts
+++ b/apps/docs/nuxt.config.ts
@@ -1,14 +1,19 @@
+import tailwindcss from '@tailwindcss/vite'
+import { defineNuxtConfig } from 'nuxt/config'
+
 export default defineNuxtConfig({
   extends: ['@pleaseai/docs'],
-
   site: {
-    name: 'PleaseAI Docs',
+    name: 'DOCS PLEASE Docs',
     url: 'https://docs.please.ai',
   },
-
   compatibilityDate: '2025-01-01',
-
   nitro: {
     preset: 'cloudflare-pages',
   },
-})
+    eslint: {
+    config: {
+        standalone: false
+    }
+},
+})
\ No newline at end of file
diff --git a/apps/docs/package.json b/apps/docs/package.json
index edeae375..614e646f 100644
--- a/apps/docs/package.json
+++ b/apps/docs/package.json
@@ -1,19 +1,25 @@
 {
   "name": "@pleaseai/docs-site",
+  "type": "module",
   "version": "0.1.0",
   "private": true,
-  "type": "module",
   "scripts": {
     "dev": "nuxt dev",
     "build": "nuxt build",
     "generate": "nuxt generate",
     "preview": "nuxt preview",
-    "postinstall": "nuxt prepare"
+    "postinstall": "nuxt prepare",
+    "lint": "eslint .",
+    "lint:fix": "eslint . --fix"
   },
   "dependencies": {
     "@pleaseai/docs": "workspace:*"
   },
   "devDependencies": {
+    "@antfu/eslint-config": "^6.2.0",
+    "@tailwindcss/vite": "^4.1.17",
+    "eslint": "^9.38.0",
+    "eslint-plugin-format": "^1.0.2",
     "nuxt": "^4.2.1"
   }
 }
diff --git a/bun.lock b/bun.lock
index 3ee24e49..e52efd19 100644
--- a/bun.lock
+++ b/bun.lock
@@ -17,6 +17,10 @@
         "@pleaseai/docs": "workspace:*",
       },
       "devDependencies": {
+        "@antfu/eslint-config": "^6.2.0",
+        "@tailwindcss/vite": "^4.1.17",
+        "eslint": "^9.38.0",
+        "eslint-plugin-format": "^1.0.2",
         "nuxt": "^4.2.1",
       },
     },
@@ -26,25 +30,29 @@
       "dependencies": {
         "@iconify-json/lucide": "^1.2.75",
         "@nuxt/content": "^3.8.2",
+        "@nuxt/eslint": "^1.11.0",
         "@nuxt/image": "^2.0.0",
         "@nuxt/kit": "^4.2.1",
         "@nuxtjs/color-mode": "^4.0.0",
         "@nuxtjs/mdc": "^0.18.4",
-        "@vueuse/core": "^13.9.0",
+        "@vueuse/core": "^14.1.0",
         "class-variance-authority": "^0.7.1",
         "clsx": "^2.1.1",
         "debug": "^4.4.1",
         "defu": "^6.1.4",
-        "lucide-vue-next": "^0.553.0",
+        "eslint": "^9.39.1",
+        "lucide-vue-next": "^0.555.0",
         "nuxt-og-image": "^5.1.12",
         "nuxt-shiki": "^0.3.1",
+        "oxc-parser": "^0.99.0",
         "parse5": "^7.3.0",
         "rehype-raw": "^7.0.0",
-        "reka-ui": "^2.2.1",
+        "reka-ui": "^2.6.0",
         "remark-emoji": "^5.0.1",
         "remark-gfm": "^4.0.1",
         "remark-mdc": "^3.5.1",
         "remark-rehype": "^11.1.2",
+        "shadcn-nuxt": "2.3.3",
         "slugify": "^1.6.6",
         "tailwind-merge": "^3.4.0",
         "tailwindcss": "^4.1.17",
@@ -54,8 +62,10 @@
         "unist-util-visit": "^5.0.0",
       },
       "devDependencies": {
+        "@antfu/eslint-config": "^6.2.0",
         "@tailwindcss/vite": "^4.1.17",
         "better-sqlite3": "^11.9.1",
+        "typescript": "^5.9.3",
         "vue-tsc": "^2.0.0",
       },
       "peerDependencies": {
@@ -216,6 +226,8 @@
 
     "@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="],
 
+    "@eslint/config-inspector": ["@eslint/config-inspector@1.4.2", "", { "dependencies": { "ansis": "^4.2.0", "bundle-require": "^5.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "esbuild": "^0.27.0", "h3": "^1.15.4", "tinyglobby": "^0.2.15", "ws": "^8.18.3" }, "peerDependencies": { "eslint": "^8.50.0 || ^9.0.0" }, "bin": { "eslint-config-inspector": "bin.mjs", "config-inspector": "bin.mjs" } }, "sha512-Ay8QcvV/Tq6YDeoltwZDQsQTrcS5flPkOp4ylk1WdV7L2UGotINwjatjbAIEqBTmP3G0g3Ah8dnuHC8DsnKPYQ=="],
+
     "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="],
 
     "@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="],
@@ -356,10 +368,16 @@
 
     "@nuxt/devtools": ["@nuxt/devtools@3.1.1", "", { "dependencies": { "@nuxt/devtools-kit": "3.1.1", "@nuxt/devtools-wizard": "3.1.1", "@nuxt/kit": "^4.2.1", "@vue/devtools-core": "^8.0.5", "@vue/devtools-kit": "^8.0.5", "birpc": "^2.8.0", "consola": "^3.4.2", "destr": "^2.0.5", "error-stack-parser-es": "^1.0.5", "execa": "^8.0.1", "fast-npm-meta": "^0.4.7", "get-port-please": "^3.2.0", "hookable": "^5.5.3", "image-meta": "^0.2.2", "is-installed-globally": "^1.0.0", "launch-editor": "^2.12.0", "local-pkg": "^1.1.2", "magicast": "^0.5.1", "nypm": "^0.6.2", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "semver": "^7.7.3", "simple-git": "^3.30.0", "sirv": "^3.0.2", "structured-clone-es": "^1.0.0", "tinyglobby": "^0.2.15", "vite-plugin-inspect": "^11.3.3", "vite-plugin-vue-tracer": "^1.1.3", "which": "^5.0.0", "ws": "^8.18.3" }, "peerDependencies": { "@vitejs/devtools": "*", "vite": ">=6.0" }, "optionalPeers": ["@vitejs/devtools"], "bin": { "devtools": "cli.mjs" } }, "sha512-UG8oKQqcSyzwBe1l0z24zypmwn6FLW/HQMHK/F/gscUU5LeMHzgBhLPD+cuLlDvwlGAbifexWNMsS/I7n95KlA=="],
 
-    "@nuxt/devtools-kit": ["@nuxt/devtools-kit@2.7.0", "", { "dependencies": { "@nuxt/kit": "^3.19.3", "execa": "^8.0.1" }, "peerDependencies": { "vite": ">=6.0" } }, "sha512-MIJdah6CF6YOW2GhfKnb8Sivu6HpcQheqdjOlZqShBr+1DyjtKQbAKSCAyKPaoIzZP4QOo2SmTFV6aN8jBeEIQ=="],
+    "@nuxt/devtools-kit": ["@nuxt/devtools-kit@3.1.1", "", { "dependencies": { "@nuxt/kit": "^4.2.1", "execa": "^8.0.1" }, "peerDependencies": { "vite": ">=6.0" } }, "sha512-sjiKFeDCOy1SyqezSgyV4rYNfQewC64k/GhOsuJgRF+wR2qr6KTVhO6u2B+csKs74KrMrnJprQBgud7ejvOXAQ=="],
 
     "@nuxt/devtools-wizard": ["@nuxt/devtools-wizard@3.1.1", "", { "dependencies": { "consola": "^3.4.2", "diff": "^8.0.2", "execa": "^8.0.1", "magicast": "^0.5.1", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "prompts": "^2.4.2", "semver": "^7.7.3" }, "bin": { "devtools-wizard": "cli.mjs" } }, "sha512-6UORjapNKko2buv+3o57DQp69n5Z91TeJ75qdtNKcTvOfCTJrO78Ew0nZSgMMGrjbIJ4pFsHQEqXfgYLw3pNxg=="],
 
+    "@nuxt/eslint": ["@nuxt/eslint@1.11.0", "", { "dependencies": { "@eslint/config-inspector": "^1.4.2", "@nuxt/devtools-kit": "^3.1.1", "@nuxt/eslint-config": "1.11.0", "@nuxt/eslint-plugin": "1.11.0", "@nuxt/kit": "^4.2.1", "chokidar": "^5.0.0", "eslint-flat-config-utils": "^2.1.4", "eslint-typegen": "^2.3.0", "find-up": "^8.0.0", "get-port-please": "^3.2.0", "mlly": "^1.8.0", "pathe": "^2.0.3", "unimport": "^5.5.0" }, "peerDependencies": { "eslint": "^9.0.0", "eslint-webpack-plugin": "^4.1.0", "vite-plugin-eslint2": "^5.0.0" }, "optionalPeers": ["eslint-webpack-plugin", "vite-plugin-eslint2"] }, "sha512-N3jq7AL2rsalVoLs0hKFjba9kmfQ8yx2KwAxCzHwq0hhaFOhwnoTfEMJo8JcKyQ+DCbWy1f38jfBk5RJhKadBg=="],
+
+    "@nuxt/eslint-config": ["@nuxt/eslint-config@1.11.0", "", { "dependencies": { "@antfu/install-pkg": "^1.1.0", "@clack/prompts": "^0.11.0", "@eslint/js": "^9.39.1", "@nuxt/eslint-plugin": "1.11.0", "@stylistic/eslint-plugin": "^5.6.1", "@typescript-eslint/eslint-plugin": "^8.48.0", "@typescript-eslint/parser": "^8.48.0", "eslint-config-flat-gitignore": "^2.1.0", "eslint-flat-config-utils": "^2.1.4", "eslint-merge-processors": "^2.0.0", "eslint-plugin-import-lite": "^0.3.0", "eslint-plugin-import-x": "^4.16.1", "eslint-plugin-jsdoc": "^61.4.1", "eslint-plugin-regexp": "^2.10.0", "eslint-plugin-unicorn": "^62.0.0", "eslint-plugin-vue": "^10.6.1", "eslint-processor-vue-blocks": "^2.0.0", "globals": "^16.5.0", "local-pkg": "^1.1.2", "pathe": "^2.0.3", "vue-eslint-parser": "^10.2.0" }, "peerDependencies": { "eslint": "^9.0.0", "eslint-plugin-format": "*" }, "optionalPeers": ["eslint-plugin-format"] }, "sha512-SIe05zqUzwp/3mLW1AhUtCPdLVKjpNDO2ODxniReb5lsuRzSp7q9OQhjUhC1QqEM2ANH3q3b8Qui9YpxUg3nMA=="],
+
+    "@nuxt/eslint-plugin": ["@nuxt/eslint-plugin@1.11.0", "", { "dependencies": { "@typescript-eslint/types": "^8.48.0", "@typescript-eslint/utils": "^8.48.0" }, "peerDependencies": { "eslint": "^9.0.0" } }, "sha512-kTNwHJjdr5qW90ww4ct8kFKdWEVb/8X4KdkDJAmRTRqLRfkfTQDOKDfpQa62fRnsuRopMEPjab3Bsya4YLbb9g=="],
+
     "@nuxt/image": ["@nuxt/image@2.0.0", "", { "dependencies": { "@nuxt/kit": "^4.2.0", "consola": "^3.4.2", "defu": "^6.1.4", "h3": "^1.15.4", "image-meta": "^0.2.2", "knitwork": "^1.2.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "std-env": "^3.10.0", "ufo": "^1.6.1" }, "optionalDependencies": { "ipx": "^3.1.1" } }, "sha512-otHi6gAoYXKLrp8m27ZjX1PjxOPaltQ4OiUs/BhkW995mF/vXf8SWQTw68fww+Uric0v+XgoVrP9icDi+yT6zw=="],
 
     "@nuxt/kit": ["@nuxt/kit@4.2.1", "", { "dependencies": { "c12": "^3.3.1", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", "errx": "^0.1.0", "exsolve": "^1.0.7", "ignore": "^7.0.5", "jiti": "^2.6.1", "klona": "^2.0.6", "mlly": "^1.8.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "rc9": "^2.1.2", "scule": "^1.3.0", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ufo": "^1.6.1", "unctx": "^2.4.1", "untyped": "^2.0.0" } }, "sha512-lLt8KLHyl7IClc3RqRpRikz15eCfTRlAWL9leVzPyg5N87FfKE/7EWgWvpiL/z4Tf3dQCIqQb88TmHE0JTIDvA=="],
@@ -406,37 +424,37 @@
 
     "@oxc-minify/binding-win32-x64-msvc": ["@oxc-minify/binding-win32-x64-msvc@0.96.0", "", { "os": "win32", "cpu": "x64" }, "sha512-T2ijfqZLpV2bgGGocXV4SXTuMoouqN0asYTIm+7jVOLvT5XgDogf3ZvCmiEnSWmxl21+r5wHcs8voU2iUROXAg=="],
 
-    "@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.96.0", "", { "os": "android", "cpu": "arm64" }, "sha512-CofbPOiW1PG+hi8bgElJPK0ioHfw8nt4Vw9d+Q9JuMhygS6LbQyu1W6tIFZ1OPFofeFRdWus3vD29FBx+tvFOA=="],
+    "@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.99.0", "", { "os": "android", "cpu": "arm64" }, "sha512-V4jhmKXgQQdRnm73F+r3ZY4pUEsijQeSraFeaCGng7abSNJGs76X6l82wHnmjLGFAeY00LWtjcELs7ZmbJ9+lA=="],
 
-    "@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.96.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-+HZ2L1a/1BsUXYik8XqQwT2Tl5Z3jRQ/RRQiPV9UsB2skKyd91NLDlQlMpdhjLGs9Qe7Y42unFjRg2iHjIiwnw=="],
+    "@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.99.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Rp41nf9zD5FyLZciS9l1GfK8PhYqrD5kEGxyTOA2esTLeAy37rZxetG2E3xteEolAkeb2WDkVrlxPtibeAncMg=="],
 
-    "@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.96.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-GC8wH1W0XaCLyTeGsmyaMdnItiYQkqfTcn9Ygc55AWI+m11lCjQeoKDIsDCm/QwrKLCN07u3WWWsuPs5ubfXpA=="],
+    "@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.99.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-WVonp40fPPxo5Gs0POTI57iEFv485TvNKOHMwZRhigwZRhZY2accEAkYIhei9eswF4HN5B44Wybkz7Gd1Qr/5Q=="],
 
-    "@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.96.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-8SeXi2FmlN15uPY5oM03cua5RXBDYmY34Uewongv6RUiAaU/kWxLvzuijpyNC+yQ1r4fC2LbWJhAsKpX5qkA6g=="],
+    "@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.99.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-H30bjOOttPmG54gAqu6+HzbLEzuNOYO2jZYrIq4At+NtLJwvNhXz28Hf5iEAFZIH/4hMpLkM4VN7uc+5UlNW3Q=="],
 
-    "@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.96.0", "", { "os": "linux", "cpu": "arm" }, "sha512-UEs+Zf6T2/FwQlLgv7gfZsKmY19sl3hK57r2BQVc2eCmCmF/deeqDcWyFjzkNLgdDDucY60PoNhNGClDm605uQ=="],
+    "@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.99.0", "", { "os": "linux", "cpu": "arm" }, "sha512-0Z/Th0SYqzSRDPs6tk5lQdW0i73UCupnim3dgq2oW0//UdLonV/5wIZCArfKGC7w9y4h8TxgXpgtIyD1kKzzlQ=="],
 
-    "@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.96.0", "", { "os": "linux", "cpu": "arm" }, "sha512-1kuWvjR2+ORJMoyxt9LSbLcDhXZnL25XOuv9VmH6NmSPvLgewzuubSlm++W03x+U7SzWFilBsdwIHtD/0mjERw=="],
+    "@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.99.0", "", { "os": "linux", "cpu": "arm" }, "sha512-xo0wqNd5bpbzQVNpAIFbHk1xa+SaS/FGBABCd942SRTnrpxl6GeDj/s1BFaGcTl8MlwlKVMwOcyKrw/2Kdfquw=="],
 
-    "@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.96.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-PHH4ETR1t0fymxuhpQNj3Z9t/78/zZa2Lj3Z3I0ZOd+/Ex+gtdhGoB5xYyy7lcYGAPMfZ+Gmr+dTCr1GYNZ3BA=="],
+    "@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.99.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-u26I6LKoLTPTd4Fcpr0aoAtjnGf5/ulMllo+QUiBhupgbVCAlaj4RyXH/mvcjcsl2bVBv9E/gYJZz2JjxQWXBA=="],
 
-    "@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.96.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-fjDPbZjkqaDSTBe0FM8nZ9zBw4B/NF/I0gH7CfvNDwIj9smISaNFypYeomkvubORpnbX9ORhvhYwg3TxQ60OGA=="],
+    "@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.99.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-qhftDo2D37SqCEl3ZTa367NqWSZNb1Ddp34CTmShLKFrnKdNiUn55RdokLnHtf1AL5ssaQlYDwBECX7XiBWOhw=="],
 
-    "@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.96.0", "", { "os": "linux", "cpu": "none" }, "sha512-59KAHd/6/LmjkdSAuJn0piKmwSavMasWNUKuYLX/UnqI5KkGIp14+LBwwaBG6KzOtIq1NrRCnmlL4XSEaNkzTg=="],
+    "@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.99.0", "", { "os": "linux", "cpu": "none" }, "sha512-zxn/xkf519f12FKkpL5XwJipsylfSSnm36h6c1zBDTz4fbIDMGyIhHfWfwM7uUmHo9Aqw1pLxFpY39Etv398+Q=="],
 
-    "@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.96.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-VtupojtgahY8XmLwpVpM3C1WQEgMD1JxpB8lzUtdSLwosWaaz1EAl+VXWNuxTTZusNuLBtmR+F0qql22ISi/9g=="],
+    "@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.99.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-Y1eSDKDS5E4IVC7Oxw+NbYAKRmJPMJTIjW+9xOWwteDHkFqpocKe0USxog+Q1uhzalD9M0p9eXWEWdGQCMDBMQ=="],
 
-    "@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.96.0", "", { "os": "linux", "cpu": "x64" }, "sha512-8XSY9aUYY+5I4I1mhSEWmYqdUrJi3J5cCAInvEVHyTnDAPkhb+tnLGVZD696TpW+lFOLrTFF2V5GMWJVafqIUA=="],
+    "@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.99.0", "", { "os": "linux", "cpu": "x64" }, "sha512-YVJMfk5cFWB8i2/nIrbk6n15bFkMHqWnMIWkVx7r2KwpTxHyFMfu2IpeVKo1ITDSmt5nBrGdLHD36QRlu2nDLg=="],
 
-    "@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.96.0", "", { "os": "linux", "cpu": "x64" }, "sha512-IIVNtqhA0uxKkD8Y6aZinKO/sOD5O62VlduE54FnUU2rzZEszrZQLL8nMGVZhTdPaKW5M1aeLmjcdnOs6er1Jg=="],
+    "@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.99.0", "", { "os": "linux", "cpu": "x64" }, "sha512-2+SDPrie5f90A1b9EirtVggOgsqtsYU5raZwkDYKyS1uvJzjqHCDhG/f4TwQxHmIc5YkczdQfwvN91lwmjsKYQ=="],
 
-    "@oxc-parser/binding-wasm32-wasi": ["@oxc-parser/binding-wasm32-wasi@0.96.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.0.7" }, "cpu": "none" }, "sha512-TJ/sNPbVD4u6kUwm7sDKa5iRDEB8vd7ZIMjYqFrrAo9US1RGYOSvt6Ie9sDRekUL9fZhNsykvSrpmIj6dg/C2w=="],
+    "@oxc-parser/binding-wasm32-wasi": ["@oxc-parser/binding-wasm32-wasi@0.99.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.0.7" }, "cpu": "none" }, "sha512-DKA4j0QerUWSMADziLM5sAyM7V53Fj95CV9SjP77bPfEfT7MnvFKnneaRMqPK1cpzjAGiQF52OBUIKyk0dwOQA=="],
 
-    "@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.96.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-zCOhRB7MYVIHLj+2QYoTuLyaipiD8JG/ggUjfsMUaupRPpvwQNhsxINLIcTcb0AS+OsT7/OREhydjO74STqQzQ=="],
+    "@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.99.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-EaB3AvsxqdNUhh9FOoAxRZ2L4PCRwDlDb//QXItwyOJrX7XS+uGK9B1KEUV4FZ/7rDhHsWieLt5e07wl2Ti5AQ=="],
 
-    "@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.96.0", "", { "os": "win32", "cpu": "x64" }, "sha512-J6zfx9TE0oS+TrqBUjMVMOi/d/j3HMj69Pip263pETOEPm788N0HXKPsc2X2jUfSTHzD9vmdjq0QFymbf2LhWg=="],
+    "@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.99.0", "", { "os": "win32", "cpu": "x64" }, "sha512-sJN1Q8h7ggFOyDn0zsHaXbP/MklAVUvhrbq0LA46Qum686P3SZQHjbATqJn9yaVEvaSKXCshgl0vQ1gWkGgpcQ=="],
 
-    "@oxc-project/types": ["@oxc-project/types@0.96.0", "", {}, "sha512-r/xkmoXA0xEpU6UGtn18CNVjXH6erU3KCpCDbpLmbVxBFor1U9MqN5Z2uMmCHJuXjJzlnDR+hWY+yPoLo8oHDw=="],
+    "@oxc-project/types": ["@oxc-project/types@0.99.0", "", {}, "sha512-LLDEhXB7g1m5J+woRSgfKsFPS3LhR9xRhTeIoEBm5WrkwMxn6eZ0Ld0c0K5eHB57ChZX6I3uSmmLjZ8pcjlRcw=="],
 
     "@oxc-transform/binding-android-arm64": ["@oxc-transform/binding-android-arm64@0.96.0", "", { "os": "android", "cpu": "arm64" }, "sha512-wOm+ZsqFvyZ7B9RefUMsj0zcXw77Z2pXA51nbSQyPXqr+g0/pDGxriZWP8Sdpz/e4AEaKPA9DvrwyOZxu7GRDQ=="],
 
@@ -736,6 +754,44 @@
 
     "@unocss/rule-utils": ["@unocss/rule-utils@66.5.9", "", { "dependencies": { "@unocss/core": "^66.5.9", "magic-string": "^0.30.21" } }, "sha512-ZdtWqbOaNQLf6NFhcEkvaBf0fjm5GZP5NV/plmQEqK6ehe1TTpaqOtO0LBFD2BUy72oXlcsFnvdgWt/CpL6FLg=="],
 
+    "@unrs/resolver-binding-android-arm-eabi": ["@unrs/resolver-binding-android-arm-eabi@1.11.1", "", { "os": "android", "cpu": "arm" }, "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw=="],
+
+    "@unrs/resolver-binding-android-arm64": ["@unrs/resolver-binding-android-arm64@1.11.1", "", { "os": "android", "cpu": "arm64" }, "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g=="],
+
+    "@unrs/resolver-binding-darwin-arm64": ["@unrs/resolver-binding-darwin-arm64@1.11.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g=="],
+
+    "@unrs/resolver-binding-darwin-x64": ["@unrs/resolver-binding-darwin-x64@1.11.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ=="],
+
+    "@unrs/resolver-binding-freebsd-x64": ["@unrs/resolver-binding-freebsd-x64@1.11.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw=="],
+
+    "@unrs/resolver-binding-linux-arm-gnueabihf": ["@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1", "", { "os": "linux", "cpu": "arm" }, "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw=="],
+
+    "@unrs/resolver-binding-linux-arm-musleabihf": ["@unrs/resolver-binding-linux-arm-musleabihf@1.11.1", "", { "os": "linux", "cpu": "arm" }, "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw=="],
+
+    "@unrs/resolver-binding-linux-arm64-gnu": ["@unrs/resolver-binding-linux-arm64-gnu@1.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ=="],
+
+    "@unrs/resolver-binding-linux-arm64-musl": ["@unrs/resolver-binding-linux-arm64-musl@1.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w=="],
+
+    "@unrs/resolver-binding-linux-ppc64-gnu": ["@unrs/resolver-binding-linux-ppc64-gnu@1.11.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA=="],
+
+    "@unrs/resolver-binding-linux-riscv64-gnu": ["@unrs/resolver-binding-linux-riscv64-gnu@1.11.1", "", { "os": "linux", "cpu": "none" }, "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ=="],
+
+    "@unrs/resolver-binding-linux-riscv64-musl": ["@unrs/resolver-binding-linux-riscv64-musl@1.11.1", "", { "os": "linux", "cpu": "none" }, "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew=="],
+
+    "@unrs/resolver-binding-linux-s390x-gnu": ["@unrs/resolver-binding-linux-s390x-gnu@1.11.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg=="],
+
+    "@unrs/resolver-binding-linux-x64-gnu": ["@unrs/resolver-binding-linux-x64-gnu@1.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w=="],
+
+    "@unrs/resolver-binding-linux-x64-musl": ["@unrs/resolver-binding-linux-x64-musl@1.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA=="],
+
+    "@unrs/resolver-binding-wasm32-wasi": ["@unrs/resolver-binding-wasm32-wasi@1.11.1", "", { "dependencies": { "@napi-rs/wasm-runtime": "^0.2.11" }, "cpu": "none" }, "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ=="],
+
+    "@unrs/resolver-binding-win32-arm64-msvc": ["@unrs/resolver-binding-win32-arm64-msvc@1.11.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw=="],
+
+    "@unrs/resolver-binding-win32-ia32-msvc": ["@unrs/resolver-binding-win32-ia32-msvc@1.11.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ=="],
+
+    "@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g=="],
+
     "@vercel/nft": ["@vercel/nft@0.30.4", "", { "dependencies": { "@mapbox/node-pre-gyp": "^2.0.0", "@rollup/pluginutils": "^5.1.3", "acorn": "^8.6.0", "acorn-import-attributes": "^1.9.5", "async-sema": "^3.1.1", "bindings": "^1.4.0", "estree-walker": "2.0.2", "glob": "^10.5.0", "graceful-fs": "^4.2.9", "node-gyp-build": "^4.2.2", "picomatch": "^4.0.2", "resolve-from": "^5.0.0" }, "bin": { "nft": "out/cli.js" } }, "sha512-wE6eAGSXScra60N2l6jWvNtVK0m+sh873CpfZW4KI2v8EHuUQp+mSEi4T+IcdPCSEDgCdAS/7bizbhQlkjzrSA=="],
 
     "@vitejs/plugin-vue": ["@vitejs/plugin-vue@6.0.2", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-beta.50" }, "peerDependencies": { "vite": "^5.0.0 || ^6.0.0 || ^7.0.0", "vue": "^3.2.25" } }, "sha512-iHmwV3QcVGGvSC1BG5bZ4z6iwa1SOpAPWmnjOErd4Ske+lZua5K9TtAVdx0gMBClJ28DViCbSmZitjWZsWO3LA=="],
@@ -788,11 +844,11 @@
 
     "@vue/shared": ["@vue/shared@3.5.25", "", {}, "sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg=="],
 
-    "@vueuse/core": ["@vueuse/core@13.9.0", "", { "dependencies": { "@types/web-bluetooth": "^0.0.21", "@vueuse/metadata": "13.9.0", "@vueuse/shared": "13.9.0" }, "peerDependencies": { "vue": "^3.5.0" } }, "sha512-ts3regBQyURfCE2BcytLqzm8+MmLlo5Ln/KLoxDVcsZ2gzIwVNnQpQOL/UKV8alUqjSZOlpFZcRNsLRqj+OzyA=="],
+    "@vueuse/core": ["@vueuse/core@14.1.0", "", { "dependencies": { "@types/web-bluetooth": "^0.0.21", "@vueuse/metadata": "14.1.0", "@vueuse/shared": "14.1.0" }, "peerDependencies": { "vue": "^3.5.0" } }, "sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw=="],
 
-    "@vueuse/metadata": ["@vueuse/metadata@13.9.0", "", {}, "sha512-1AFRvuiGphfF7yWixZa0KwjYH8ulyjDCC0aFgrGRz8+P4kvDFSdXLVfTk5xAN9wEuD1J6z4/myMoYbnHoX07zg=="],
+    "@vueuse/metadata": ["@vueuse/metadata@14.1.0", "", {}, "sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA=="],
 
-    "@vueuse/shared": ["@vueuse/shared@13.9.0", "", { "peerDependencies": { "vue": "^3.5.0" } }, "sha512-e89uuTLMh0U5cZ9iDpEI2senqPGfbPRTHM/0AaQkcxnpqjkZqDYP8rpfm7edOz8s+pOCOROEy1PIveSW8+fL5g=="],
+    "@vueuse/shared": ["@vueuse/shared@14.1.0", "", { "peerDependencies": { "vue": "^3.5.0" } }, "sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw=="],
 
     "@webcontainer/env": ["@webcontainer/env@1.1.1", "", {}, "sha512-6aN99yL695Hi9SuIk1oC88l9o0gmxL1nGWWQ/kNy81HigJ0FoaoTXpytCj6ItzgyCEwA9kF1wixsTuv5cjsgng=="],
 
@@ -878,6 +934,8 @@
 
     "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="],
 
+    "bundle-require": ["bundle-require@5.1.0", "", { "dependencies": { "load-tsconfig": "^0.2.3" }, "peerDependencies": { "esbuild": ">=0.18" } }, "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA=="],
+
     "c12": ["c12@3.3.2", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.3", "exsolve": "^1.0.8", "giget": "^2.0.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "*" }, "optionalPeers": ["magicast"] }, "sha512-QkikB2X5voO1okL3QsES0N690Sn/K9WokXqUsDQsWy5SnYb+psYQFGA10iy1bZHj3fjISKsI67Q90gruvWWM3A=="],
 
     "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],
@@ -1118,6 +1176,8 @@
 
     "eslint-formatting-reporter": ["eslint-formatting-reporter@0.0.0", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0" }, "peerDependencies": { "eslint": ">=8.40.0" } }, "sha512-k9RdyTqxqN/wNYVaTk/ds5B5rA8lgoAmvceYN7bcZMBwU7TuXx5ntewJv81eF3pIL/CiJE+pJZm36llG8yhyyw=="],
 
+    "eslint-import-context": ["eslint-import-context@0.1.9", "", { "dependencies": { "get-tsconfig": "^4.10.1", "stable-hash-x": "^0.2.0" }, "peerDependencies": { "unrs-resolver": "^1.0.0" }, "optionalPeers": ["unrs-resolver"] }, "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg=="],
+
     "eslint-json-compat-utils": ["eslint-json-compat-utils@0.2.1", "", { "dependencies": { "esquery": "^1.6.0" }, "peerDependencies": { "eslint": "*", "jsonc-eslint-parser": "^2.4.0" } }, "sha512-YzEodbDyW8DX8bImKhAcCeu/L31Dd/70Bidx2Qex9OFUtgzXLqtfWL4Hr5fM/aCCB8QUZLuJur0S9k6UfgFkfg=="],
 
     "eslint-merge-processors": ["eslint-merge-processors@2.0.0", "", { "peerDependencies": { "eslint": "*" } }, "sha512-sUuhSf3IrJdGooquEUB5TNpGNpBoQccbnaLHsb1XkBLUPPqCNivCpY05ZcpCOiV9uHwO2yxXEWVczVclzMxYlA=="],
@@ -1134,6 +1194,8 @@
 
     "eslint-plugin-import-lite": ["eslint-plugin-import-lite@0.3.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/types": "^8.34.0" }, "peerDependencies": { "eslint": ">=9.0.0", "typescript": ">=4.5" }, "optionalPeers": ["typescript"] }, "sha512-dkNBAL6jcoCsXZsQ/Tt2yXmMDoNt5NaBh/U7yvccjiK8cai6Ay+MK77bMykmqQA2bTF6lngaLCDij6MTO3KkvA=="],
 
+    "eslint-plugin-import-x": ["eslint-plugin-import-x@4.16.1", "", { "dependencies": { "@typescript-eslint/types": "^8.35.0", "comment-parser": "^1.4.1", "debug": "^4.4.1", "eslint-import-context": "^0.1.9", "is-glob": "^4.0.3", "minimatch": "^9.0.3 || ^10.0.1", "semver": "^7.7.2", "stable-hash-x": "^0.2.0", "unrs-resolver": "^1.9.2" }, "peerDependencies": { "@typescript-eslint/utils": "^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "eslint-import-resolver-node": "*" }, "optionalPeers": ["@typescript-eslint/utils", "eslint-import-resolver-node"] }, "sha512-vPZZsiOKaBAIATpFE2uMI4w5IRwdv/FpQ+qZZMR4E+PeOcM4OeoEbqxRMnywdxP19TyB/3h6QBB0EWon7letSQ=="],
+
     "eslint-plugin-jsdoc": ["eslint-plugin-jsdoc@61.4.1", "", { "dependencies": { "@es-joy/jsdoccomment": "~0.76.0", "@es-joy/resolve.exports": "1.2.0", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", "debug": "^4.4.3", "escape-string-regexp": "^4.0.0", "espree": "^10.4.0", "esquery": "^1.6.0", "html-entities": "^2.6.0", "object-deep-merge": "^2.0.0", "parse-imports-exports": "^0.2.4", "semver": "^7.7.3", "spdx-expression-parse": "^4.0.0", "to-valid-identifier": "^1.0.0" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, "sha512-3c1QW/bV25sJ1MsIvsvW+EtLtN6yZMduw7LVQNVt72y2/5BbV5Pg5b//TE5T48LRUxoEQGaZJejCmcj3wCxBzw=="],
 
     "eslint-plugin-jsonc": ["eslint-plugin-jsonc@2.21.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.5.1", "diff-sequences": "^27.5.1", "eslint-compat-utils": "^0.6.4", "eslint-json-compat-utils": "^0.2.1", "espree": "^9.6.1 || ^10.3.0", "graphemer": "^1.4.0", "jsonc-eslint-parser": "^2.4.0", "natural-compare": "^1.4.0", "synckit": "^0.6.2 || ^0.7.3 || ^0.11.5" }, "peerDependencies": { "eslint": ">=6.0.0" } }, "sha512-HttlxdNG5ly3YjP1cFMP62R4qKLxJURfBZo2gnMY+yQojZxkLyOpY1H1KRTKBmvQeSG9pIpSGEhDjE17vvYosg=="],
@@ -1162,6 +1224,8 @@
 
     "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
 
+    "eslint-typegen": ["eslint-typegen@2.3.0", "", { "dependencies": { "json-schema-to-typescript-lite": "^15.0.0", "ohash": "^2.0.11" }, "peerDependencies": { "eslint": "^9.0.0" } }, "sha512-azYgAvhlz1AyTpeLfVSKcrNJInuIsRrcUrOcHmEl8T9oMKesePVUPrF8gRgE6azV8CAlFzxJDTyaXAAbA/BYiA=="],
+
     "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
 
     "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
@@ -1446,6 +1510,8 @@
 
     "json-schema-to-typescript": ["json-schema-to-typescript@15.0.4", "", { "dependencies": { "@apidevtools/json-schema-ref-parser": "^11.5.5", "@types/json-schema": "^7.0.15", "@types/lodash": "^4.17.7", "is-glob": "^4.0.3", "js-yaml": "^4.1.0", "lodash": "^4.17.21", "minimist": "^1.2.8", "prettier": "^3.2.5", "tinyglobby": "^0.2.9" }, "bin": { "json2ts": "dist/src/cli.js" } }, "sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ=="],
 
+    "json-schema-to-typescript-lite": ["json-schema-to-typescript-lite@15.0.0", "", { "dependencies": { "@apidevtools/json-schema-ref-parser": "^14.1.1", "@types/json-schema": "^7.0.15" } }, "sha512-5mMORSQm9oTLyjM4mWnyNBi2T042Fhg1/0gCIB6X8U/LVpM2A+Nmj2yEyArqVouDmFThDxpEXcnTgSrjkGJRFA=="],
+
     "json-schema-to-zod": ["json-schema-to-zod@2.7.0", "", { "bin": { "json-schema-to-zod": "dist/cjs/cli.js" } }, "sha512-eW59l3NQ6sa3HcB+Ahf7pP6iGU7MY4we5JsPqXQ2ZcIPF8QxSg/lkY8lN0Js/AG0NjMbk+nZGUfHlceiHF+bwQ=="],
 
     "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
@@ -1502,6 +1568,8 @@
 
     "listhen": ["listhen@1.9.0", "", { "dependencies": { "@parcel/watcher": "^2.4.1", "@parcel/watcher-wasm": "^2.4.1", "citty": "^0.1.6", "clipboardy": "^4.0.0", "consola": "^3.2.3", "crossws": ">=0.2.0 <0.4.0", "defu": "^6.1.4", "get-port-please": "^3.1.2", "h3": "^1.12.0", "http-shutdown": "^1.2.2", "jiti": "^2.1.2", "mlly": "^1.7.1", "node-forge": "^1.3.1", "pathe": "^1.1.2", "std-env": "^3.7.0", "ufo": "^1.5.4", "untun": "^0.1.3", "uqr": "^0.1.2" }, "bin": { "listen": "bin/listhen.mjs", "listhen": "bin/listhen.mjs" } }, "sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg=="],
 
+    "load-tsconfig": ["load-tsconfig@0.2.5", "", {}, "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg=="],
+
     "local-pkg": ["local-pkg@1.1.2", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.3.0", "quansync": "^0.2.11" } }, "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A=="],
 
     "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
@@ -1522,7 +1590,7 @@
 
     "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
 
-    "lucide-vue-next": ["lucide-vue-next@0.553.0", "", { "peerDependencies": { "vue": ">=3.0.1" } }, "sha512-0tg9XT+VCElTT+7EXXbBRhWe1nU7Doa32Xv/dHP5/LCleFVgV6cAqziM3C7AetqmsYIsfAtNwRYdtvs4Ds7aUg=="],
+    "lucide-vue-next": ["lucide-vue-next@0.555.0", "", { "peerDependencies": { "vue": ">=3.0.1" } }, "sha512-7hczPsiMD/y+VNLpal5Q5Wv09kQxlHS0l/cM1xagrd+MA3i5umMm+PUXqllvsbgwAl3PHv27fo59h4PN02GM5A=="],
 
     "magic-regexp": ["magic-regexp@0.10.0", "", { "dependencies": { "estree-walker": "^3.0.3", "magic-string": "^0.30.12", "mlly": "^1.7.2", "regexp-tree": "^0.1.27", "type-level-regexp": "~0.1.17", "ufo": "^1.5.4", "unplugin": "^2.0.0" } }, "sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg=="],
 
@@ -1670,6 +1738,8 @@
 
     "napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="],
 
+    "napi-postinstall": ["napi-postinstall@0.3.4", "", { "bin": { "napi-postinstall": "lib/cli.js" } }, "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ=="],
+
     "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
 
     "natural-orderby": ["natural-orderby@5.0.0", "", {}, "sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg=="],
@@ -1746,7 +1816,7 @@
 
     "oxc-minify": ["oxc-minify@0.96.0", "", { "optionalDependencies": { "@oxc-minify/binding-android-arm64": "0.96.0", "@oxc-minify/binding-darwin-arm64": "0.96.0", "@oxc-minify/binding-darwin-x64": "0.96.0", "@oxc-minify/binding-freebsd-x64": "0.96.0", "@oxc-minify/binding-linux-arm-gnueabihf": "0.96.0", "@oxc-minify/binding-linux-arm-musleabihf": "0.96.0", "@oxc-minify/binding-linux-arm64-gnu": "0.96.0", "@oxc-minify/binding-linux-arm64-musl": "0.96.0", "@oxc-minify/binding-linux-riscv64-gnu": "0.96.0", "@oxc-minify/binding-linux-s390x-gnu": "0.96.0", "@oxc-minify/binding-linux-x64-gnu": "0.96.0", "@oxc-minify/binding-linux-x64-musl": "0.96.0", "@oxc-minify/binding-wasm32-wasi": "0.96.0", "@oxc-minify/binding-win32-arm64-msvc": "0.96.0", "@oxc-minify/binding-win32-x64-msvc": "0.96.0" } }, "sha512-dXeeGrfPJJ4rMdw+NrqiCRtbzVX2ogq//R0Xns08zql2HjV3Zi2SBJ65saqfDaJzd2bcHqvGWH+M44EQCHPAcA=="],
 
-    "oxc-parser": ["oxc-parser@0.96.0", "", { "dependencies": { "@oxc-project/types": "^0.96.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm64": "0.96.0", "@oxc-parser/binding-darwin-arm64": "0.96.0", "@oxc-parser/binding-darwin-x64": "0.96.0", "@oxc-parser/binding-freebsd-x64": "0.96.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.96.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.96.0", "@oxc-parser/binding-linux-arm64-gnu": "0.96.0", "@oxc-parser/binding-linux-arm64-musl": "0.96.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.96.0", "@oxc-parser/binding-linux-s390x-gnu": "0.96.0", "@oxc-parser/binding-linux-x64-gnu": "0.96.0", "@oxc-parser/binding-linux-x64-musl": "0.96.0", "@oxc-parser/binding-wasm32-wasi": "0.96.0", "@oxc-parser/binding-win32-arm64-msvc": "0.96.0", "@oxc-parser/binding-win32-x64-msvc": "0.96.0" } }, "sha512-ucs6niJ5mZlYP3oTl4AK2eD2m7WLoSaljswnSFVYWrXzme5PtM97S7Ve1Tjx+/TKjanmEZuSt1f1qYi6SZvntw=="],
+    "oxc-parser": ["oxc-parser@0.99.0", "", { "dependencies": { "@oxc-project/types": "^0.99.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm64": "0.99.0", "@oxc-parser/binding-darwin-arm64": "0.99.0", "@oxc-parser/binding-darwin-x64": "0.99.0", "@oxc-parser/binding-freebsd-x64": "0.99.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.99.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.99.0", "@oxc-parser/binding-linux-arm64-gnu": "0.99.0", "@oxc-parser/binding-linux-arm64-musl": "0.99.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.99.0", "@oxc-parser/binding-linux-s390x-gnu": "0.99.0", "@oxc-parser/binding-linux-x64-gnu": "0.99.0", "@oxc-parser/binding-linux-x64-musl": "0.99.0", "@oxc-parser/binding-wasm32-wasi": "0.99.0", "@oxc-parser/binding-win32-arm64-msvc": "0.99.0", "@oxc-parser/binding-win32-x64-msvc": "0.99.0" } }, "sha512-MpS1lbd2vR0NZn1v0drpgu7RUFu3x9Rd0kxExObZc2+F+DIrV0BOMval/RO3BYGwssIOerII6iS8EbbpCCZQpQ=="],
 
     "oxc-transform": ["oxc-transform@0.96.0", "", { "optionalDependencies": { "@oxc-transform/binding-android-arm64": "0.96.0", "@oxc-transform/binding-darwin-arm64": "0.96.0", "@oxc-transform/binding-darwin-x64": "0.96.0", "@oxc-transform/binding-freebsd-x64": "0.96.0", "@oxc-transform/binding-linux-arm-gnueabihf": "0.96.0", "@oxc-transform/binding-linux-arm-musleabihf": "0.96.0", "@oxc-transform/binding-linux-arm64-gnu": "0.96.0", "@oxc-transform/binding-linux-arm64-musl": "0.96.0", "@oxc-transform/binding-linux-riscv64-gnu": "0.96.0", "@oxc-transform/binding-linux-s390x-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-musl": "0.96.0", "@oxc-transform/binding-wasm32-wasi": "0.96.0", "@oxc-transform/binding-win32-arm64-msvc": "0.96.0", "@oxc-transform/binding-win32-x64-msvc": "0.96.0" } }, "sha512-dQPNIF+gHpSkmC0+Vg9IktNyhcn28Y8R3eTLyzn52UNymkasLicl3sFAtz7oEVuFmCpgGjaUTKkwk+jW2cHpDQ=="],
 
@@ -2014,6 +2084,8 @@
 
     "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
 
+    "shadcn-nuxt": ["shadcn-nuxt@2.3.3", "", { "dependencies": { "@nuxt/kit": "^3.17.4", "oxc-parser": "^0.97.0" } }, "sha512-zx2mwC68aKRmPjG6iB0SFh+zguNQxLH7SXeY9xGIcmXTAz1HJhnu7gjj5/PcPbZqNm3Sbsj1F3Tvt77glfC6Pw=="],
+
     "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="],
 
     "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
@@ -2068,6 +2140,8 @@
 
     "srvx": ["srvx@0.9.6", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-5L4rT6qQqqb+xcoDoklUgCNdmzqJ6vbcDRwPVGRXewF55IJH0pqh0lQlrJ266ZWTKJ4mfeioqHQJeAYesS+RrQ=="],
 
+    "stable-hash-x": ["stable-hash-x@0.2.0", "", {}, "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ=="],
+
     "standard-as-callback": ["standard-as-callback@2.1.0", "", {}, "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="],
 
     "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
@@ -2216,10 +2290,12 @@
 
     "unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
 
-    "unplugin-utils": ["unplugin-utils@0.2.5", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-gwXJnPRewT4rT7sBi/IvxKTjsms7jX7QIDLOClApuZwR49SXbrB1z2NLUZ+vDHyqCj/n58OzRRqaW+B8OZi8vg=="],
+    "unplugin-utils": ["unplugin-utils@0.3.1", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog=="],
 
     "unplugin-vue-router": ["unplugin-vue-router@0.16.2", "", { "dependencies": { "@babel/generator": "^7.28.5", "@vue-macros/common": "^3.1.1", "@vue/language-core": "^3.1.3", "ast-walker-scope": "^0.8.3", "chokidar": "^4.0.3", "json5": "^2.2.3", "local-pkg": "^1.1.2", "magic-string": "^0.30.21", "mlly": "^1.8.0", "muggle-string": "^0.4.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "scule": "^1.3.0", "tinyglobby": "^0.2.15", "unplugin": "^2.3.10", "unplugin-utils": "^0.3.1", "yaml": "^2.8.1" }, "peerDependencies": { "@vue/compiler-sfc": "^3.5.17", "vue-router": "^4.6.0" }, "optionalPeers": ["vue-router"] }, "sha512-lE6ZjnHaXfS2vFI/PSEwdKcdOo5RwAbCKUnPBIN9YwLgSWas3x+qivzQvJa/uxhKzJldE6WK43aDKjGj9Rij9w=="],
 
+    "unrs-resolver": ["unrs-resolver@1.11.1", "", { "dependencies": { "napi-postinstall": "^0.3.0" }, "optionalDependencies": { "@unrs/resolver-binding-android-arm-eabi": "1.11.1", "@unrs/resolver-binding-android-arm64": "1.11.1", "@unrs/resolver-binding-darwin-arm64": "1.11.1", "@unrs/resolver-binding-darwin-x64": "1.11.1", "@unrs/resolver-binding-freebsd-x64": "1.11.1", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-musl": "1.11.1", "@unrs/resolver-binding-wasm32-wasi": "1.11.1", "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg=="],
+
     "unstorage": ["unstorage@1.17.3", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.4", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.1" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q=="],
 
     "untun": ["untun@0.1.3", "", { "dependencies": { "citty": "^0.1.5", "consola": "^3.2.3", "pathe": "^1.1.1" }, "bin": { "untun": "bin/untun.mjs" } }, "sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ=="],
@@ -2350,6 +2426,8 @@
 
     "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
 
+    "@eslint/config-inspector/esbuild": ["esbuild@0.27.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.0", "@esbuild/android-arm": "0.27.0", "@esbuild/android-arm64": "0.27.0", "@esbuild/android-x64": "0.27.0", "@esbuild/darwin-arm64": "0.27.0", "@esbuild/darwin-x64": "0.27.0", "@esbuild/freebsd-arm64": "0.27.0", "@esbuild/freebsd-x64": "0.27.0", "@esbuild/linux-arm": "0.27.0", "@esbuild/linux-arm64": "0.27.0", "@esbuild/linux-ia32": "0.27.0", "@esbuild/linux-loong64": "0.27.0", "@esbuild/linux-mips64el": "0.27.0", "@esbuild/linux-ppc64": "0.27.0", "@esbuild/linux-riscv64": "0.27.0", "@esbuild/linux-s390x": "0.27.0", "@esbuild/linux-x64": "0.27.0", "@esbuild/netbsd-arm64": "0.27.0", "@esbuild/netbsd-x64": "0.27.0", "@esbuild/openbsd-arm64": "0.27.0", "@esbuild/openbsd-x64": "0.27.0", "@esbuild/openharmony-arm64": "0.27.0", "@esbuild/sunos-x64": "0.27.0", "@esbuild/win32-arm64": "0.27.0", "@esbuild/win32-ia32": "0.27.0", "@esbuild/win32-x64": "0.27.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA=="],
+
     "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
 
     "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
@@ -2360,18 +2438,18 @@
 
     "@nuxt/content/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="],
 
-    "@nuxt/devtools/@nuxt/devtools-kit": ["@nuxt/devtools-kit@3.1.1", "", { "dependencies": { "@nuxt/kit": "^4.2.1", "execa": "^8.0.1" }, "peerDependencies": { "vite": ">=6.0" } }, "sha512-sjiKFeDCOy1SyqezSgyV4rYNfQewC64k/GhOsuJgRF+wR2qr6KTVhO6u2B+csKs74KrMrnJprQBgud7ejvOXAQ=="],
-
     "@nuxt/devtools/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
 
     "@nuxt/devtools/which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="],
 
-    "@nuxt/devtools-kit/@nuxt/kit": ["@nuxt/kit@3.20.1", "", { "dependencies": { "c12": "^3.3.1", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", "errx": "^0.1.0", "exsolve": "^1.0.7", "ignore": "^7.0.5", "jiti": "^2.6.1", "klona": "^2.0.6", "knitwork": "^1.2.0", "mlly": "^1.8.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "rc9": "^2.1.2", "scule": "^1.3.0", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ufo": "^1.6.1", "unctx": "^2.4.1", "untyped": "^2.0.0" } }, "sha512-TIslaylfI5kd3AxX5qts0qyrIQ9Uq3HAA1bgIIJ+c+zpDfK338YS+YrCWxBBzDMECRCbAS58mqAd2MtJfG1ENA=="],
-
     "@nuxt/devtools-kit/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
 
     "@nuxt/devtools-wizard/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
 
+    "@nuxt/eslint/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
+
+    "@nuxt/eslint/find-up": ["find-up@8.0.0", "", { "dependencies": { "locate-path": "^8.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-JGG8pvDi2C+JxidYdIwQDyS/CgcrIdh18cvgxcBge3wSHRQOrooMD3GlFBcmMJAN9M42SAZjDp5zv1dglJjwww=="],
+
     "@nuxt/kit/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
 
     "@nuxt/nitro-server/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
@@ -2414,12 +2492,12 @@
 
     "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
 
+    "@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="],
+
     "@vercel/nft/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
 
     "@vercel/nft/resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
 
-    "@vue-macros/common/unplugin-utils": ["unplugin-utils@0.3.1", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog=="],
-
     "@vue/compiler-core/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
 
     "@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
@@ -2462,6 +2540,8 @@
 
     "eslint-plugin-es-x/eslint-compat-utils": ["eslint-compat-utils@0.5.1", "", { "dependencies": { "semver": "^7.5.4" }, "peerDependencies": { "eslint": ">=6.0.0" } }, "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q=="],
 
+    "eslint-plugin-import-x/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="],
+
     "eslint-plugin-jsdoc/@es-joy/jsdoccomment": ["@es-joy/jsdoccomment@0.76.0", "", { "dependencies": { "@types/estree": "^1.0.8", "@typescript-eslint/types": "^8.46.0", "comment-parser": "1.4.1", "esquery": "^1.6.0", "jsdoc-type-pratt-parser": "~6.10.0" } }, "sha512-g+RihtzFgGTx2WYCuTHbdOXJeAlGnROws0TeALx9ow/ZmOROOZkVg5wp/B44n0WJgI4SQFP1eWM2iRPlU2Y14w=="],
 
     "eslint-plugin-jsonc/synckit": ["synckit@0.11.11", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw=="],
@@ -2482,8 +2562,12 @@
 
     "hast-util-to-parse5/property-information": ["property-information@6.5.0", "", {}, "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig=="],
 
+    "impound/unplugin-utils": ["unplugin-utils@0.2.5", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-gwXJnPRewT4rT7sBi/IvxKTjsms7jX7QIDLOClApuZwR49SXbrB1z2NLUZ+vDHyqCj/n58OzRRqaW+B8OZi8vg=="],
+
     "is-wsl/is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="],
 
+    "json-schema-to-typescript-lite/@apidevtools/json-schema-ref-parser": ["@apidevtools/json-schema-ref-parser@14.2.1", "", { "dependencies": { "js-yaml": "^4.1.0" }, "peerDependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-HmdFw9CDYqM6B25pqGBpNeLCKvGPlIx1EbLrVL0zPvj50CJQUHyBNBw45Muk0kEIkogo1VZvOKHajdMuAzSxRg=="],
+
     "jsonc-eslint-parser/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
 
     "jsonc-eslint-parser/espree": ["espree@9.6.1", "", { "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" } }, "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ=="],
@@ -2502,14 +2586,16 @@
 
     "nitropack/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
 
-    "nitropack/unplugin-utils": ["unplugin-utils@0.3.1", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog=="],
-
     "nitropack/unwasm": ["unwasm@0.3.11", "", { "dependencies": { "knitwork": "^1.2.0", "magic-string": "^0.30.17", "mlly": "^1.7.4", "pathe": "^2.0.3", "pkg-types": "^2.2.0", "unplugin": "^2.3.6" } }, "sha512-Vhp5gb1tusSQw5of/g3Q697srYgMXvwMgXMjcG4ZNga02fDX9coxJ9fAb0Ci38hM2Hv/U1FXRPGgjP2BYqhNoQ=="],
 
     "nuxt/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
 
     "nuxt/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
 
+    "nuxt/oxc-parser": ["oxc-parser@0.96.0", "", { "dependencies": { "@oxc-project/types": "^0.96.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm64": "0.96.0", "@oxc-parser/binding-darwin-arm64": "0.96.0", "@oxc-parser/binding-darwin-x64": "0.96.0", "@oxc-parser/binding-freebsd-x64": "0.96.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.96.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.96.0", "@oxc-parser/binding-linux-arm64-gnu": "0.96.0", "@oxc-parser/binding-linux-arm64-musl": "0.96.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.96.0", "@oxc-parser/binding-linux-s390x-gnu": "0.96.0", "@oxc-parser/binding-linux-x64-gnu": "0.96.0", "@oxc-parser/binding-linux-x64-musl": "0.96.0", "@oxc-parser/binding-wasm32-wasi": "0.96.0", "@oxc-parser/binding-win32-arm64-msvc": "0.96.0", "@oxc-parser/binding-win32-x64-msvc": "0.96.0" } }, "sha512-ucs6niJ5mZlYP3oTl4AK2eD2m7WLoSaljswnSFVYWrXzme5PtM97S7Ve1Tjx+/TKjanmEZuSt1f1qYi6SZvntw=="],
+
+    "nuxt-og-image/@nuxt/devtools-kit": ["@nuxt/devtools-kit@2.7.0", "", { "dependencies": { "@nuxt/kit": "^3.19.3", "execa": "^8.0.1" }, "peerDependencies": { "vite": ">=6.0" } }, "sha512-MIJdah6CF6YOW2GhfKnb8Sivu6HpcQheqdjOlZqShBr+1DyjtKQbAKSCAyKPaoIzZP4QOo2SmTFV6aN8jBeEIQ=="],
+
     "nuxt-og-image/execa": ["execa@9.6.0", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.2.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.1.1" } }, "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw=="],
 
     "nuxt-og-image/unwasm": ["unwasm@0.3.11", "", { "dependencies": { "knitwork": "^1.2.0", "magic-string": "^0.30.17", "mlly": "^1.7.4", "pathe": "^2.0.3", "pkg-types": "^2.2.0", "unplugin": "^2.3.6" } }, "sha512-Vhp5gb1tusSQw5of/g3Q697srYgMXvwMgXMjcG4ZNga02fDX9coxJ9fAb0Ci38hM2Hv/U1FXRPGgjP2BYqhNoQ=="],
@@ -2532,6 +2618,10 @@
 
     "rollup-plugin-visualizer/open": ["open@8.4.2", "", { "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", "is-wsl": "^2.2.0" } }, "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ=="],
 
+    "shadcn-nuxt/@nuxt/kit": ["@nuxt/kit@3.20.1", "", { "dependencies": { "c12": "^3.3.1", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", "errx": "^0.1.0", "exsolve": "^1.0.7", "ignore": "^7.0.5", "jiti": "^2.6.1", "klona": "^2.0.6", "knitwork": "^1.2.0", "mlly": "^1.8.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "rc9": "^2.1.2", "scule": "^1.3.0", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ufo": "^1.6.1", "unctx": "^2.4.1", "untyped": "^2.0.0" } }, "sha512-TIslaylfI5kd3AxX5qts0qyrIQ9Uq3HAA1bgIIJ+c+zpDfK338YS+YrCWxBBzDMECRCbAS58mqAd2MtJfG1ENA=="],
+
+    "shadcn-nuxt/oxc-parser": ["oxc-parser@0.97.0", "", { "dependencies": { "@oxc-project/types": "^0.97.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm64": "0.97.0", "@oxc-parser/binding-darwin-arm64": "0.97.0", "@oxc-parser/binding-darwin-x64": "0.97.0", "@oxc-parser/binding-freebsd-x64": "0.97.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.97.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.97.0", "@oxc-parser/binding-linux-arm64-gnu": "0.97.0", "@oxc-parser/binding-linux-arm64-musl": "0.97.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.97.0", "@oxc-parser/binding-linux-s390x-gnu": "0.97.0", "@oxc-parser/binding-linux-x64-gnu": "0.97.0", "@oxc-parser/binding-linux-x64-musl": "0.97.0", "@oxc-parser/binding-wasm32-wasi": "0.97.0", "@oxc-parser/binding-win32-arm64-msvc": "0.97.0", "@oxc-parser/binding-win32-x64-msvc": "0.97.0" } }, "sha512-gxUfidyxJY97BJ+JEN/PxiIxIU1Y1FAPyMTncgNymgd/Cb+TYprsXZqjVnVCmTUlIBoA1XVjbfP0+Iz+uAt7Ow=="],
+
     "socket.io-client/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
 
     "socket.io-parser/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="],
@@ -2546,18 +2636,12 @@
 
     "unimport/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
 
-    "unimport/unplugin-utils": ["unplugin-utils@0.3.1", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog=="],
-
     "unplugin-vue-router/@vue/language-core": ["@vue/language-core@3.1.5", "", { "dependencies": { "@volar/language-core": "2.4.23", "@vue/compiler-dom": "^3.5.0", "@vue/shared": "^3.5.0", "alien-signals": "^3.0.0", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", "picomatch": "^4.0.2" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-FMcqyzWN+sYBeqRMWPGT2QY0mUasZMVIuHvmb5NT3eeqPrbHBYtCP8JWEUCDCgM+Zr62uuWY/qoeBrPrzfa78w=="],
 
-    "unplugin-vue-router/unplugin-utils": ["unplugin-utils@0.3.1", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog=="],
-
     "untun/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
 
     "vite-plugin-checker/npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="],
 
-    "vite-plugin-inspect/unplugin-utils": ["unplugin-utils@0.3.1", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog=="],
-
     "vue-component-meta/@volar/typescript": ["@volar/typescript@2.4.23", "", { "dependencies": { "@volar/language-core": "2.4.23", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag=="],
 
     "vue-component-meta/@vue/language-core": ["@vue/language-core@3.1.5", "", { "dependencies": { "@volar/language-core": "2.4.23", "@vue/compiler-dom": "^3.5.0", "@vue/shared": "^3.5.0", "alien-signals": "^3.0.0", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", "picomatch": "^4.0.2" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-FMcqyzWN+sYBeqRMWPGT2QY0mUasZMVIuHvmb5NT3eeqPrbHBYtCP8JWEUCDCgM+Zr62uuWY/qoeBrPrzfa78w=="],
@@ -2572,14 +2656,64 @@
 
     "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
 
+    "@eslint/config-inspector/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.0", "", { "os": "android", "cpu": "arm" }, "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.0", "", { "os": "android", "cpu": "arm64" }, "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.0", "", { "os": "android", "cpu": "x64" }, "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.0", "", { "os": "linux", "cpu": "arm" }, "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.0", "", { "os": "linux", "cpu": "none" }, "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.0", "", { "os": "linux", "cpu": "none" }, "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.0", "", { "os": "linux", "cpu": "none" }, "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.0", "", { "os": "linux", "cpu": "x64" }, "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.0", "", { "os": "none", "cpu": "arm64" }, "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.0", "", { "os": "none", "cpu": "x64" }, "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.0", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.0", "", { "os": "none", "cpu": "arm64" }, "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.0", "", { "os": "sunos", "cpu": "x64" }, "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ=="],
+
+    "@eslint/config-inspector/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.0", "", { "os": "win32", "cpu": "x64" }, "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg=="],
+
     "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
 
     "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
 
     "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
 
-    "@nuxt/devtools-kit/@nuxt/kit/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
-
     "@nuxt/devtools-kit/execa/get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="],
 
     "@nuxt/devtools-kit/execa/human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="],
@@ -2622,6 +2756,10 @@
 
     "@nuxt/devtools/execa/strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="],
 
+    "@nuxt/eslint/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
+
+    "@nuxt/eslint/find-up/locate-path": ["locate-path@8.0.0", "", { "dependencies": { "p-locate": "^6.0.0" } }, "sha512-XT9ewWAC43tiAV7xDAPflMkG0qOPn2QjHqlgX8FOqmWa/rxnyYDulF9T0F7tRy1u+TVTmK/M//6VIOye+2zDXg=="],
+
     "@nuxt/telemetry/@nuxt/kit/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
 
     "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
@@ -2666,6 +2804,10 @@
 
     "mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
 
+    "nuxt-og-image/@nuxt/devtools-kit/@nuxt/kit": ["@nuxt/kit@3.20.1", "", { "dependencies": { "c12": "^3.3.1", "consola": "^3.4.2", "defu": "^6.1.4", "destr": "^2.0.5", "errx": "^0.1.0", "exsolve": "^1.0.7", "ignore": "^7.0.5", "jiti": "^2.6.1", "klona": "^2.0.6", "knitwork": "^1.2.0", "mlly": "^1.8.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "rc9": "^2.1.2", "scule": "^1.3.0", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ufo": "^1.6.1", "unctx": "^2.4.1", "untyped": "^2.0.0" } }, "sha512-TIslaylfI5kd3AxX5qts0qyrIQ9Uq3HAA1bgIIJ+c+zpDfK338YS+YrCWxBBzDMECRCbAS58mqAd2MtJfG1ENA=="],
+
+    "nuxt-og-image/@nuxt/devtools-kit/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
+
     "nuxt-og-image/execa/get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="],
 
     "nuxt-og-image/execa/human-signals": ["human-signals@8.0.1", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="],
@@ -2680,6 +2822,38 @@
 
     "nuxt-shiki/@nuxt/kit/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
 
+    "nuxt/oxc-parser/@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.96.0", "", { "os": "android", "cpu": "arm64" }, "sha512-CofbPOiW1PG+hi8bgElJPK0ioHfw8nt4Vw9d+Q9JuMhygS6LbQyu1W6tIFZ1OPFofeFRdWus3vD29FBx+tvFOA=="],
+
+    "nuxt/oxc-parser/@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.96.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-+HZ2L1a/1BsUXYik8XqQwT2Tl5Z3jRQ/RRQiPV9UsB2skKyd91NLDlQlMpdhjLGs9Qe7Y42unFjRg2iHjIiwnw=="],
+
+    "nuxt/oxc-parser/@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.96.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-GC8wH1W0XaCLyTeGsmyaMdnItiYQkqfTcn9Ygc55AWI+m11lCjQeoKDIsDCm/QwrKLCN07u3WWWsuPs5ubfXpA=="],
+
+    "nuxt/oxc-parser/@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.96.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-8SeXi2FmlN15uPY5oM03cua5RXBDYmY34Uewongv6RUiAaU/kWxLvzuijpyNC+yQ1r4fC2LbWJhAsKpX5qkA6g=="],
+
+    "nuxt/oxc-parser/@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.96.0", "", { "os": "linux", "cpu": "arm" }, "sha512-UEs+Zf6T2/FwQlLgv7gfZsKmY19sl3hK57r2BQVc2eCmCmF/deeqDcWyFjzkNLgdDDucY60PoNhNGClDm605uQ=="],
+
+    "nuxt/oxc-parser/@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.96.0", "", { "os": "linux", "cpu": "arm" }, "sha512-1kuWvjR2+ORJMoyxt9LSbLcDhXZnL25XOuv9VmH6NmSPvLgewzuubSlm++W03x+U7SzWFilBsdwIHtD/0mjERw=="],
+
+    "nuxt/oxc-parser/@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.96.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-PHH4ETR1t0fymxuhpQNj3Z9t/78/zZa2Lj3Z3I0ZOd+/Ex+gtdhGoB5xYyy7lcYGAPMfZ+Gmr+dTCr1GYNZ3BA=="],
+
+    "nuxt/oxc-parser/@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.96.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-fjDPbZjkqaDSTBe0FM8nZ9zBw4B/NF/I0gH7CfvNDwIj9smISaNFypYeomkvubORpnbX9ORhvhYwg3TxQ60OGA=="],
+
+    "nuxt/oxc-parser/@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.96.0", "", { "os": "linux", "cpu": "none" }, "sha512-59KAHd/6/LmjkdSAuJn0piKmwSavMasWNUKuYLX/UnqI5KkGIp14+LBwwaBG6KzOtIq1NrRCnmlL4XSEaNkzTg=="],
+
+    "nuxt/oxc-parser/@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.96.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-VtupojtgahY8XmLwpVpM3C1WQEgMD1JxpB8lzUtdSLwosWaaz1EAl+VXWNuxTTZusNuLBtmR+F0qql22ISi/9g=="],
+
+    "nuxt/oxc-parser/@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.96.0", "", { "os": "linux", "cpu": "x64" }, "sha512-8XSY9aUYY+5I4I1mhSEWmYqdUrJi3J5cCAInvEVHyTnDAPkhb+tnLGVZD696TpW+lFOLrTFF2V5GMWJVafqIUA=="],
+
+    "nuxt/oxc-parser/@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.96.0", "", { "os": "linux", "cpu": "x64" }, "sha512-IIVNtqhA0uxKkD8Y6aZinKO/sOD5O62VlduE54FnUU2rzZEszrZQLL8nMGVZhTdPaKW5M1aeLmjcdnOs6er1Jg=="],
+
+    "nuxt/oxc-parser/@oxc-parser/binding-wasm32-wasi": ["@oxc-parser/binding-wasm32-wasi@0.96.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.0.7" }, "cpu": "none" }, "sha512-TJ/sNPbVD4u6kUwm7sDKa5iRDEB8vd7ZIMjYqFrrAo9US1RGYOSvt6Ie9sDRekUL9fZhNsykvSrpmIj6dg/C2w=="],
+
+    "nuxt/oxc-parser/@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.96.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-zCOhRB7MYVIHLj+2QYoTuLyaipiD8JG/ggUjfsMUaupRPpvwQNhsxINLIcTcb0AS+OsT7/OREhydjO74STqQzQ=="],
+
+    "nuxt/oxc-parser/@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.96.0", "", { "os": "win32", "cpu": "x64" }, "sha512-J6zfx9TE0oS+TrqBUjMVMOi/d/j3HMj69Pip263pETOEPm788N0HXKPsc2X2jUfSTHzD9vmdjq0QFymbf2LhWg=="],
+
+    "nuxt/oxc-parser/@oxc-project/types": ["@oxc-project/types@0.96.0", "", {}, "sha512-r/xkmoXA0xEpU6UGtn18CNVjXH6erU3KCpCDbpLmbVxBFor1U9MqN5Z2uMmCHJuXjJzlnDR+hWY+yPoLo8oHDw=="],
+
     "readdir-glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
 
     "reka-ui/@vueuse/core/@vueuse/metadata": ["@vueuse/metadata@12.8.2", "", {}, "sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A=="],
@@ -2688,6 +2862,40 @@
 
     "rollup-plugin-visualizer/open/is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="],
 
+    "shadcn-nuxt/@nuxt/kit/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.97.0", "", { "os": "android", "cpu": "arm64" }, "sha512-oLCGuX+1zqTIUjTfCxiZO/Ad4p4wo2MksBSpjdgOC7htyfIg/Se9PK2xU2jzSXlIyzBivwK6AJFqJpcbzJlmsQ=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.97.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Rg7Yy0ICS4HiF+/ZcmjB7h67YOw23Iw06ETHP+0UHQkNuecFew9aDycGG62ohCb1/+QC5uVTW9naR4F8L3FndQ=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.97.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Kr2rgG7yEnv6ivreQtwKAetGeovfWMxsWzTPlM4BMkhI6jsj10BFN+tP5kUHrES66e7eaoFs0SNepHulCpofdw=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.97.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kAWTFHVR3KLcYQ7oEpRQV+WtEAPWZODQ/FsIVGVNAjzIfm9myuiLh7Kys8Vh3QwATPCuPg1w7FGexIm/A1a1lQ=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.97.0", "", { "os": "linux", "cpu": "arm" }, "sha512-w4wYc5KRO6Mdxq9wXh6fAMuxB1LX7btj74+fTZG7/eP7ZiCTsxIM0GR4l7xQjRJOFd9rzlu7ZPq3LM7e9wmPTg=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.97.0", "", { "os": "linux", "cpu": "arm" }, "sha512-DY+3aV2k9YyCRQ5/Zw83cG0xXvgnA6d31JSGfWkOAq9Aa22GeBE/NOzqqMw72HcxRKvYcJsCVpBwQaTICuBGIQ=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.97.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-4B/H4CSc8LZSBTzQHMHQbbZww8B1qaQO+1iBxeKYo1LBD5ZAUZwgYCyM1VUPgqEfUY358a1/Nhn4RIwAbnEFWw=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.97.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Wg8ZPEXR3HHDlzvxqFH9XVc6xfnXaEjMmAuJ9priQmMin42O4B5TwvLmBNlW5Is30faKopGXiiH/Gjmcw/x4xg=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.97.0", "", { "os": "linux", "cpu": "none" }, "sha512-OJNHq6KGPdOh+YVk67T3MfRzLIy9MDMZCzH1f+xgh+kKPWzC4RqlqDNuoyqYiIxjO6kAVZZUQYvx4XVSKluJxw=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.97.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-yZV1kKNzewd/lwWYBw6IRy7ckbduQsUt5LisM8NXt8T0Dg+jhkyy4y7M6X57/KyvT//vHCuRvpnwTr9lk1M9IA=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.97.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Ck7cJMsZX19B0dvsl1v9a8VLeL9kEfUc0zMBjkgYmJfhVuINHcnZlQs8E5zTfD+dpP1wYzUhwgqv3o6hl9QaXA=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.97.0", "", { "os": "linux", "cpu": "x64" }, "sha512-COlEtnuyWfVjvylxhxoSd2HkAI85flvrQu3vGtt4Bm3+ZVdteFCNQskk3q8XfD0Cs+FdtnvDMbhApHyFKaEfsQ=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-parser/binding-wasm32-wasi": ["@oxc-parser/binding-wasm32-wasi@0.97.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.0.7" }, "cpu": "none" }, "sha512-5Rt1uEe1VTw6aUluz8/nBNUbyCVGzwMJbXvPv+b4So+mFlkL+X2cTHb9LH8hcBgJ2TDITLT32J2TcV8Q8EPaKw=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.97.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-e2HDWO997STh7gADYJcjrZ+Fh5cSF8fwT6rRchNoV/hSwbJSC6ZpYFFFQEw2qZ2qyMeTmqQ6QVf7T9oKV18UXg=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.97.0", "", { "os": "win32", "cpu": "x64" }, "sha512-DQ92RUXw67ynu6fUzlFN/gr/rN3nxEQ35AC3EJYAgNKy/GFFJbNKGwFxGnmooje29XhBwibaRdxDs1OIgZBHvQ=="],
+
+    "shadcn-nuxt/oxc-parser/@oxc-project/types": ["@oxc-project/types@0.97.0", "", {}, "sha512-lxmZK4xFrdvU0yZiDwgVQTCvh2gHWBJCBk5ALsrtsBWhs0uDIi+FTOnXRQeQfs304imdvTdaakT/lqwQ8hkOXQ=="],
+
     "unplugin-vue-router/@vue/language-core/@volar/language-core": ["@volar/language-core@2.4.23", "", { "dependencies": { "@volar/source-map": "2.4.23" } }, "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ=="],
 
     "unplugin-vue-router/@vue/language-core/alien-signals": ["alien-signals@3.1.1", "", {}, "sha512-ogkIWbVrLwKtHY6oOAXaYkAxP+cTH7V5FZ5+Tm4NZFd8VDZ6uNMDrfzqctTZ42eTMCSR3ne3otpcxmqSnFfPYA=="],
@@ -2714,6 +2922,8 @@
 
     "@nuxt/devtools/execa/onetime/mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="],
 
+    "@nuxt/eslint/find-up/locate-path/p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="],
+
     "archiver-utils/readable-stream/buffer/base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
 
     "archiver/readable-stream/buffer/base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
@@ -2726,6 +2936,22 @@
 
     "crc32-stream/readable-stream/buffer/base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
 
+    "nuxt-og-image/@nuxt/devtools-kit/@nuxt/kit/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
+
+    "nuxt-og-image/@nuxt/devtools-kit/execa/get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="],
+
+    "nuxt-og-image/@nuxt/devtools-kit/execa/human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="],
+
+    "nuxt-og-image/@nuxt/devtools-kit/execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="],
+
+    "nuxt-og-image/@nuxt/devtools-kit/execa/npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="],
+
+    "nuxt-og-image/@nuxt/devtools-kit/execa/onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="],
+
+    "nuxt-og-image/@nuxt/devtools-kit/execa/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
+
+    "nuxt-og-image/@nuxt/devtools-kit/execa/strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="],
+
     "nuxt-og-image/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
 
     "unplugin-vue-router/@vue/language-core/@volar/language-core/@volar/source-map": ["@volar/source-map@2.4.23", "", {}, "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q=="],
@@ -2735,5 +2961,13 @@
     "vue-component-meta/@vue/language-core/@volar/language-core/@volar/source-map": ["@volar/source-map@2.4.23", "", {}, "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q=="],
 
     "zip-stream/readable-stream/buffer/base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
+
+    "@nuxt/eslint/find-up/locate-path/p-locate/p-limit": ["p-limit@4.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="],
+
+    "nuxt-og-image/@nuxt/devtools-kit/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
+
+    "nuxt-og-image/@nuxt/devtools-kit/execa/onetime/mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="],
+
+    "@nuxt/eslint/find-up/locate-path/p-locate/p-limit/yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="],
   }
 }
diff --git a/docs/ref-analysis.md b/docs/ref-analysis.md
index 19e47ca8..66a9d67c 100644
--- a/docs/ref-analysis.md
+++ b/docs/ref-analysis.md
@@ -28,15 +28,15 @@ layer/
 
 ### Key Components (nuxt-ui based)
 
-| Component | Purpose |
-|-----------|---------|
-| `UApp` | Root wrapper with locale |
-| `UHeader`, `UFooter` | Site chrome |
-| `UPage`, `UPageAside` | Page layout |
-| `UContentNavigation` | Sidebar navigation |
-| `UContentToc` | Table of contents |
-| `UContentSearch` | Search command palette |
-| `UContentSurround` | Prev/Next navigation |
+| Component             | Purpose                  |
+| --------------------- | ------------------------ |
+| `UApp`                | Root wrapper with locale |
+| `UHeader`, `UFooter`  | Site chrome              |
+| `UPage`, `UPageAside` | Page layout              |
+| `UContentNavigation`  | Sidebar navigation       |
+| `UContentToc`         | Table of contents        |
+| `UContentSearch`      | Search command palette   |
+| `UContentSurround`    | Prev/Next navigation     |
 
 ### Composables
 
@@ -94,18 +94,18 @@ apps/v4/
 
 Core components used for documentation:
 
-| Component | Files | Purpose |
-|-----------|-------|---------|
-| `Sidebar` | 10+ files | Navigation sidebar |
-| `Command` | 7 files | Search palette |
-| `Button` | 1 file | Actions |
-| `Dialog` | 4 files | Modals |
-| `Sheet` | 4 files | Mobile drawer |
-| `DropdownMenu` | 8 files | Menus |
-| `Tooltip` | 3 files | Hover info |
-| `Alert` | 3 files | Callouts |
-| `Collapsible` | 3 files | Expandable |
-| `ScrollArea` | 2 files | Custom scroll |
+| Component      | Files     | Purpose            |
+| -------------- | --------- | ------------------ |
+| `Sidebar`      | 10+ files | Navigation sidebar |
+| `Command`      | 7 files   | Search palette     |
+| `Button`       | 1 file    | Actions            |
+| `Dialog`       | 4 files   | Modals             |
+| `Sheet`        | 4 files   | Mobile drawer      |
+| `DropdownMenu` | 8 files   | Menus              |
+| `Tooltip`      | 3 files   | Hover info         |
+| `Alert`        | 3 files   | Callouts           |
+| `Collapsible`  | 3 files   | Expandable         |
+| `ScrollArea`   | 2 files   | Custom scroll      |
 
 ### Styling (Tailwind v4)
 
@@ -144,6 +144,7 @@ Core components used for documentation:
 ### Prose Components
 
 Override markdown rendering:
+
 - `ProseH1.vue` - `ProseH6.vue`
 - `ProseP.vue`, `ProseA.vue`
 - `ProsePre.vue`, `ProseCode.vue`
@@ -153,25 +154,26 @@ Override markdown rendering:
 
 ## 3. Component Mapping
 
-| Docus (nuxt-ui) | Layer (shadcn-vue) |
-|-----------------|-------------------|
-| `UApp` | Remove (plain div) |
-| `UHeader` | Custom `AppHeader.vue` |
-| `UFooter` | Custom `AppFooter.vue` |
-| `UPage` | CSS Grid layout |
-| `UPageAside` | shadcn `Sidebar` |
-| `UContentNavigation` | `DocsSidebar.vue` |
-| `UContentToc` | `DocsTableOfContents.vue` |
-| `UContentSurround` | `DocsPageNav.vue` |
-| `UContentSearch` | shadcn `Command` + `Dialog` |
-| `UButton` | shadcn `Button` |
-| `UColorModeButton` | `ModeSwitcher.vue` |
+| Docus (nuxt-ui)      | Layer (shadcn-vue)          |
+| -------------------- | --------------------------- |
+| `UApp`               | Remove (plain div)          |
+| `UHeader`            | Custom `AppHeader.vue`      |
+| `UFooter`            | Custom `AppFooter.vue`      |
+| `UPage`              | CSS Grid layout             |
+| `UPageAside`         | shadcn `Sidebar`            |
+| `UContentNavigation` | `DocsSidebar.vue`           |
+| `UContentToc`        | `DocsTableOfContents.vue`   |
+| `UContentSurround`   | `DocsPageNav.vue`           |
+| `UContentSearch`     | shadcn `Command` + `Dialog` |
+| `UButton`            | shadcn `Button`             |
+| `UColorModeButton`   | `ModeSwitcher.vue`          |
 
 ---
 
 ## 4. Key Files to Reference
 
 ### From Docus
+
 - `modules/config.ts` - Configuration module pattern
 - `modules/routing.ts` - Routing with i18n support
 - `content.config.ts` - Content collections
@@ -179,6 +181,7 @@ Override markdown rendering:
 - `app/pages/[[lang]]/[...slug].vue` - Docs page
 
 ### From shadcn-vue
+
 - `assets/css/main.css` - Tailwind v4 theme
 - `registry/new-york-v4/ui/sidebar/` - Sidebar components
 - `registry/new-york-v4/ui/command/` - Command palette
@@ -191,6 +194,7 @@ Override markdown rendering:
 ## 5. Dependencies
 
 ### Docus
+
 ```json
 {
   "@nuxt/ui": "^4.2.1",
@@ -202,6 +206,7 @@ Override markdown rendering:
 ```
 
 ### shadcn-vue
+
 ```json
 {
   "reka-ui": "^2.2.1",
@@ -223,4 +228,4 @@ Override markdown rendering:
 2. **Tailwind v4** - oklch colors, @theme inline
 3. **Hybrid approach** - Docus modules + shadcn components
 4. **English only initially** - i18n-ready structure
-5. **Copy components** - Full control, no external runtime
\ No newline at end of file
+5. **Copy components** - Full control, no external runtime
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 4bb5227a..c3e0ea3b 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -3,4 +3,5 @@ import antfu from '@antfu/eslint-config'
 export default antfu({
   formatters: true,
   vue: true,
+    type:'lib'
 })
diff --git a/package.json b/package.json
index 3611c0cf..50d97c4b 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,19 @@
 {
   "name": "docs-please-workspace",
   "version": "1.0.0",
+  "packageManager": "bun@1.3.2",
   "description": "",
+  "author": "",
+  "license": "ISC",
+  "homepage": "https://github.com/pleaseai/docs#readme",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/pleaseai/docs.git"
+  },
+  "bugs": {
+    "url": "https://github.com/pleaseai/docs/issues"
+  },
+  "keywords": [],
   "main": "index.js",
   "scripts": {
     "dev": "dotenvx run -- bun run --cwd apps/docs dev",
@@ -13,26 +25,14 @@
     "env:encrypt": "dotenvx encrypt",
     "env:decrypt": "dotenvx decrypt"
   },
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/pleaseai/docs.git"
-  },
-  "keywords": [],
-  "author": "",
-  "license": "ISC",
-  "bugs": {
-    "url": "https://github.com/pleaseai/docs/issues"
-  },
-  "homepage": "https://github.com/pleaseai/docs#readme",
   "devDependencies": {
     "@antfu/eslint-config": "^6.2.0",
     "@dotenvx/dotenvx": "^1.34.0",
     "eslint": "^9.38.0",
     "eslint-plugin-format": "^1.0.2"
   },
-  "packageManager": "bun@1.3.2",
   "workspaces": [
     "packages/*",
     "apps/*"
   ]
-}
\ No newline at end of file
+}
diff --git a/packages/layer/README.md b/packages/layer/README.md
index 7c3de9f9..005f82c3 100644
--- a/packages/layer/README.md
+++ b/packages/layer/README.md
@@ -5,6 +5,7 @@ A Nuxt layer for documentation sites using **shadcn-vue** instead of nuxt-ui.
 ## Overview
 
 This layer provides a complete documentation theme built with:
+
 - **shadcn-vue** - Beautiful, accessible UI components
 - **Nuxt Content** - Markdown-based content management
 - **Tailwind CSS v4** - Modern CSS with CSS variables
@@ -59,4 +60,4 @@ pnpm dev
 
 ## License
 
-MIT
\ No newline at end of file
+MIT
diff --git a/packages/layer/app/assets/css/main.css b/packages/layer/app/assets/css/main.css
index 8ff3e231..d3d55f64 100644
--- a/packages/layer/app/assets/css/main.css
+++ b/packages/layer/app/assets/css/main.css
@@ -1,5 +1,5 @@
-@import "tailwindcss";
-@import "tw-animate-css";
+@import 'tailwindcss';
+@import 'tw-animate-css';
 
 @custom-variant dark (&:is(.dark *));
 
@@ -34,12 +34,15 @@
   --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
   --color-sidebar-border: var(--sidebar-border);
   --color-sidebar-ring: var(--sidebar-ring);
+  --color-chart-5: var(--chart-5);
+  --color-chart-4: var(--chart-4);
+  --color-chart-3: var(--chart-3);
+  --color-chart-2: var(--chart-2);
+  --color-chart-1: var(--chart-1);
 }
 
 :root {
   --radius: 0.625rem;
-  --background: oklch(1 0 0);
-  --foreground: oklch(0.145 0 0);
   --card: oklch(1 0 0);
   --card-foreground: oklch(0.145 0 0);
   --popover: oklch(1 0 0);
@@ -64,6 +67,13 @@
   --sidebar-accent-foreground: oklch(0.205 0 0);
   --sidebar-border: oklch(0.922 0 0);
   --sidebar-ring: oklch(0.708 0 0);
+  --chart-1: oklch(0.646 0.222 41.116);
+  --chart-2: oklch(0.6 0.118 184.704);
+  --chart-3: oklch(0.398 0.07 227.392);
+  --chart-4: oklch(0.828 0.189 84.429);
+  --chart-5: oklch(0.769 0.188 70.08);
+  --background: oklch(1 0 0);
+  --foreground: oklch(0.145 0 0);
 }
 
 .dark {
@@ -71,7 +81,7 @@
   --foreground: oklch(0.985 0 0);
   --card: oklch(0.205 0 0);
   --card-foreground: oklch(0.985 0 0);
-  --popover: oklch(0.269 0 0);
+  --popover: oklch(0.205 0 0);
   --popover-foreground: oklch(0.985 0 0);
   --primary: oklch(0.922 0 0);
   --primary-foreground: oklch(0.205 0 0);
@@ -79,7 +89,7 @@
   --secondary-foreground: oklch(0.985 0 0);
   --muted: oklch(0.269 0 0);
   --muted-foreground: oklch(0.708 0 0);
-  --accent: oklch(0.371 0 0);
+  --accent: oklch(0.269 0 0);
   --accent-foreground: oklch(0.985 0 0);
   --destructive: oklch(0.704 0.191 22.216);
   --border: oklch(1 0 0 / 10%);
@@ -92,7 +102,12 @@
   --sidebar-accent: oklch(0.269 0 0);
   --sidebar-accent-foreground: oklch(0.985 0 0);
   --sidebar-border: oklch(1 0 0 / 10%);
-  --sidebar-ring: oklch(0.439 0 0);
+  --sidebar-ring: oklch(0.556 0 0);
+  --chart-1: oklch(0.488 0.243 264.376);
+  --chart-2: oklch(0.696 0.17 162.48);
+  --chart-3: oklch(0.769 0.188 70.08);
+  --chart-4: oklch(0.627 0.265 303.9);
+  --chart-5: oklch(0.645 0.246 16.439);
 }
 
 @layer base {
diff --git a/packages/layer/app/components/app/AppHeader.vue b/packages/layer/app/components/app/AppHeader.vue
index 8fbd3139..ced7a513 100644
--- a/packages/layer/app/components/app/AppHeader.vue
+++ b/packages/layer/app/components/app/AppHeader.vue
@@ -1,5 +1,6 @@
 <script setup lang="ts">
 import { Moon, Sun } from 'lucide-vue-next'
+import Button from '~/components/ui/button/Button.vue'
 
 const colorMode = useColorMode()
 
diff --git a/packages/layer/app/components/content/Callout.vue b/packages/layer/app/components/content/Callout.vue
new file mode 100644
index 00000000..4e77cfde
--- /dev/null
+++ b/packages/layer/app/components/content/Callout.vue
@@ -0,0 +1,36 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from 'vue'
+import type { AlertVariants } from '@/components/ui/alert'
+import { InfoIcon } from 'lucide-vue-next'
+import { cn } from '@/lib/utils'
+import {
+  Alert,
+  AlertDescription,
+  AlertTitle,
+} from '@/components/ui/alert'
+
+const props = defineProps<{
+  icon?: boolean
+  title?: string
+  class?: HTMLAttributes['class']
+  variant?: AlertVariants['variant']
+}>()
+</script>
+
+<template>
+  <Alert
+    :class="cn(
+      'bg-background text-foreground mt-6 w-auto border md:-mx-1',
+      props.class,
+    )"
+    :variant
+  >
+    <InfoIcon v-if="icon" />
+    <AlertTitle v-if="title">
+      {{ title }}
+    </AlertTitle>
+    <AlertDescription class="text-card-foreground/80">
+      <slot />
+    </AlertDescription>
+  </Alert>
+</template>
diff --git a/packages/layer/app/components/content/CodeCollapsibleWrapper.vue b/packages/layer/app/components/content/CodeCollapsibleWrapper.vue
new file mode 100644
index 00000000..f083ec2f
--- /dev/null
+++ b/packages/layer/app/components/content/CodeCollapsibleWrapper.vue
@@ -0,0 +1,47 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from 'vue'
+import { cn } from '@/lib/utils'
+import { Button } from '@/components/ui/button'
+import {
+  Collapsible,
+  CollapsibleContent,
+  CollapsibleTrigger,
+} from '@/components/ui/collapsible'
+import { Separator } from '@/components/ui/separator'
+
+const props = defineProps<{
+  class?: HTMLAttributes['class']
+}>()
+
+const open = ref(false)
+</script>
+
+<template>
+  <Collapsible
+    v-model:open="open"
+    :class="cn('group/collapsible relative md:-mx-1', props.class)"
+  >
+    <CollapsibleTrigger as-child>
+      <div class="absolute top-1.5 right-9 z-10 flex items-center">
+        <Button
+          variant="ghost"
+          size="sm"
+          class="text-muted-foreground h-7 rounded-md px-2"
+        >
+          {{ open ? "Collapse" : "Expand" }}
+        </Button>
+        <Separator orientation="vertical" class="mx-1.5 !h-4" />
+      </div>
+    </CollapsibleTrigger>
+
+    <CollapsibleContent
+      force-mount
+      class="relative mt-6 overflow-hidden data-[state=closed]:max-h-64 [&>figure]:mt-0 [&>figure]:md:!mx-0"
+    >
+      <slot />
+    </CollapsibleContent>
+    <CollapsibleTrigger class="from-code/70 to-code text-muted-foreground absolute inset-x-0 -bottom-2 flex h-20 items-center justify-center rounded-b-lg bg-gradient-to-b text-sm group-data-[state=open]/collapsible:hidden">
+      {{ open ? "Collapse" : "Expand" }}
+    </CollapsibleTrigger>
+  </Collapsible>
+</template>
diff --git a/packages/layer/app/components/content/CodeTabs.vue b/packages/layer/app/components/content/CodeTabs.vue
new file mode 100644
index 00000000..85bf5a9d
--- /dev/null
+++ b/packages/layer/app/components/content/CodeTabs.vue
@@ -0,0 +1,14 @@
+<script setup lang="ts">
+import { Tabs } from '@/components/ui/tabs'
+
+const { config } = useConfig()
+</script>
+
+<template>
+  <Tabs
+    v-model="config.installationType"
+    class="relative mt-6 w-full"
+  >
+    <slot />
+  </Tabs>
+</template>
diff --git a/packages/layer/app/components/content/ComponentPreview.vue b/packages/layer/app/components/content/ComponentPreview.vue
new file mode 100644
index 00000000..4f7c3d45
--- /dev/null
+++ b/packages/layer/app/components/content/ComponentPreview.vue
@@ -0,0 +1,64 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from 'vue'
+
+const props = defineProps<{
+  name: string
+  align?: 'center' | 'start' | 'end'
+  description?: string
+  hideCode?: boolean
+  type?: 'block' | 'component' | 'example'
+  class?: HTMLAttributes['class']
+}>()
+
+const Component = props.type === 'block'
+  ? defineAsyncComponent({
+      loader: () => import(`@/registry/new-york-v4/blocks/${props.name}/page.vue`),
+    })
+  : props.name.toLowerCase().includes('chart') && !props.name.toLocaleLowerCase().includes('demo')
+    ? defineAsyncComponent({
+        loader: () => import(`@/registry/new-york-v4/charts/${props.name}.vue`),
+      })
+    : defineAsyncComponent({
+        loader: () => import(`@/components/demo/${props.name}.vue`),
+      })
+</script>
+
+<template>
+  <p v-if="!Component" class="text-muted-foreground text-sm">
+    Component
+    <code class="bg-muted relative rounded px-[0.3rem] py-[0.2rem] font-mono text-sm">
+      {{ name }}
+    </code>
+    not found in registry.
+  </p>
+
+  <div v-else-if="type === 'block'" class="relative aspect-[4/2.5] w-full overflow-hidden rounded-md border md:-mx-1">
+    <img
+      :src="`/r/styles/new-york-v4/${name}-light.png`"
+      :alt="name"
+      width="1440"
+      height="900"
+      class="bg-background absolute top-0 left-0 z-20 w-[970px] max-w-none sm:w-[1280px] md:hidden dark:hidden md:dark:hidden"
+    >
+    <img
+      :src="`/r/styles/new-york-v4/${name}-dark.png`"
+      :alt="name"
+      :width="1440"
+      :height="900"
+      class="bg-background absolute top-0 left-0 z-20 hidden w-[970px] max-w-none sm:w-[1280px] md:hidden dark:block md:dark:hidden"
+    >
+    <div class="bg-background absolute inset-0 hidden w-[1600px] md:block">
+      <iframe :src="`/view/${name}`" class="size-full" />
+    </div>
+  </div>
+
+  <ComponentPreviewTabs
+    v-else
+    :class="props.class"
+    :align
+    :hide-code
+    :component="Component"
+  >
+    <ComponentSource v-if="!hideCode" :name :collapsible="false" />
+  </ComponentPreviewTabs>
+</template>
diff --git a/packages/layer/app/components/content/ComponentsList.vue b/packages/layer/app/components/content/ComponentsList.vue
new file mode 100644
index 00000000..f9197411
--- /dev/null
+++ b/packages/layer/app/components/content/ComponentsList.vue
@@ -0,0 +1,24 @@
+<script setup lang="ts">
+const { data } = await useNavigation()
+
+const list = computed(() => data.value?.[0]?.children.find(item => item.title === 'Components')?.children ?? [])
+</script>
+
+<template>
+  <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3 md:gap-x-8 lg:gap-x-16 lg:gap-y-6 xl:gap-x-20">
+    <NuxtLink
+      v-for="component in list"
+      :key="component.title"
+      :to="component.path"
+      class="inline-flex items-center gap-2 text-lg font-medium underline-offset-4 hover:underline md:text-base"
+    >
+      {{ component.title }}
+
+      <span
+        v-if="component.new"
+        class="flex size-2 rounded-full bg-green-500"
+        title="New"
+      />
+    </NuxtLink>
+  </div>
+</template>
diff --git a/packages/layer/app/components/content/LinkedCard.vue b/packages/layer/app/components/content/LinkedCard.vue
new file mode 100644
index 00000000..e94b8107
--- /dev/null
+++ b/packages/layer/app/components/content/LinkedCard.vue
@@ -0,0 +1,19 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from 'vue'
+import { cn } from '~/lib/utils'
+
+const props = defineProps<{
+  class?: HTMLAttributes['class']
+}>()
+</script>
+
+<template>
+  <NuxtLink
+    :class="cn(
+      'bg-surface text-surface-foreground hover:bg-surface/80 flex w-full flex-col items-center rounded-xl p-6 transition-colors sm:p-10',
+      props.class,
+    )"
+  >
+    <slot />
+  </NuxtLink>
+</template>
diff --git a/packages/layer/app/components/content/ProseA.vue b/packages/layer/app/components/content/ProseA.vue
new file mode 100644
index 00000000..da03ae05
--- /dev/null
+++ b/packages/layer/app/components/content/ProseA.vue
@@ -0,0 +1,18 @@
+<script setup lang="ts">
+const props = withDefaults(defineProps<{
+  href?: string
+  target?: '_blank' | '_parent' | '_self' | '_top' | (string & object) | null | undefined
+}>(), {
+  href: '',
+})
+</script>
+
+<template>
+  <NuxtLink
+    :href="props.href"
+    :target="props.target"
+    class="font-medium underline underline-offset-4"
+  >
+    <slot />
+  </NuxtLink>
+</template>
diff --git a/packages/layer/app/components/content/ProseBlockQuote.vue b/packages/layer/app/components/content/ProseBlockQuote.vue
new file mode 100644
index 00000000..e57063c0
--- /dev/null
+++ b/packages/layer/app/components/content/ProseBlockQuote.vue
@@ -0,0 +1,8 @@
+<script setup lang="ts">
+</script>
+
+<template>
+  <blockquote class="mt-6 border-l-2 pl-6 italic">
+    <slot />
+  </blockquote>
+</template>
diff --git a/packages/layer/app/components/content/ProseCode.vue b/packages/layer/app/components/content/ProseCode.vue
new file mode 100644
index 00000000..4d865ccb
--- /dev/null
+++ b/packages/layer/app/components/content/ProseCode.vue
@@ -0,0 +1,8 @@
+<script setup lang="ts">
+</script>
+
+<template>
+  <code class="bg-muted relative rounded-md px-[0.3rem] py-[0.2rem] font-mono text-[0.8rem] outline-none">
+    <slot />
+  </code>
+</template>
diff --git a/packages/layer/app/components/content/ProseH1.vue b/packages/layer/app/components/content/ProseH1.vue
new file mode 100644
index 00000000..858c979e
--- /dev/null
+++ b/packages/layer/app/components/content/ProseH1.vue
@@ -0,0 +1,7 @@
+<script setup lang="ts"></script>
+
+<template>
+  <h1 class="font-heading mt-2 scroll-m-28 text-3xl font-bold tracking-tight">
+    <slot />
+  </h1>
+</template>
diff --git a/packages/layer/app/components/content/ProseH2.vue b/packages/layer/app/components/content/ProseH2.vue
new file mode 100644
index 00000000..e525d566
--- /dev/null
+++ b/packages/layer/app/components/content/ProseH2.vue
@@ -0,0 +1,8 @@
+<script setup lang="ts">
+</script>
+
+<template>
+  <h2 class="font-heading [&+]*:[code]:text-xl mt-10 scroll-m-28 text-xl font-medium tracking-tight first:mt-0 lg:mt-16 [&+.steps]:!mt-0 [&+.steps>h3]:!mt-4 [&+h3]:!mt-6 [&+p]:!mt-4">
+    <slot />
+  </h2>
+</template>
diff --git a/packages/layer/app/components/content/ProseH3.vue b/packages/layer/app/components/content/ProseH3.vue
new file mode 100644
index 00000000..4ce8db56
--- /dev/null
+++ b/packages/layer/app/components/content/ProseH3.vue
@@ -0,0 +1,9 @@
+<script setup lang="ts"></script>
+
+<template>
+  <h3
+    class="font-heading mt-12 scroll-m-28 text-lg font-medium tracking-tight [&+p]:!mt-4 *:[code]:text-xl"
+  >
+    <slot />
+  </h3>
+</template>
diff --git a/packages/layer/app/components/content/ProseH4.vue b/packages/layer/app/components/content/ProseH4.vue
new file mode 100644
index 00000000..e4685f05
--- /dev/null
+++ b/packages/layer/app/components/content/ProseH4.vue
@@ -0,0 +1,9 @@
+<script setup lang="ts"></script>
+
+<template>
+  <h4
+    class="font-heading mt-8 scroll-m-28 text-base font-medium tracking-tight"
+  >
+    <slot />
+  </h4>
+</template>
diff --git a/packages/layer/app/components/content/ProseH5.vue b/packages/layer/app/components/content/ProseH5.vue
new file mode 100644
index 00000000..f77c7252
--- /dev/null
+++ b/packages/layer/app/components/content/ProseH5.vue
@@ -0,0 +1,7 @@
+<script setup lang="ts"></script>
+
+<template>
+  <h5 class="mt-8 scroll-m-28 text-base font-medium tracking-tight">
+    <slot />
+  </h5>
+</template>
diff --git a/packages/layer/app/components/content/ProseH6.vue b/packages/layer/app/components/content/ProseH6.vue
new file mode 100644
index 00000000..7cbc8c64
--- /dev/null
+++ b/packages/layer/app/components/content/ProseH6.vue
@@ -0,0 +1,7 @@
+<script setup lang="ts"></script>
+
+<template>
+  <h6 class="mt-8 scroll-m-28 text-base font-medium tracking-tight">
+    <slot />
+  </h6>
+</template>
diff --git a/packages/layer/app/components/content/ProseHr.vue b/packages/layer/app/components/content/ProseHr.vue
new file mode 100644
index 00000000..4990d915
--- /dev/null
+++ b/packages/layer/app/components/content/ProseHr.vue
@@ -0,0 +1,6 @@
+<script setup lang="ts">
+</script>
+
+<template>
+  <hr class="my-4 md:my-8">
+</template>
diff --git a/packages/layer/app/components/content/ProseImg.vue b/packages/layer/app/components/content/ProseImg.vue
new file mode 100644
index 00000000..38709648
--- /dev/null
+++ b/packages/layer/app/components/content/ProseImg.vue
@@ -0,0 +1,6 @@
+<script setup lang="ts">
+</script>
+
+<template>
+  <img class="rounded-md">
+</template>
diff --git a/packages/layer/app/components/content/ProseLi.vue b/packages/layer/app/components/content/ProseLi.vue
new file mode 100644
index 00000000..9bb60733
--- /dev/null
+++ b/packages/layer/app/components/content/ProseLi.vue
@@ -0,0 +1,8 @@
+<script setup lang="ts">
+</script>
+
+<template>
+  <li class="mt-2">
+    <slot />
+  </li>
+</template>
diff --git a/packages/layer/app/components/content/ProseOl.vue b/packages/layer/app/components/content/ProseOl.vue
new file mode 100644
index 00000000..b9cf4930
--- /dev/null
+++ b/packages/layer/app/components/content/ProseOl.vue
@@ -0,0 +1,8 @@
+<script setup lang="ts">
+</script>
+
+<template>
+  <ol class="my-6 ml-6 list-decimal">
+    <slot />
+  </ol>
+</template>
diff --git a/packages/layer/app/components/content/ProseP.vue b/packages/layer/app/components/content/ProseP.vue
new file mode 100644
index 00000000..f4d7690d
--- /dev/null
+++ b/packages/layer/app/components/content/ProseP.vue
@@ -0,0 +1,14 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from 'vue'
+import { cn } from '~/lib/utils'
+
+const props = defineProps<{
+  class?: HTMLAttributes['class']
+}>()
+</script>
+
+<template>
+  <p :class="cn('leading-relaxed [&:not(:first-child)]:mt-6', props.class)">
+    <slot />
+  </p>
+</template>
diff --git a/packages/layer/app/components/content/ProsePre.vue b/packages/layer/app/components/content/ProsePre.vue
new file mode 100644
index 00000000..89217c64
--- /dev/null
+++ b/packages/layer/app/components/content/ProsePre.vue
@@ -0,0 +1,82 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from 'vue'
+import { getIconForLanguageExtension } from '@/components/Icons'
+import { cn } from '~/lib/utils'
+
+const props = defineProps<{
+  code: string
+  language: string
+  filename?: string
+  highlights?: number[]
+  meta?: string
+  class?: HTMLAttributes['class']
+  unwrap?: boolean
+}>()
+
+const npmBlock = ['npm install', 'npm create', 'npm run', 'npx']
+const isNpmCommand = computed(() => npmBlock.some(s => props.code.startsWith(s)))
+const isShowingLineNumber = computed(() => props.meta?.includes('showLineNumbers'))
+
+const title = computed(() => props.filename || props.meta?.match(/title="([^"]+)"/)?.[1])
+
+const lang = computed(() => props.language.replace('language-', ''))
+const IconExtension = computed(() => {
+  return getIconForLanguageExtension(lang.value)
+})
+
+const highlighter = await getShikiHighlighter()
+const highlighted = highlighter.highlight(props.code.trimEnd(), { lang: lang.value, transformers: [
+  {
+    name: 'stripe-wrapper',
+    root(node) {
+      const pre = node.children.find(child => child.type === 'element' && child.tagName === 'pre')
+      if (pre?.type === 'element') {
+        const code = pre.children.find(child => child.type === 'element' && child.tagName === 'code')
+        if (code?.type === 'element') {
+          node.children = code.children
+        }
+      }
+    },
+  },
+  {
+    name: 'modify-lines',
+    line(node) {
+      node.properties.class = undefined
+      node.properties['data-line'] = ''
+    },
+  },
+  {
+    name: 'highlight-line-inline',
+    line(node, line, ...a) {
+      if (props.highlights?.includes(line))
+        node.properties['data-highlighted-line'] = ''
+    },
+    // TODO: implement `data-highlighted-chars`
+    tokens(tokens) {},
+  },
+] })
+
+const codeAttributes = computed(() => isShowingLineNumber.value
+  ? ({
+      'data-line-numbers': '',
+      'data-line-numbers-max-digits': 2,
+    })
+  : undefined)
+</script>
+
+<template>
+  <pre v-if="unwrap" :class="cn('no-scrollbar min-w-0 overflow-x-auto px-4 py-3.5 outline-none has-[[data-highlighted-line]]:px-0 has-[[data-line-numbers]]:px-0 has-[[data-slot=tabs]]:p-0 !bg-transparent', props.class)" :data-language="lang"><code v-bind="codeAttributes" v-html="highlighted" /></pre>
+  <figure v-else data-pretty-code-figure>
+    <pre v-if="isNpmCommand" :class="cn('no-scrollbar min-w-0 overflow-x-auto px-4 py-3.5 outline-none has-[[data-highlighted-line]]:px-0 has-[[data-line-numbers]]:px-0 has-[[data-slot=tabs]]:p-0', props.class)"><CodeBlockCommand :code /></pre>
+
+    <template v-else-if="title">
+      <figcaption data-pretty-code-title :data-language="lang" class="text-code-foreground [&_svg]:text-code-foreground flex items-center gap-2 [&_svg]:size-4 [&_svg]:opacity-70">
+        <component :is="IconExtension" v-if="IconExtension" />
+        {{ title }}
+      </figcaption>
+      <pre :data-language="lang" :class="cn('no-scrollbar min-w-0 overflow-x-auto px-4 py-3.5 outline-none has-[[data-highlighted-line]]:px-0 has-[[data-line-numbers]]:px-0 has-[[data-slot=tabs]]:p-0', props.class)"><CopyButton :value="code" /><code v-bind="codeAttributes" v-html="highlighted" /></pre>
+    </template>
+
+    <pre v-else :data-language="lang" :class="cn('no-scrollbar min-w-0 overflow-x-auto px-4 py-3.5 outline-none has-[[data-highlighted-line]]:px-0 has-[[data-line-numbers]]:px-0 has-[[data-slot=tabs]]:p-0', props.class)"><CopyButton :value="code" /><code v-bind="codeAttributes" v-html="highlighted" /></pre>
+  </figure>
+</template>
diff --git a/packages/layer/app/components/content/ProseStrong.vue b/packages/layer/app/components/content/ProseStrong.vue
new file mode 100644
index 00000000..37bd0ca0
--- /dev/null
+++ b/packages/layer/app/components/content/ProseStrong.vue
@@ -0,0 +1,8 @@
+<script setup lang="ts">
+</script>
+
+<template>
+  <strong class="font-medium">
+    <slot />
+  </strong>
+</template>
diff --git a/packages/layer/app/components/content/ProseTable.vue b/packages/layer/app/components/content/ProseTable.vue
new file mode 100644
index 00000000..c31a498e
--- /dev/null
+++ b/packages/layer/app/components/content/ProseTable.vue
@@ -0,0 +1,26 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from 'vue'
+import { cn } from '~/lib/utils'
+
+defineOptions({
+  inheritAttrs: false,
+})
+
+const props = defineProps<{
+  class?: HTMLAttributes['class']
+}>()
+</script>
+
+<template>
+  <div class="no-scrollbar my-6 w-full overflow-y-auto rounded-lg border">
+    <table
+      :class="cn(
+        'relative w-full overflow-hidden border-none text-sm [&_tbody_tr:last-child]:border-b-0',
+        props.class,
+      )"
+      v-bind="$attrs"
+    >
+      <slot />
+    </table>
+  </div>
+</template>
diff --git a/packages/layer/app/components/content/ProseTd.vue b/packages/layer/app/components/content/ProseTd.vue
new file mode 100644
index 00000000..1885eefa
--- /dev/null
+++ b/packages/layer/app/components/content/ProseTd.vue
@@ -0,0 +1,8 @@
+<script setup lang="ts">
+</script>
+
+<template>
+  <td class="px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right">
+    <slot />
+  </td>
+</template>
diff --git a/packages/layer/app/components/content/ProseTh.vue b/packages/layer/app/components/content/ProseTh.vue
new file mode 100644
index 00000000..ada6f96b
--- /dev/null
+++ b/packages/layer/app/components/content/ProseTh.vue
@@ -0,0 +1,8 @@
+<script setup lang="ts">
+</script>
+
+<template>
+  <th class="px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right">
+    <slot />
+  </th>
+</template>
diff --git a/packages/layer/app/components/content/ProseTr.vue b/packages/layer/app/components/content/ProseTr.vue
new file mode 100644
index 00000000..5337d968
--- /dev/null
+++ b/packages/layer/app/components/content/ProseTr.vue
@@ -0,0 +1,8 @@
+<script setup lang="ts">
+</script>
+
+<template>
+  <tr class="last:border-b-none m-0 border-b">
+    <slot />
+  </tr>
+</template>
diff --git a/packages/layer/app/components/content/ProseUl.vue b/packages/layer/app/components/content/ProseUl.vue
new file mode 100644
index 00000000..dc5a196e
--- /dev/null
+++ b/packages/layer/app/components/content/ProseUl.vue
@@ -0,0 +1,8 @@
+<script setup lang="ts">
+</script>
+
+<template>
+  <ul class="my-6 ml-6 list-disc">
+    <slot />
+  </ul>
+</template>
diff --git a/packages/layer/app/components/content/Step.vue b/packages/layer/app/components/content/Step.vue
new file mode 100644
index 00000000..5810260c
--- /dev/null
+++ b/packages/layer/app/components/content/Step.vue
@@ -0,0 +1,18 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from 'vue'
+import { cn } from '~/lib/utils'
+
+const props = defineProps<{
+  class?: HTMLAttributes['class']
+}>()
+</script>
+
+<template>
+  <h3
+    :class="cn(
+      'font-heading mt-8 scroll-m-32 text-xl font-medium tracking-tight', props.class,
+    )"
+  >
+    <slot mdc-unwrap="p" />
+  </h3>
+</template>
diff --git a/packages/layer/app/components/content/Steps.vue b/packages/layer/app/components/content/Steps.vue
new file mode 100644
index 00000000..61cea4bc
--- /dev/null
+++ b/packages/layer/app/components/content/Steps.vue
@@ -0,0 +1,18 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from 'vue'
+import { cn } from '~/lib/utils'
+
+const props = defineProps<{
+  class?: HTMLAttributes['class']
+}>()
+</script>
+
+<template>
+  <div
+    :class="cn(
+      '[&>h3]:step steps mb-12 [counter-reset:step] *:[h3]:first:!mt-0', props.class,
+    )"
+  >
+    <slot />
+  </div>
+</template>
diff --git a/packages/layer/app/components/content/Tabs.vue b/packages/layer/app/components/content/Tabs.vue
new file mode 100644
index 00000000..3e6269e1
--- /dev/null
+++ b/packages/layer/app/components/content/Tabs.vue
@@ -0,0 +1,13 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from 'vue'
+import { Tabs } from '@/components/ui/tabs'
+import { cn } from '~/lib/utils'
+
+const props = defineProps<{ class?: HTMLAttributes['class'] }>()
+</script>
+
+<template>
+  <Tabs :class="cn(props.class)">
+    <slot />
+  </Tabs>
+</template>
diff --git a/packages/layer/app/components/content/TabsContent.vue b/packages/layer/app/components/content/TabsContent.vue
new file mode 100644
index 00000000..7b4ca468
--- /dev/null
+++ b/packages/layer/app/components/content/TabsContent.vue
@@ -0,0 +1,14 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from 'vue'
+import { TabsContent } from '@/components/ui/tabs'
+import { cn } from '~/lib/utils'
+
+const props = defineProps<{ class?: HTMLAttributes['class'] }>()
+// Ignore Vue tsc warning as the props will be passed as fallback attribute
+</script>
+
+<template>
+  <TabsContent :class="cn('relative [&_h3.font-heading]:text-base [&_h3.font-heading]:font-medium *:[figure]:first:mt-0 [&>.steps]:mt-6', props.class)">
+    <slot />
+  </TabsContent>
+</template>
diff --git a/packages/layer/app/components/content/TabsList.vue b/packages/layer/app/components/content/TabsList.vue
new file mode 100644
index 00000000..0b235437
--- /dev/null
+++ b/packages/layer/app/components/content/TabsList.vue
@@ -0,0 +1,13 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from 'vue'
+import { TabsList } from '@/components/ui/tabs'
+import { cn } from '~/lib/utils'
+
+const props = defineProps<{ class?: HTMLAttributes['class'] }>()
+</script>
+
+<template>
+  <TabsList :class="cn('justify-start gap-4 rounded-none bg-transparent px-0', props.class)">
+    <slot />
+  </TabsList>
+</template>
diff --git a/packages/layer/app/components/content/TabsTrigger.vue b/packages/layer/app/components/content/TabsTrigger.vue
new file mode 100644
index 00000000..43121b5c
--- /dev/null
+++ b/packages/layer/app/components/content/TabsTrigger.vue
@@ -0,0 +1,13 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from 'vue'
+import { TabsTrigger } from '@/components/ui/tabs'
+import { cn } from '~/lib/utils'
+
+const props = defineProps<{ class?: HTMLAttributes['class'] }>()
+</script>
+
+<template>
+  <TabsTrigger :class="cn('text-muted-foreground data-[state=active]:text-foreground data-[state=active]:border-primary dark:data-[state=active]:border-primary hover:text-primary rounded-none border-0 border-b-2 border-transparent bg-transparent px-0 pb-3 text-base data-[state=active]:bg-transparent data-[state=active]:shadow-none dark:data-[state=active]:bg-transparent', props.class)">
+    <slot />
+  </TabsTrigger>
+</template>
diff --git a/packages/layer/app/components/docs/DocsSidebar.vue b/packages/layer/app/components/docs/DocsSidebar.vue
index e013bf6d..b9fe01d4 100644
--- a/packages/layer/app/components/docs/DocsSidebar.vue
+++ b/packages/layer/app/components/docs/DocsSidebar.vue
@@ -1,12 +1,11 @@
 <script setup lang="ts">
 import { ChevronRight } from 'lucide-vue-next'
-import type { NavigationItem } from '~/composables/useNavigation'
 
 const { data: navigation } = await useNavigation()
 const route = useRoute()
 
 function isActive(path: string) {
-  return route.path === path || route.path.startsWith(path + '/')
+  return route.path === path || route.path.startsWith(`${path}/`)
 }
 </script>
 
diff --git a/packages/layer/app/components/docs/DocsTableOfContents.vue b/packages/layer/app/components/docs/DocsTableOfContents.vue
index 1f01ff6c..b57532e9 100644
--- a/packages/layer/app/components/docs/DocsTableOfContents.vue
+++ b/packages/layer/app/components/docs/DocsTableOfContents.vue
@@ -27,7 +27,8 @@ onMounted(() => {
 
   props.toc?.forEach((item) => {
     const el = document.getElementById(item.id)
-    if (el) observer.observe(el)
+    if (el)
+      observer.observe(el)
   })
 
   onUnmounted(() => observer.disconnect())
diff --git a/packages/layer/app/components/ui/alert/Alert.vue b/packages/layer/app/components/ui/alert/Alert.vue
new file mode 100644
index 00000000..a9d336ff
--- /dev/null
+++ b/packages/layer/app/components/ui/alert/Alert.vue
@@ -0,0 +1,21 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from "vue"
+import type { AlertVariants } from "."
+import { cn } from "@/lib/utils"
+import { alertVariants } from "."
+
+const props = defineProps<{
+  class?: HTMLAttributes["class"]
+  variant?: AlertVariants["variant"]
+}>()
+</script>
+
+<template>
+  <div
+    data-slot="alert"
+    :class="cn(alertVariants({ variant }), props.class)"
+    role="alert"
+  >
+    <slot />
+  </div>
+</template>
diff --git a/packages/layer/app/components/ui/alert/AlertDescription.vue b/packages/layer/app/components/ui/alert/AlertDescription.vue
new file mode 100644
index 00000000..9f7d24df
--- /dev/null
+++ b/packages/layer/app/components/ui/alert/AlertDescription.vue
@@ -0,0 +1,17 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from "vue"
+import { cn } from "@/lib/utils"
+
+const props = defineProps<{
+  class?: HTMLAttributes["class"]
+}>()
+</script>
+
+<template>
+  <div
+    data-slot="alert-description"
+    :class="cn('text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed', props.class)"
+  >
+    <slot />
+  </div>
+</template>
diff --git a/packages/layer/app/components/ui/alert/AlertTitle.vue b/packages/layer/app/components/ui/alert/AlertTitle.vue
new file mode 100644
index 00000000..b2183843
--- /dev/null
+++ b/packages/layer/app/components/ui/alert/AlertTitle.vue
@@ -0,0 +1,17 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from "vue"
+import { cn } from "@/lib/utils"
+
+const props = defineProps<{
+  class?: HTMLAttributes["class"]
+}>()
+</script>
+
+<template>
+  <div
+    data-slot="alert-title"
+    :class="cn('col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight', props.class)"
+  >
+    <slot />
+  </div>
+</template>
diff --git a/packages/layer/app/components/ui/alert/index.ts b/packages/layer/app/components/ui/alert/index.ts
new file mode 100644
index 00000000..42d07b64
--- /dev/null
+++ b/packages/layer/app/components/ui/alert/index.ts
@@ -0,0 +1,24 @@
+import type { VariantProps } from "class-variance-authority"
+import { cva } from "class-variance-authority"
+
+export { default as Alert } from "./Alert.vue"
+export { default as AlertDescription } from "./AlertDescription.vue"
+export { default as AlertTitle } from "./AlertTitle.vue"
+
+export const alertVariants = cva(
+  "relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
+  {
+    variants: {
+      variant: {
+        default: "bg-card text-card-foreground",
+        destructive:
+          "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
+      },
+    },
+    defaultVariants: {
+      variant: "default",
+    },
+  },
+)
+
+export type AlertVariants = VariantProps<typeof alertVariants>
diff --git a/packages/layer/app/components/ui/button/Button.vue b/packages/layer/app/components/ui/button/Button.vue
index be56cad1..374320b7 100644
--- a/packages/layer/app/components/ui/button/Button.vue
+++ b/packages/layer/app/components/ui/button/Button.vue
@@ -1,19 +1,19 @@
 <script setup lang="ts">
-import type { PrimitiveProps } from 'reka-ui'
-import type { HTMLAttributes } from 'vue'
-import type { ButtonVariants } from './variants'
-import { Primitive } from 'reka-ui'
-import { cn } from '~/utils/cn'
-import { buttonVariants } from './variants'
+import type { PrimitiveProps } from "reka-ui"
+import type { HTMLAttributes } from "vue"
+import type { ButtonVariants } from "."
+import { Primitive } from "reka-ui"
+import { cn } from "@/lib/utils"
+import { buttonVariants } from "."
 
 interface Props extends PrimitiveProps {
-  variant?: ButtonVariants['variant']
-  size?: ButtonVariants['size']
-  class?: HTMLAttributes['class']
+  variant?: ButtonVariants["variant"]
+  size?: ButtonVariants["size"]
+  class?: HTMLAttributes["class"]
 }
 
 const props = withDefaults(defineProps<Props>(), {
-  as: 'button',
+  as: "button",
 })
 </script>
 
diff --git a/packages/layer/app/components/ui/button/index.ts b/packages/layer/app/components/ui/button/index.ts
new file mode 100644
index 00000000..26e2c559
--- /dev/null
+++ b/packages/layer/app/components/ui/button/index.ts
@@ -0,0 +1,38 @@
+import type { VariantProps } from "class-variance-authority"
+import { cva } from "class-variance-authority"
+
+export { default as Button } from "./Button.vue"
+
+export const buttonVariants = cva(
+  "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",
+  {
+    variants: {
+      variant: {
+        default:
+          "bg-primary text-primary-foreground hover:bg-primary/90",
+        destructive:
+          "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
+        outline:
+          "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
+        secondary:
+          "bg-secondary text-secondary-foreground hover:bg-secondary/80",
+        ghost:
+          "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
+        link: "text-primary underline-offset-4 hover:underline",
+      },
+      size: {
+        "default": "h-9 px-4 py-2 has-[>svg]:px-3",
+        "sm": "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
+        "lg": "h-10 rounded-md px-6 has-[>svg]:px-4",
+        "icon": "size-9",
+        "icon-sm": "size-8",
+        "icon-lg": "size-10",
+      },
+    },
+    defaultVariants: {
+      variant: "default",
+      size: "default",
+    },
+  },
+)
+export type ButtonVariants = VariantProps<typeof buttonVariants>
diff --git a/packages/layer/app/components/ui/button/variants.ts b/packages/layer/app/components/ui/button/variants.ts
deleted file mode 100644
index a766db0a..00000000
--- a/packages/layer/app/components/ui/button/variants.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import type { VariantProps } from 'class-variance-authority'
-import { cva } from 'class-variance-authority'
-
-export { default as Button } from './Button.vue'
-
-export const buttonVariants = cva(
-  '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',
-  {
-    variants: {
-      variant: {
-        default:
-          'bg-primary text-primary-foreground hover:bg-primary/90',
-        destructive:
-          'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
-        outline:
-          'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
-        secondary:
-          'bg-secondary text-secondary-foreground hover:bg-secondary/80',
-        ghost:
-          'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
-        link: 'text-primary underline-offset-4 hover:underline',
-      },
-      size: {
-        'default': 'h-9 px-4 py-2 has-[>svg]:px-3',
-        'sm': 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
-        'lg': 'h-10 rounded-md px-6 has-[>svg]:px-4',
-        'icon': 'size-9',
-        'icon-sm': 'size-8',
-        'icon-lg': 'size-10',
-      },
-    },
-    defaultVariants: {
-      variant: 'default',
-      size: 'default',
-    },
-  },
-)
-export type ButtonVariants = VariantProps<typeof buttonVariants>
diff --git a/packages/layer/app/components/ui/collapsible/Collapsible.vue b/packages/layer/app/components/ui/collapsible/Collapsible.vue
new file mode 100644
index 00000000..70a94978
--- /dev/null
+++ b/packages/layer/app/components/ui/collapsible/Collapsible.vue
@@ -0,0 +1,19 @@
+<script setup lang="ts">
+import type { CollapsibleRootEmits, CollapsibleRootProps } from "reka-ui"
+import { CollapsibleRoot, useForwardPropsEmits } from "reka-ui"
+
+const props = defineProps<CollapsibleRootProps>()
+const emits = defineEmits<CollapsibleRootEmits>()
+
+const forwarded = useForwardPropsEmits(props, emits)
+</script>
+
+<template>
+  <CollapsibleRoot
+    v-slot="slotProps"
+    data-slot="collapsible"
+    v-bind="forwarded"
+  >
+    <slot v-bind="slotProps" />
+  </CollapsibleRoot>
+</template>
diff --git a/packages/layer/app/components/ui/collapsible/CollapsibleContent.vue b/packages/layer/app/components/ui/collapsible/CollapsibleContent.vue
new file mode 100644
index 00000000..8be0a113
--- /dev/null
+++ b/packages/layer/app/components/ui/collapsible/CollapsibleContent.vue
@@ -0,0 +1,15 @@
+<script setup lang="ts">
+import type { CollapsibleContentProps } from "reka-ui"
+import { CollapsibleContent } from "reka-ui"
+
+const props = defineProps<CollapsibleContentProps>()
+</script>
+
+<template>
+  <CollapsibleContent
+    data-slot="collapsible-content"
+    v-bind="props"
+  >
+    <slot />
+  </CollapsibleContent>
+</template>
diff --git a/packages/layer/app/components/ui/collapsible/CollapsibleTrigger.vue b/packages/layer/app/components/ui/collapsible/CollapsibleTrigger.vue
new file mode 100644
index 00000000..33bec783
--- /dev/null
+++ b/packages/layer/app/components/ui/collapsible/CollapsibleTrigger.vue
@@ -0,0 +1,15 @@
+<script setup lang="ts">
+import type { CollapsibleTriggerProps } from "reka-ui"
+import { CollapsibleTrigger } from "reka-ui"
+
+const props = defineProps<CollapsibleTriggerProps>()
+</script>
+
+<template>
+  <CollapsibleTrigger
+    data-slot="collapsible-trigger"
+    v-bind="props"
+  >
+    <slot />
+  </CollapsibleTrigger>
+</template>
diff --git a/packages/layer/app/components/ui/collapsible/index.ts b/packages/layer/app/components/ui/collapsible/index.ts
new file mode 100644
index 00000000..86a031d5
--- /dev/null
+++ b/packages/layer/app/components/ui/collapsible/index.ts
@@ -0,0 +1,3 @@
+export { default as Collapsible } from "./Collapsible.vue"
+export { default as CollapsibleContent } from "./CollapsibleContent.vue"
+export { default as CollapsibleTrigger } from "./CollapsibleTrigger.vue"
diff --git a/packages/layer/app/components/ui/separator/Separator.vue b/packages/layer/app/components/ui/separator/Separator.vue
index 1ddb85ca..78d60eca 100644
--- a/packages/layer/app/components/ui/separator/Separator.vue
+++ b/packages/layer/app/components/ui/separator/Separator.vue
@@ -1,18 +1,18 @@
 <script setup lang="ts">
-import type { SeparatorProps } from 'reka-ui'
-import type { HTMLAttributes } from 'vue'
-import { reactiveOmit } from '@vueuse/core'
-import { Separator } from 'reka-ui'
-import { cn } from '~/utils/cn'
+import type { SeparatorProps } from "reka-ui"
+import type { HTMLAttributes } from "vue"
+import { reactiveOmit } from "@vueuse/core"
+import { Separator } from "reka-ui"
+import { cn } from "@/lib/utils"
 
 const props = withDefaults(defineProps<
-  SeparatorProps & { class?: HTMLAttributes['class'] }
+  SeparatorProps & { class?: HTMLAttributes["class"] }
 >(), {
-  orientation: 'horizontal',
+  orientation: "horizontal",
   decorative: true,
 })
 
-const delegatedProps = reactiveOmit(props, 'class')
+const delegatedProps = reactiveOmit(props, "class")
 </script>
 
 <template>
diff --git a/packages/layer/app/components/ui/separator/index.ts b/packages/layer/app/components/ui/separator/index.ts
new file mode 100644
index 00000000..44072873
--- /dev/null
+++ b/packages/layer/app/components/ui/separator/index.ts
@@ -0,0 +1 @@
+export { default as Separator } from "./Separator.vue"
diff --git a/packages/layer/app/components/ui/tabs/Tabs.vue b/packages/layer/app/components/ui/tabs/Tabs.vue
new file mode 100644
index 00000000..d260a15c
--- /dev/null
+++ b/packages/layer/app/components/ui/tabs/Tabs.vue
@@ -0,0 +1,24 @@
+<script setup lang="ts">
+import type { TabsRootEmits, TabsRootProps } from "reka-ui"
+import type { HTMLAttributes } from "vue"
+import { reactiveOmit } from "@vueuse/core"
+import { TabsRoot, useForwardPropsEmits } from "reka-ui"
+import { cn } from "@/lib/utils"
+
+const props = defineProps<TabsRootProps & { class?: HTMLAttributes["class"] }>()
+const emits = defineEmits<TabsRootEmits>()
+
+const delegatedProps = reactiveOmit(props, "class")
+const forwarded = useForwardPropsEmits(delegatedProps, emits)
+</script>
+
+<template>
+  <TabsRoot
+    v-slot="slotProps"
+    data-slot="tabs"
+    v-bind="forwarded"
+    :class="cn('flex flex-col gap-2', props.class)"
+  >
+    <slot v-bind="slotProps" />
+  </TabsRoot>
+</template>
diff --git a/packages/layer/app/components/ui/tabs/TabsContent.vue b/packages/layer/app/components/ui/tabs/TabsContent.vue
new file mode 100644
index 00000000..3186ee88
--- /dev/null
+++ b/packages/layer/app/components/ui/tabs/TabsContent.vue
@@ -0,0 +1,21 @@
+<script setup lang="ts">
+import type { TabsContentProps } from "reka-ui"
+import type { HTMLAttributes } from "vue"
+import { reactiveOmit } from "@vueuse/core"
+import { TabsContent } from "reka-ui"
+import { cn } from "@/lib/utils"
+
+const props = defineProps<TabsContentProps & { class?: HTMLAttributes["class"] }>()
+
+const delegatedProps = reactiveOmit(props, "class")
+</script>
+
+<template>
+  <TabsContent
+    data-slot="tabs-content"
+    :class="cn('flex-1 outline-none', props.class)"
+    v-bind="delegatedProps"
+  >
+    <slot />
+  </TabsContent>
+</template>
diff --git a/packages/layer/app/components/ui/tabs/TabsList.vue b/packages/layer/app/components/ui/tabs/TabsList.vue
new file mode 100644
index 00000000..a64a2dad
--- /dev/null
+++ b/packages/layer/app/components/ui/tabs/TabsList.vue
@@ -0,0 +1,24 @@
+<script setup lang="ts">
+import type { TabsListProps } from "reka-ui"
+import type { HTMLAttributes } from "vue"
+import { reactiveOmit } from "@vueuse/core"
+import { TabsList } from "reka-ui"
+import { cn } from "@/lib/utils"
+
+const props = defineProps<TabsListProps & { class?: HTMLAttributes["class"] }>()
+
+const delegatedProps = reactiveOmit(props, "class")
+</script>
+
+<template>
+  <TabsList
+    data-slot="tabs-list"
+    v-bind="delegatedProps"
+    :class="cn(
+      'bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]',
+      props.class,
+    )"
+  >
+    <slot />
+  </TabsList>
+</template>
diff --git a/packages/layer/app/components/ui/tabs/TabsTrigger.vue b/packages/layer/app/components/ui/tabs/TabsTrigger.vue
new file mode 100644
index 00000000..45e424f7
--- /dev/null
+++ b/packages/layer/app/components/ui/tabs/TabsTrigger.vue
@@ -0,0 +1,26 @@
+<script setup lang="ts">
+import type { TabsTriggerProps } from "reka-ui"
+import type { HTMLAttributes } from "vue"
+import { reactiveOmit } from "@vueuse/core"
+import { TabsTrigger, useForwardProps } from "reka-ui"
+import { cn } from "@/lib/utils"
+
+const props = defineProps<TabsTriggerProps & { class?: HTMLAttributes["class"] }>()
+
+const delegatedProps = reactiveOmit(props, "class")
+
+const forwardedProps = useForwardProps(delegatedProps)
+</script>
+
+<template>
+  <TabsTrigger
+    data-slot="tabs-trigger"
+    :class="cn(
+      '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',
+      props.class,
+    )"
+    v-bind="forwardedProps"
+  >
+    <slot />
+  </TabsTrigger>
+</template>
diff --git a/packages/layer/app/components/ui/tabs/index.ts b/packages/layer/app/components/ui/tabs/index.ts
new file mode 100644
index 00000000..7f99b7f2
--- /dev/null
+++ b/packages/layer/app/components/ui/tabs/index.ts
@@ -0,0 +1,4 @@
+export { default as Tabs } from "./Tabs.vue"
+export { default as TabsContent } from "./TabsContent.vue"
+export { default as TabsList } from "./TabsList.vue"
+export { default as TabsTrigger } from "./TabsTrigger.vue"
diff --git a/packages/layer/app/composables/useNavigation.ts b/packages/layer/app/composables/useNavigation.ts
index 1eb2fb7f..62bff040 100644
--- a/packages/layer/app/composables/useNavigation.ts
+++ b/packages/layer/app/composables/useNavigation.ts
@@ -27,7 +27,7 @@ function mapWithType(item: ContentNavigationItem): NavigationItem {
   }
 }
 
-export async function useNavigation() {
+export async function useNavigation(): Promise<{ data: Ref<NavigationItem[]> }> {
   const { data } = useAsyncData('navigation', () => {
     return queryCollectionNavigation('docs')
   }, {
diff --git a/packages/layer/app/lib/utils.ts b/packages/layer/app/lib/utils.ts
new file mode 100644
index 00000000..c66a9d9c
--- /dev/null
+++ b/packages/layer/app/lib/utils.ts
@@ -0,0 +1,7 @@
+import type { ClassValue } from "clsx"
+import { clsx } from "clsx"
+import { twMerge } from "tailwind-merge"
+
+export function cn(...inputs: ClassValue[]) {
+  return twMerge(clsx(inputs))
+}
diff --git a/packages/layer/app/pages/[...slug].vue b/packages/layer/app/pages/[...slug].vue
index 4597f534..3f3f6d1e 100644
--- a/packages/layer/app/pages/[...slug].vue
+++ b/packages/layer/app/pages/[...slug].vue
@@ -6,16 +6,15 @@ definePageMeta({
 const route = useRoute()
 
 const { data: page } = await useAsyncData(`docs-${route.path}`, () =>
-  queryCollection('docs').path(route.path).first(),
-)
+  queryCollection('docs').path(route.path).first())
 
 const { data: surround } = await useAsyncData(`surround-${route.path}`, () =>
-  queryCollectionItemSurroundings('docs', route.path),
-)
+  queryCollectionItemSurroundings('docs', route.path))
 
 // Extract TOC from page body
-const toc = computed(() => {
-  if (!page.value?.body) return []
+const _toc = computed(() => {
+  if (!page.value?.body)
+    return []
 
   const headings: { id: string, text: string, depth: number }[] = []
 
@@ -23,7 +22,7 @@ const toc = computed(() => {
     if (node.tag && node.tag.match(/^h[2-4]$/)) {
       const id = node.props?.id
       const text = extractText(node.children)
-      const depth = parseInt(node.tag.charAt(1))
+      const depth = Number.parseInt(node.tag.charAt(1))
       if (id && text) {
         headings.push({ id, text, depth })
       }
@@ -36,11 +35,14 @@ const toc = computed(() => {
   }
 
   function extractText(children: any[]): string {
-    if (!children) return ''
+    if (!children)
+      return ''
     return children
       .map((child) => {
-        if (typeof child === 'string') return child
-        if (child.children) return extractText(child.children)
+        if (typeof child === 'string')
+          return child
+        if (child.children)
+          return extractText(child.children)
         return ''
       })
       .join('')
@@ -68,7 +70,7 @@ useSeoMeta({
       :description="page.description"
     />
 
-    <Separator class="my-6" />
+    <UiSeparator class="my-6" />
 
     <div class="prose dark:prose-invert max-w-none">
       <ContentRenderer :value="page" />
diff --git a/packages/layer/app/pages/index.vue b/packages/layer/app/pages/index.vue
index 3dda9b81..26c4c8b8 100644
--- a/packages/layer/app/pages/index.vue
+++ b/packages/layer/app/pages/index.vue
@@ -4,8 +4,7 @@ definePageMeta({
 })
 
 const { data: page } = await useAsyncData('landing', () =>
-  queryCollection('landing').path('/').first(),
-)
+  queryCollection('landing').path('/').first())
 </script>
 
 <template>
diff --git a/packages/layer/app/plugins/ssr-width.ts b/packages/layer/app/plugins/ssr-width.ts
new file mode 100644
index 00000000..da7bf414
--- /dev/null
+++ b/packages/layer/app/plugins/ssr-width.ts
@@ -0,0 +1,5 @@
+import { provideSSRWidth } from '@vueuse/core'
+
+export default defineNuxtPlugin((nuxtApp) => {
+    provideSSRWidth(1024, nuxtApp.vueApp)
+})
diff --git a/packages/layer/app/utils/cn.ts b/packages/layer/app/utils/cn.ts
deleted file mode 100644
index abba253f..00000000
--- a/packages/layer/app/utils/cn.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import type { ClassValue } from 'clsx'
-import { clsx } from 'clsx'
-import { twMerge } from 'tailwind-merge'
-
-export function cn(...inputs: ClassValue[]) {
-  return twMerge(clsx(inputs))
-}
diff --git a/packages/layer/components.json b/packages/layer/components.json
new file mode 100644
index 00000000..b213dc8d
--- /dev/null
+++ b/packages/layer/components.json
@@ -0,0 +1,21 @@
+{
+  "$schema": "https://shadcn-vue.com/schema.json",
+  "style": "new-york",
+  "typescript": true,
+  "tailwind": {
+    "config": "",
+    "css": "app/assets/css/main.css",
+    "baseColor": "neutral",
+    "cssVariables": true,
+    "prefix": ""
+  },
+  "iconLibrary": "lucide",
+  "aliases": {
+    "components": "@/components",
+    "utils": "@/lib/utils",
+    "ui": "@/components/ui",
+    "lib": "@/lib",
+    "composables": "@/composables"
+  },
+  "registries": {}
+}
diff --git a/packages/layer/content.config.ts b/packages/layer/content.config.ts
index a9172952..456be9d3 100644
--- a/packages/layer/content.config.ts
+++ b/packages/layer/content.config.ts
@@ -1,4 +1,4 @@
-import { defineContentConfig, defineCollection, z } from '@nuxt/content'
+import { defineCollection, defineContentConfig, z } from '@nuxt/content'
 
 const docsSchema = z.object({
   links: z.array(z.object({
diff --git a/packages/layer/eslint.config.mjs b/packages/layer/eslint.config.mjs
new file mode 100644
index 00000000..6a85a89c
--- /dev/null
+++ b/packages/layer/eslint.config.mjs
@@ -0,0 +1,11 @@
+// @ts-check
+import antfu from '@antfu/eslint-config'
+import withNuxt from './.nuxt/eslint.config.mjs'
+
+export default withNuxt(
+  antfu({
+    type: 'lib',
+  }, {
+    ignores: ['**/dist/**', '**/.nuxt/**', '**/node_modules/**', 'app/components/ui/**' ],
+  }),
+)
diff --git a/packages/layer/modules/config.ts b/packages/layer/modules/config.ts
index b6d8eaa0..b63431aa 100644
--- a/packages/layer/modules/config.ts
+++ b/packages/layer/modules/config.ts
@@ -1,7 +1,7 @@
 import { defineNuxtModule } from '@nuxt/kit'
 import { defu } from 'defu'
-import { inferSiteURL, getPackageJsonMetadata } from '../utils/meta'
 import { getGitBranch, getGitEnv } from '../utils/git'
+import { getPackageJsonMetadata, inferSiteURL } from '../utils/meta'
 
 export default defineNuxtModule({
   meta: {
diff --git a/packages/layer/modules/css.ts b/packages/layer/modules/css.ts
index cb66ff15..21fa2b4b 100644
--- a/packages/layer/modules/css.ts
+++ b/packages/layer/modules/css.ts
@@ -1,4 +1,4 @@
-import { defineNuxtModule, addTemplate, createResolver } from '@nuxt/kit'
+import { addTemplate, createResolver, defineNuxtModule } from '@nuxt/kit'
 import { joinURL } from 'ufo'
 
 export default defineNuxtModule({
diff --git a/packages/layer/modules/shadcn.ts b/packages/layer/modules/shadcn.ts
new file mode 100644
index 00000000..07598923
--- /dev/null
+++ b/packages/layer/modules/shadcn.ts
@@ -0,0 +1,116 @@
+import { readdirSync, readFileSync } from 'node:fs'
+import { join } from 'node:path'
+import {
+    addComponent,
+    addComponentsDir,
+    createResolver,
+    defineNuxtModule,
+    findPath,
+    useLogger,
+} from '@nuxt/kit'
+import { parseSync } from 'oxc-parser'
+
+// Module options TypeScript interface definition
+export interface ModuleOptions {
+    /**
+     * Prefix for all the imported component.
+     * @default "Ui"
+     */
+    prefix?: string
+    /**
+     * Directory that the component lives in.
+     * Will respect the Nuxt aliases.
+     * @link https://nuxt.com/docs/api/nuxt-config#alias
+     * @default "@/components/ui"
+     */
+    componentDir?: string
+}
+
+export default defineNuxtModule<ModuleOptions>({
+    meta: {
+        name: 'shadcn',
+        configKey: 'shadcn',
+    },
+    defaults: {
+        prefix: 'Ui',
+        componentDir: '@/components/ui',
+    },
+    async setup({ prefix, componentDir }, nuxt) {
+        const COMPONENT_DIR_PATH = componentDir!
+        const ROOT_DIR_PATH = nuxt.options.rootDir
+
+        const logger = useLogger('shadcn-nuxt')
+        logger.start('Setting up shadcn-nuxt module', { COMPONENT_DIR_PATH, ROOT_DIR_PATH })
+
+        // Build list of potential component directory paths from all layers
+        // _layers[0] is the app, subsequent entries are extended layers
+        // We check all layers and find the first existing component directory
+        const potentialPaths: string[] = []
+
+        for (const layer of nuxt.options._layers) {
+            const layerRoot = layer.cwd
+            // Resolve component directory relative to layer root
+            const componentPath = COMPONENT_DIR_PATH.replace(/^@\//, '')
+
+            // Try app/ subdirectory first (Nuxt 4 layer structure)
+            potentialPaths.push(join(layerRoot, 'app', componentPath))
+            // Also try direct path (traditional structure)
+            potentialPaths.push(join(layerRoot, componentPath))
+        }
+
+        logger.info('Checking', { potentialPaths })
+        // Use findPath to find the first existing component directory
+        const componentsPath = (await findPath(potentialPaths, {}, 'dir')) || ROOT_DIR_PATH
+
+        logger.info('Decided on', { componentsPath })
+
+        // Create resolver relative to the found components path
+        const { resolve, resolvePath } = createResolver(componentsPath)
+
+        // Tell Nuxt to not scan `componentsDir` for auto imports as we will do it manually
+        // See https://github.com/unovue/shadcn-vue/pull/528#discussion_r1590206268
+        addComponentsDir({
+            path: componentsPath,
+            extensions: [],
+            ignore: ['**/*'],
+        }, {
+            prepend: true,
+        })
+
+        // Manually scan `componentsDir` for components and register them for auto imports
+        try {
+            await Promise.all(readdirSync(componentsPath).map(async (dir) => {
+                try {
+                    const filePath = await resolvePath(join(componentsPath, dir, 'index'), { extensions: ['.ts', '.js'] })
+                    const content = readFileSync(filePath, { encoding: 'utf8' })
+                    const ast = parseSync(filePath, content, {
+                        sourceType: 'module',
+                    })
+
+                    const exportedKeys: string[] = ast.program.body
+                        .filter(node => node.type === 'ExportNamedDeclaration')
+                        // @ts-expect-error parse return any
+                        .flatMap(node => node.specifiers?.map(specifier => specifier.exported?.name) || [])
+                        .filter((key: string) => /^[A-Z]/.test(key))
+
+                    exportedKeys.forEach((key) => {
+                        addComponent({
+                            name: `${prefix}${key}`, // name of the component to be used in vue templates
+                            export: key, // (optional) if the component is a named (rather than default) export
+                            filePath: resolve(filePath),
+                            priority: 1,
+                        })
+                    })
+                }
+                catch (err) {
+                    if (err instanceof Error)
+                        console.warn('Module error: ', err.message)
+                }
+            }))
+        }
+        catch (err) {
+            if (err instanceof Error)
+                console.warn(err.message)
+        }
+    },
+})
\ No newline at end of file
diff --git a/packages/layer/nuxt.config.ts b/packages/layer/nuxt.config.ts
index 23509408..0a6d2e4b 100644
--- a/packages/layer/nuxt.config.ts
+++ b/packages/layer/nuxt.config.ts
@@ -1,5 +1,5 @@
-import tailwindcss from '@tailwindcss/vite'
 import { createResolver } from '@nuxt/kit'
+import tailwindcss from '@tailwindcss/vite'
 
 const { resolve } = createResolver(import.meta.url)
 
@@ -7,23 +7,25 @@ export default defineNuxtConfig({
   modules: [
     resolve('./modules/config'),
     resolve('./modules/css'),
+    resolve('./modules/shadcn'),
     '@nuxtjs/color-mode',
     '@nuxt/content',
     '@nuxt/image',
     'nuxt-shiki',
     'nuxt-og-image',
+    '@nuxt/eslint',
   ],
-
   devtools: { enabled: true },
-
-  components: [
-    { path: resolve('./app/components') },
-    { path: resolve('./app/components/ui'), pathPrefix: false },
-    { path: resolve('./app/components/content'), global: true, pathPrefix: false },
-  ],
-
+  shadcn: {
+    /**
+     * Directory that the component lives in.
+     * Will respect the Nuxt aliases.
+     * @link https://nuxt.com/docs/api/nuxt-config#alias
+     * @default "@/components/ui"
+     */
+    componentDir: '@/components/ui',
+  },
   css: [resolve('./app/assets/css/main.css')],
-
   content: {
     build: {
       markdown: {
@@ -31,7 +33,6 @@ export default defineNuxtConfig({
       },
     },
   },
-
   shiki: {
     defaultTheme: {
       light: 'github-light-default',
@@ -53,17 +54,14 @@ export default defineNuxtConfig({
       'mdc',
     ],
   },
-
   colorMode: {
     classSuffix: '',
     preference: 'system',
     fallback: 'light',
   },
-
   vite: {
     plugins: [tailwindcss()],
   },
-
   nitro: {
     prerender: {
       crawlLinks: true,
@@ -71,6 +69,10 @@ export default defineNuxtConfig({
       autoSubfolderIndex: false,
     },
   },
-
+  eslint: {
+    config: {
+      standalone: false,
+    },
+  },
   compatibilityDate: '2025-01-01',
 })
diff --git a/packages/layer/package.json b/packages/layer/package.json
index 4d2f6a26..cc3b87b2 100644
--- a/packages/layer/package.json
+++ b/packages/layer/package.json
@@ -1,24 +1,24 @@
 {
   "name": "@pleaseai/docs",
+  "type": "module",
   "version": "0.1.0",
   "description": "Nuxt layer for documentation sites using shadcn-vue",
-  "type": "module",
-  "main": "./nuxt.config.ts",
+  "license": "MIT",
   "repository": {
     "type": "git",
     "url": "git+https://github.com/pleaseai/docs.git"
   },
-  "license": "MIT",
+  "main": "./nuxt.config.ts",
   "files": [
+    "README.md",
     "app",
+    "content.config.ts",
     "i18n",
     "lib",
     "modules",
-    "server",
-    "content.config.ts",
     "nuxt.config.ts",
     "nuxt.schema.ts",
-    "README.md"
+    "server"
   ],
   "scripts": {
     "dev": "nuxt dev",
@@ -26,30 +26,39 @@
     "generate": "nuxt generate",
     "preview": "nuxt preview",
     "postinstall": "nuxt prepare",
-    "typecheck": "vue-tsc -b"
+    "typecheck": "vue-tsc -b",
+    "lint": "eslint .",
+    "lint:fix": "eslint . --fix"
+  },
+  "peerDependencies": {
+    "nuxt": "^4.0.0"
   },
   "dependencies": {
     "@iconify-json/lucide": "^1.2.75",
     "@nuxt/content": "^3.8.2",
+    "@nuxt/eslint": "^1.11.0",
     "@nuxt/image": "^2.0.0",
     "@nuxt/kit": "^4.2.1",
     "@nuxtjs/color-mode": "^4.0.0",
     "@nuxtjs/mdc": "^0.18.4",
-    "@vueuse/core": "^13.9.0",
+    "@vueuse/core": "^14.1.0",
     "class-variance-authority": "^0.7.1",
     "clsx": "^2.1.1",
     "debug": "^4.4.1",
     "defu": "^6.1.4",
-    "lucide-vue-next": "^0.553.0",
+    "eslint": "^9.39.1",
+    "lucide-vue-next": "^0.555.0",
     "nuxt-og-image": "^5.1.12",
     "nuxt-shiki": "^0.3.1",
+    "oxc-parser": "^0.99.0",
     "parse5": "^7.3.0",
     "rehype-raw": "^7.0.0",
-    "reka-ui": "^2.2.1",
+    "reka-ui": "^2.6.0",
     "remark-emoji": "^5.0.1",
     "remark-gfm": "^4.0.1",
     "remark-mdc": "^3.5.1",
     "remark-rehype": "^11.1.2",
+    "shadcn-nuxt": "2.3.3",
     "slugify": "^1.6.6",
     "tailwind-merge": "^3.4.0",
     "tailwindcss": "^4.1.17",
@@ -58,12 +67,11 @@
     "unified": "^11.0.5",
     "unist-util-visit": "^5.0.0"
   },
-  "peerDependencies": {
-    "nuxt": "^4.0.0"
-  },
   "devDependencies": {
+    "@antfu/eslint-config": "^6.2.0",
     "@tailwindcss/vite": "^4.1.17",
     "better-sqlite3": "^11.9.1",
+    "typescript": "^5.9.3",
     "vue-tsc": "^2.0.0"
   }
 }
diff --git a/packages/layer/utils/git.ts b/packages/layer/utils/git.ts
index 4ba41831..f04f4c31 100644
--- a/packages/layer/utils/git.ts
+++ b/packages/layer/utils/git.ts
@@ -1,4 +1,5 @@
 import { execSync } from 'node:child_process'
+import process from 'node:process'
 
 export interface GitInfo {
   name: string
@@ -6,7 +7,7 @@ export interface GitInfo {
   url: string
 }
 
-export function getGitBranch() {
+export function getGitBranch(): string {
   const envName
     = process.env.CF_PAGES_BRANCH
       || process.env.CI_COMMIT_BRANCH
diff --git a/packages/layer/utils/meta.ts b/packages/layer/utils/meta.ts
index d46a8550..e0f772e3 100644
--- a/packages/layer/utils/meta.ts
+++ b/packages/layer/utils/meta.ts
@@ -1,7 +1,8 @@
 import { readFile } from 'node:fs/promises'
 import { resolve } from 'node:path'
+import process from 'node:process'
 
-export function inferSiteURL() {
+export function inferSiteURL(): string | undefined {
   return (
     process.env.NUXT_SITE_URL
     || (process.env.NEXT_PUBLIC_VERCEL_URL && `https://${process.env.NEXT_PUBLIC_VERCEL_URL}`)
@@ -11,7 +12,7 @@ export function inferSiteURL() {
   )
 }
 
-export async function getPackageJsonMetadata(dir: string) {
+export async function getPackageJsonMetadata(dir: string): Promise<{ name: string, description?: string }> {
   try {
     const packageJson = await readFile(resolve(dir, 'package.json'), 'utf-8')
     const parsed = JSON.parse(packageJson)

From 859c65be45813fd976b695987cb518e5f60d9058 Mon Sep 17 00:00:00 2001
From: Minsu Lee <amond@amond.net>
Date: Mon, 1 Dec 2025 14:50:04 +0900
Subject: [PATCH 2/5] fix(layer): resolve content collection and component
 issues in multi-layer setup

- Add useNuxt() to content.config.ts to resolve app's content directory
- Register content components globally via components:dirs hook
- Add CopyButton, CodeBlockCommand components and Icons.ts from shadcn-vue
- Add tooltip UI components via shadcn-vue CLI
- Add useConfig composable for package manager preference
- Fix container utility class definition for Tailwind CSS v4
- Add @tabler/icons-vue dependency for icon components
---
 bun.lock                                      |   9 +-
 packages/layer/app/assets/css/main.css        |  34 +-
 packages/layer/app/components/Icons.ts        | 327 ++++++++++++++++++
 .../components/content/CodeBlockCommand.vue   |  76 ++++
 .../app/components/content/CopyButton.vue     |  57 +++
 .../app/components/ui/tooltip/Tooltip.vue     |  19 +
 .../components/ui/tooltip/TooltipContent.vue  |  34 ++
 .../components/ui/tooltip/TooltipProvider.vue |  14 +
 .../components/ui/tooltip/TooltipTrigger.vue  |  15 +
 .../layer/app/components/ui/tooltip/index.ts  |   4 +
 packages/layer/app/composables/useConfig.ts   |  23 ++
 packages/layer/content.config.ts              |   7 +
 packages/layer/nuxt.config.ts                 |  12 +-
 packages/layer/package.json                   |   3 +-
 14 files changed, 623 insertions(+), 11 deletions(-)
 create mode 100644 packages/layer/app/components/Icons.ts
 create mode 100644 packages/layer/app/components/content/CodeBlockCommand.vue
 create mode 100644 packages/layer/app/components/content/CopyButton.vue
 create mode 100644 packages/layer/app/components/ui/tooltip/Tooltip.vue
 create mode 100644 packages/layer/app/components/ui/tooltip/TooltipContent.vue
 create mode 100644 packages/layer/app/components/ui/tooltip/TooltipProvider.vue
 create mode 100644 packages/layer/app/components/ui/tooltip/TooltipTrigger.vue
 create mode 100644 packages/layer/app/components/ui/tooltip/index.ts
 create mode 100644 packages/layer/app/composables/useConfig.ts

diff --git a/bun.lock b/bun.lock
index e52efd19..ae92a883 100644
--- a/bun.lock
+++ b/bun.lock
@@ -35,6 +35,7 @@
         "@nuxt/kit": "^4.2.1",
         "@nuxtjs/color-mode": "^4.0.0",
         "@nuxtjs/mdc": "^0.18.4",
+        "@tabler/icons-vue": "^3.35.0",
         "@vueuse/core": "^14.1.0",
         "class-variance-authority": "^0.7.1",
         "clsx": "^2.1.1",
@@ -47,7 +48,7 @@
         "oxc-parser": "^0.99.0",
         "parse5": "^7.3.0",
         "rehype-raw": "^7.0.0",
-        "reka-ui": "^2.6.0",
+        "reka-ui": "^2.6.1",
         "remark-emoji": "^5.0.1",
         "remark-gfm": "^4.0.1",
         "remark-mdc": "^3.5.1",
@@ -660,6 +661,10 @@
 
     "@swc/helpers": ["@swc/helpers@0.5.17", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="],
 
+    "@tabler/icons": ["@tabler/icons@3.35.0", "", {}, "sha512-yYXe+gJ56xlZFiXwV9zVoe3FWCGuZ/D7/G4ZIlDtGxSx5CGQK110wrnT29gUj52kEZoxqF7oURTk97GQxELOFQ=="],
+
+    "@tabler/icons-vue": ["@tabler/icons-vue@3.35.0", "", { "dependencies": { "@tabler/icons": "3.35.0" }, "peerDependencies": { "vue": ">=3.0.1" } }, "sha512-m5ugq8mWYfTzx0opMcX49ADFxr3xu0IhJaOddw8Djlhx30pBOPWwOiIUBMAqlgP9TFHAysdwqrq50hBw5DxPSQ=="],
+
     "@tailwindcss/node": ["@tailwindcss/node@4.1.17", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.17" } }, "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg=="],
 
     "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.17", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.17", "@tailwindcss/oxide-darwin-arm64": "4.1.17", "@tailwindcss/oxide-darwin-x64": "4.1.17", "@tailwindcss/oxide-freebsd-x64": "4.1.17", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17", "@tailwindcss/oxide-linux-arm64-musl": "4.1.17", "@tailwindcss/oxide-linux-x64-gnu": "4.1.17", "@tailwindcss/oxide-linux-x64-musl": "4.1.17", "@tailwindcss/oxide-wasm32-wasi": "4.1.17", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17", "@tailwindcss/oxide-win32-x64-msvc": "4.1.17" } }, "sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA=="],
@@ -2020,7 +2025,7 @@
 
     "rehype-sort-attributes": ["rehype-sort-attributes@5.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-Bxo+AKUIELcnnAZwJDt5zUDDRpt4uzhfz9d0PVGhcxYWsbFj5Cv35xuWxu5r1LeYNFNhgGqsr9Q2QiIOM/Qctg=="],
 
-    "reka-ui": ["reka-ui@2.6.0", "", { "dependencies": { "@floating-ui/dom": "^1.6.13", "@floating-ui/vue": "^1.1.6", "@internationalized/date": "^3.5.0", "@internationalized/number": "^3.5.0", "@tanstack/vue-virtual": "^3.12.0", "@vueuse/core": "^12.5.0", "@vueuse/shared": "^12.5.0", "aria-hidden": "^1.2.4", "defu": "^6.1.4", "ohash": "^2.0.11" }, "peerDependencies": { "vue": ">= 3.2.0" } }, "sha512-NrGMKrABD97l890mFS3TNUzB0BLUfbL3hh0NjcJRIUSUljb288bx3Mzo31nOyUcdiiW0HqFGXJwyCBh9cWgb0w=="],
+    "reka-ui": ["reka-ui@2.6.1", "", { "dependencies": { "@floating-ui/dom": "^1.6.13", "@floating-ui/vue": "^1.1.6", "@internationalized/date": "^3.5.0", "@internationalized/number": "^3.5.0", "@tanstack/vue-virtual": "^3.12.0", "@vueuse/core": "^12.5.0", "@vueuse/shared": "^12.5.0", "aria-hidden": "^1.2.4", "defu": "^6.1.4", "ohash": "^2.0.11" }, "peerDependencies": { "vue": ">= 3.2.0" } }, "sha512-XK7cJDQoNuGXfCNzBBo/81Yg/OgjPwvbabnlzXG2VsdSgNsT6iIkuPBPr+C0Shs+3bb0x0lbPvgQAhMSCKm5Ww=="],
 
     "remark-emoji": ["remark-emoji@5.0.2", "", { "dependencies": { "@types/mdast": "^4.0.4", "emoticon": "^4.0.1", "mdast-util-find-and-replace": "^3.0.1", "node-emoji": "^2.1.3", "unified": "^11.0.4" } }, "sha512-IyIqGELcyK5AVdLFafoiNww+Eaw/F+rGrNSXoKucjo95uL267zrddgxGM83GN1wFIb68pyDuAsY3m5t2Cav1pQ=="],
 
diff --git a/packages/layer/app/assets/css/main.css b/packages/layer/app/assets/css/main.css
index d3d55f64..dcf980b7 100644
--- a/packages/layer/app/assets/css/main.css
+++ b/packages/layer/app/assets/css/main.css
@@ -136,15 +136,35 @@
 }
 
 /* Utility classes */
-@utility container {
-  @apply mx-auto max-w-7xl px-4 sm:px-6 lg:px-8;
-}
+@layer utilities {
+  .container {
+    margin-left: auto;
+    margin-right: auto;
+    max-width: 80rem;
+    padding-left: 1rem;
+    padding-right: 1rem;
+  }
+
+  @media (min-width: 640px) {
+    .container {
+      padding-left: 1.5rem;
+      padding-right: 1.5rem;
+    }
+  }
 
-@utility no-scrollbar {
-  -ms-overflow-style: none;
-  scrollbar-width: none;
+  @media (min-width: 1024px) {
+    .container {
+      padding-left: 2rem;
+      padding-right: 2rem;
+    }
+  }
+
+  .no-scrollbar {
+    -ms-overflow-style: none;
+    scrollbar-width: none;
+  }
 
-  &::-webkit-scrollbar {
+  .no-scrollbar::-webkit-scrollbar {
     display: none;
   }
 }
diff --git a/packages/layer/app/components/Icons.ts b/packages/layer/app/components/Icons.ts
new file mode 100644
index 00000000..3cf71e24
--- /dev/null
+++ b/packages/layer/app/components/Icons.ts
@@ -0,0 +1,327 @@
+import type { VNode } from 'vue'
+import { FileIcon } from 'lucide-vue-next'
+import { defineComponent, h } from 'vue'
+
+interface IconProps {
+  class?: string
+  style?: Record<string, any>
+  [key: string]: any
+}
+
+function createIcon(svgContent: (props: IconProps) => VNode) {
+  return defineComponent({
+    name: 'Icon',
+    props: {
+      class: {
+        type: String,
+        default: '',
+      },
+    },
+    setup(props, { attrs }) {
+      return () => svgContent({ ...props, ...attrs })
+    },
+  })
+}
+
+export const Icons = {
+  logo: createIcon((props: IconProps) =>
+    h('svg', {
+      xmlns: 'http://www.w3.org/2000/svg',
+      viewBox: '0 0 256 256',
+      style: {
+        color: '#41B883',
+      },
+      ...props,
+    }, [
+      h('rect', { width: '256', height: '256', fill: 'none' }),
+      h('line', {
+        'x1': '208',
+        'y1': '128',
+        'x2': '128',
+        'y2': '208',
+        'fill': 'none',
+        'stroke': 'currentColor',
+        'stroke-linecap': 'round',
+        'stroke-linejoin': 'round',
+        'stroke-width': '32',
+      }),
+      h('line', {
+        'x1': '192',
+        'y1': '40',
+        'x2': '40',
+        'y2': '192',
+        'fill': 'none',
+        'stroke': 'currentColor',
+        'stroke-linecap': 'round',
+        'stroke-linejoin': 'round',
+        'stroke-width': '32',
+      }),
+    ]),
+  ),
+
+  twitter: createIcon((props: IconProps) =>
+    h('svg', {
+      height: '23',
+      viewBox: '0 0 1200 1227',
+      width: '23',
+      xmlns: 'http://www.w3.org/2000/svg',
+      ...props,
+    }, [
+      h('path', {
+        d: 'M714.163 519.284L1160.89 0H1055.03L667.137 450.887L357.328 0H0L468.492 681.821L0 1226.37H105.866L515.491 750.218L842.672 1226.37H1200L714.137 519.284H714.163ZM569.165 687.828L521.697 619.934L144.011 79.6944H306.615L611.412 515.685L658.88 583.579L1055.08 1150.3H892.476L569.165 687.854V687.828Z',
+      }),
+    ]),
+  ),
+
+  gitHub: createIcon((props: IconProps) =>
+    h('svg', {
+      viewBox: '0 0 438.549 438.549',
+      ...props,
+    }, [
+      h('path', {
+        fill: 'currentColor',
+        d: 'M409.132 114.573c-19.608-33.596-46.205-60.194-79.798-79.8-33.598-19.607-70.277-29.408-110.063-29.408-39.781 0-76.472 9.804-110.063 29.408-33.596 19.605-60.192 46.204-79.8 79.8C9.803 148.168 0 184.854 0 224.63c0 47.78 13.94 90.745 41.827 128.906 27.884 38.164 63.906 64.572 108.063 79.227 5.14.954 8.945.283 11.419-1.996 2.475-2.282 3.711-5.14 3.711-8.562 0-.571-.049-5.708-.144-15.417a2549.81 2549.81 0 01-.144-25.406l-6.567 1.136c-4.187.767-9.469 1.092-15.846 1-6.374-.089-12.991-.757-19.842-1.999-6.854-1.231-13.229-4.086-19.13-8.559-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-.951-2.568-2.098-3.711-3.429-1.142-1.331-1.997-2.663-2.568-3.997-.572-1.335-.098-2.43 1.427-3.289 1.525-.859 4.281-1.276 8.28-1.276l5.708.853c3.807.763 8.516 3.042 14.133 6.851 5.614 3.806 10.229 8.754 13.846 14.842 4.38 7.806 9.657 13.754 15.846 17.847 6.184 4.093 12.419 6.136 18.699 6.136 6.28 0 11.704-.476 16.274-1.423 4.565-.952 8.848-2.383 12.847-4.285 1.713-12.758 6.377-22.559 13.988-29.41-10.848-1.14-20.601-2.857-29.264-5.14-8.658-2.286-17.605-5.996-26.835-11.14-9.235-5.137-16.896-11.516-22.985-19.126-6.09-7.614-11.088-17.61-14.987-29.979-3.901-12.374-5.852-26.648-5.852-42.826 0-23.035 7.52-42.637 22.557-58.817-7.044-17.318-6.379-36.732 1.997-58.24 5.52-1.715 13.706-.428 24.554 3.853 10.85 4.283 18.794 7.952 23.84 10.994 5.046 3.041 9.089 5.618 12.135 7.708 17.705-4.947 35.976-7.421 54.818-7.421s37.117 2.474 54.823 7.421l10.849-6.849c7.419-4.57 16.18-8.758 26.262-12.565 10.088-3.805 17.802-4.853 23.134-3.138 8.562 21.509 9.325 40.922 2.279 58.24 15.036 16.18 22.559 35.787 22.559 58.817 0 16.178-1.958 30.497-5.853 42.966-3.9 12.471-8.941 22.457-15.125 29.979-6.191 7.521-13.901 13.85-23.131 18.986-9.232 5.14-18.182 8.85-26.84 11.136-8.662 2.286-18.415 4.004-29.263 5.146 9.894 8.562 14.842 22.077 14.842 40.539v60.237c0 3.422 1.19 6.279 3.572 8.562 2.379 2.279 6.136 2.95 11.276 1.995 44.163-14.653 80.185-41.062 108.068-79.226 27.88-38.161 41.825-81.126 41.825-128.906-.01-39.771-9.818-76.454-29.414-110.049z',
+      }),
+    ]),
+  ),
+
+  radix: createIcon((props: IconProps) =>
+    h('svg', {
+      viewBox: '0 0 25 25',
+      fill: 'none',
+      ...props,
+    }, [
+      h('path', {
+        d: 'M12 25C7.58173 25 4 21.4183 4 17C4 12.5817 7.58173 9 12 9V25Z',
+        fill: 'currentcolor',
+      }),
+      h('path', {
+        d: 'M12 0H4V8H12V0Z',
+        fill: 'currentcolor',
+      }),
+      h('path', {
+        d: 'M17 8C19.2091 8 21 6.20914 21 4C21 1.79086 19.2091 0 17 0C14.7909 0 13 1.79086 13 4C13 6.20914 14.7909 8 17 8Z',
+        fill: 'currentcolor',
+      }),
+    ]),
+  ),
+
+  aria: createIcon((props: IconProps) =>
+    h('svg', {
+      role: 'img',
+      viewBox: '0 0 24 24',
+      fill: 'currentColor',
+      ...props,
+    }, [
+      h('path', {
+        d: 'M13.966 22.624l-1.69-4.281H8.122l3.892-9.144 5.662 13.425zM8.884 1.376H0v21.248zm15.116 0h-8.884L24 22.624Z',
+      }),
+    ]),
+  ),
+
+  npm: createIcon((props: IconProps) =>
+    h('svg', {
+      viewBox: '0 0 24 24',
+      ...props,
+    }, [
+      h('path', {
+        d: 'M1.763 0C.786 0 0 .786 0 1.763v20.474C0 23.214.786 24 1.763 24h20.474c.977 0 1.763-.786 1.763-1.763V1.763C24 .786 23.214 0 22.237 0zM5.13 5.323l13.837.019-.009 13.836h-3.464l.01-10.382h-3.456L12.04 19.17H5.113z',
+        fill: 'currentColor',
+      }),
+    ]),
+  ),
+
+  yarn: createIcon((props: IconProps) =>
+    h('svg', {
+      viewBox: '0 0 24 24',
+      ...props,
+    }, [
+      h('path', {
+        d: 'M12 0C5.375 0 0 5.375 0 12s5.375 12 12 12 12-5.375 12-12S18.625 0 12 0zm.768 4.105c.183 0 .363.053.525.157.125.083.287.185.755 1.154.31-.088.468-.042.551-.019.204.056.366.19.463.375.477.917.542 2.553.334 3.605-.241 1.232-.755 2.029-1.131 2.576.324.329.778.899 1.117 1.825.278.774.31 1.478.273 2.015a5.51 5.51 0 0 0 .602-.329c.593-.366 1.487-.917 2.553-.931.714-.009 1.269.445 1.353 1.103a1.23 1.23 0 0 1-.945 1.362c-.649.158-.95.278-1.821.843-1.232.797-2.539 1.242-3.012 1.39a1.686 1.686 0 0 1-.704.343c-.737.181-3.266.315-3.466.315h-.046c-.783 0-1.214-.241-1.45-.491-.658.329-1.51.19-2.122-.134a1.078 1.078 0 0 1-.58-1.153 1.243 1.243 0 0 1-.153-.195c-.162-.25-.528-.936-.454-1.946.056-.723.556-1.367.88-1.71a5.522 5.522 0 0 1 .408-2.256c.306-.727.885-1.348 1.32-1.737-.32-.537-.644-1.367-.329-2.21.227-.602.412-.936.82-1.08h-.005c.199-.074.389-.153.486-.259a3.418 3.418 0 0 1 2.298-1.103c.037-.093.079-.185.125-.283.31-.658.639-1.029 1.024-1.168a.94.94 0 0 1 .328-.06zm.006.7c-.507.016-1.001 1.519-1.001 1.519s-1.27-.204-2.266.871c-.199.218-.468.334-.746.44-.079.028-.176.023-.417.672-.371.991.625 2.094.625 2.094s-1.186.839-1.626 1.881c-.486 1.144-.338 2.261-.338 2.261s-.843.732-.899 1.487c-.051.663.139 1.2.343 1.515.227.343.51.176.51.176s-.561.653-.037.931c.477.25 1.283.394 1.71-.037.31-.31.371-1.001.486-1.283.028-.065.12.111.209.199.097.093.264.195.264.195s-.755.324-.445 1.066c.102.246.468.403 1.066.398.222-.005 2.664-.139 3.313-.296.375-.088.505-.283.505-.283s1.566-.431 2.998-1.357c.917-.598 1.293-.76 2.034-.936.612-.148.57-1.098-.241-1.084-.839.009-1.575.44-2.196.825-1.163.718-1.742.672-1.742.672l-.018-.032c-.079-.13.371-1.293-.134-2.678-.547-1.515-1.413-1.881-1.344-1.997.297-.5 1.038-1.297 1.334-2.78.176-.899.13-2.377-.269-3.151-.074-.144-.732.241-.732.241s-.616-1.371-.788-1.483a.271.271 0 0 0-.157-.046z',
+        fill: 'currentColor',
+      }),
+    ]),
+  ),
+
+  pnpm: createIcon((props: IconProps) =>
+    h('svg', {
+      viewBox: '0 0 24 24',
+      ...props,
+    }, [
+      h('path', {
+        d: 'M0 0v7.5h7.5V0zm8.25 0v7.5h7.498V0zm8.25 0v7.5H24V0zM8.25 8.25v7.5h7.498v-7.5zm8.25 0v7.5H24v-7.5zM0 16.5V24h7.5v-7.5zm8.25 0V24h7.498v-7.5zm8.25 0V24H24v-7.5z',
+        fill: 'currentColor',
+      }),
+    ]),
+  ),
+
+  react: createIcon((props: IconProps) =>
+    h('svg', {
+      viewBox: '0 0 24 24',
+      ...props,
+    }, [
+      h('path', {
+        d: 'M14.23 12.004a2.236 2.236 0 0 1-2.235 2.236 2.236 2.236 0 0 1-2.236-2.236 2.236 2.236 0 0 1 2.235-2.236 2.236 2.236 0 0 1 2.236 2.236zm2.648-10.69c-1.346 0-3.107.96-4.888 2.622-1.78-1.653-3.542-2.602-4.887-2.602-.41 0-.783.093-1.106.278-1.375.793-1.683 3.264-.973 6.365C1.98 8.917 0 10.42 0 12.004c0 1.59 1.99 3.097 5.043 4.03-.704 3.113-.39 5.588.988 6.38.32.187.69.275 1.102.275 1.345 0 3.107-.96 4.888-2.624 1.78 1.654 3.542 2.603 4.887 2.603.41 0 .783-.09 1.106-.275 1.374-.792 1.683-3.263.973-6.365C22.02 15.096 24 13.59 24 12.004c0-1.59-1.99-3.097-5.043-4.032.704-3.11.39-5.587-.988-6.38-.318-.184-.688-.277-1.092-.278zm-.005 1.09v.006c.225 0 .406.044.558.127.666.382.955 1.835.73 3.704-.054.46-.142.945-.25 1.44-.96-.236-2.006-.417-3.107-.534-.66-.905-1.345-1.727-2.035-2.447 1.592-1.48 3.087-2.292 4.105-2.295zm-9.77.02c1.012 0 2.514.808 4.11 2.28-.686.72-1.37 1.537-2.02 2.442-1.107.117-2.154.298-3.113.538-.112-.49-.195-.964-.254-1.42-.23-1.868.054-3.32.714-3.707.19-.09.4-.127.563-.132zm4.882 3.05c.455.468.91.992 1.36 1.564-.44-.02-.89-.034-1.345-.034-.46 0-.915.01-1.36.034.44-.572.895-1.096 1.345-1.565zM12 8.1c.74 0 1.477.034 2.202.093.406.582.802 1.203 1.183 1.86.372.64.71 1.29 1.018 1.946-.308.655-.646 1.31-1.013 1.95-.38.66-.773 1.288-1.18 1.87-.728.063-1.466.098-2.21.098-.74 0-1.477-.035-2.202-.093-.406-.582-.802-1.204-1.183-1.86-.372-.64-.71-1.29-1.018-1.946.303-.657.646-1.313 1.013-1.954.38-.66.773-1.286 1.18-1.868.728-.064 1.466-.098 2.21-.098zm-3.635.254c-.24.377-.48.763-.704 1.16-.225.39-.435.782-.635 1.174-.265-.656-.49-1.31-.676-1.947.64-.15 1.315-.283 2.015-.386zm7.26 0c.695.103 1.365.23 2.006.387-.18.632-.405 1.282-.66 1.933-.2-.39-.41-.783-.64-1.174-.225-.392-.465-.774-.705-1.146zm3.063.675c.484.15.944.317 1.375.498 1.732.74 2.852 1.708 2.852 2.476-.005.768-1.125 1.74-2.857 2.475-.42.18-.88.342-1.355.493-.28-.958-.646-1.956-1.1-2.98.45-1.017.81-2.01 1.085-2.964zm-13.395.004c.278.96.645 1.957 1.1 2.98-.45 1.017-.812 2.01-1.086 2.964-.484-.15-.944-.318-1.37-.5-1.732-.737-2.852-1.706-2.852-2.474 0-.768 1.12-1.742 2.852-2.476.42-.18.88-.342 1.356-.494zm11.678 4.28c.265.657.49 1.312.676 1.948-.64.157-1.316.29-2.016.39.24-.375.48-.762.705-1.158.225-.39.435-.788.636-1.18zm-9.945.02c.2.392.41.783.64 1.175.23.39.465.772.705 1.143-.695-.102-1.365-.23-2.006-.386.18-.63.406-1.282.66-1.933zM17.92 16.32c.112.493.2.968.254 1.423.23 1.868-.054 3.32-.714 3.708-.147.09-.338.128-.563.128-1.012 0-2.514-.807-4.11-2.28.686-.72 1.37-1.536 2.02-2.44 1.107-.118 2.154-.3 3.113-.54zm-11.83.01c.96.234 2.006.415 3.107.532.66.905 1.345 1.727 2.035 2.446-1.595 1.483-3.092 2.295-4.11 2.295-.22-.005-.406-.05-.553-.132-.666-.38-.955-1.834-.73-3.703.054-.46.142-.944.25-1.438zm4.56.64c.44.02.89.034 1.345.034.46 0 .915-.01 1.36-.034-.44.572-.895 1.095-1.345 1.565-.455-.47-.91-.993-1.36-1.565z',
+        fill: 'currentColor',
+      }),
+    ]),
+  ),
+
+  tailwind: createIcon((props: IconProps) =>
+    h('svg', {
+      viewBox: '0 0 24 24',
+      ...props,
+    }, [
+      h('path', {
+        d: 'M12.001,4.8c-3.2,0-5.2,1.6-6,4.8c1.2-1.6,2.6-2.2,4.2-1.8c0.913,0.228,1.565,0.89,2.288,1.624 C13.666,10.618,15.027,12,18.001,12c3.2,0,5.2-1.6,6-4.8c-1.2,1.6-2.6,2.2-4.2,1.8c-0.913-0.228-1.565-0.89-2.288-1.624 C16.337,6.182,14.976,4.8,12.001,4.8z M6.001,12c-3.2,0-5.2,1.6-6,4.8c1.2-1.6,2.6-2.2,4.2-1.8c0.913,0.228,1.565,0.89,2.288,1.624 c1.177,1.194,2.538,2.576,5.512,2.576c3.2,0,5.2-1.6,6-4.8c-1.2,1.6-2.6,2.2-4.2,1.8c-0.913-0.228-1.565-0.89-2.288-1.624 C10.337,13.382,8.976,12,6.001,12z',
+        fill: 'currentColor',
+      }),
+    ]),
+  ),
+
+  google: createIcon((props: IconProps) =>
+    h('svg', {
+      role: 'img',
+      viewBox: '0 0 24 24',
+      ...props,
+    }, [
+      h('path', {
+        fill: 'currentColor',
+        d: 'M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z',
+      }),
+    ]),
+  ),
+
+  apple: createIcon((props: IconProps) =>
+    h('svg', {
+      role: 'img',
+      viewBox: '0 0 24 24',
+      ...props,
+    }, [
+      h('path', {
+        d: 'M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701',
+        fill: 'currentColor',
+      }),
+    ]),
+  ),
+
+  paypal: createIcon((props: IconProps) =>
+    h('svg', {
+      role: 'img',
+      viewBox: '0 0 24 24',
+      ...props,
+    }, [
+      h('path', {
+        d: 'M7.076 21.337H2.47a.641.641 0 0 1-.633-.74L4.944.901C5.026.382 5.474 0 5.998 0h7.46c2.57 0 4.578.543 5.69 1.81 1.01 1.15 1.304 2.42 1.012 4.287-.023.143-.047.288-.077.437-.983 5.05-4.349 6.797-8.647 6.797h-2.19c-.524 0-.968.382-1.05.9l-1.12 7.106zm14.146-14.42a3.35 3.35 0 0 0-.607-.541c-.013.076-.026.175-.041.254-.93 4.778-4.005 7.201-9.138 7.201h-2.19a.563.563 0 0 0-.556.479l-1.187 7.527h-.506l-.24 1.516a.56.56 0 0 0 .554.647h3.882c.46 0 .85-.334.922-.788.06-.26.76-4.852.816-5.09a.932.932 0 0 1 .923-.788h.58c3.76 0 6.705-1.528 7.565-5.946.36-1.847.174-3.388-.777-4.471z',
+        fill: 'currentColor',
+      }),
+    ]),
+  ),
+
+  spinner: createIcon((props: IconProps) =>
+    h('svg', {
+      'xmlns': 'http://www.w3.org/2000/svg',
+      'width': '24',
+      'height': '24',
+      'viewBox': '0 0 24 24',
+      'fill': 'none',
+      'stroke': 'currentColor',
+      'stroke-width': '2',
+      'stroke-linecap': 'round',
+      'stroke-linejoin': 'round',
+      ...props,
+    }, [
+      h('path', { d: 'M21 12a9 9 0 1 1-6.219-8.56' }),
+    ]),
+  ),
+
+  json: createIcon((props: IconProps) =>
+    h('svg', {
+      xmlns: 'http://www.w3.org/2000/svg',
+      viewBox: '0 0 24 24',
+      ...props,
+    }, [
+      h('path', {
+        fill: 'currentColor',
+        d: 'M12.043 23.968c.479-.004.953-.029 1.426-.094a11.805 11.805 0 0 0 3.146-.863 12.404 12.404 0 0 0 3.793-2.542 11.977 11.977 0 0 0 2.44-3.427 11.794 11.794 0 0 0 1.02-3.476c.149-1.16.135-2.346-.045-3.499a11.96 11.96 0 0 0-.793-2.788 11.197 11.197 0 0 0-.854-1.617c-1.168-1.837-2.861-3.314-4.81-4.3a12.835 12.835 0 0 0-2.172-.87h-.005c.119.063.24.132.345.201.12.074.239.146.351.225a8.93 8.93 0 0 1 1.559 1.33c1.063 1.145 1.797 2.548 2.218 4.041.284.982.434 1.998.495 3.017.044.743.044 1.491-.047 2.229-.149 1.27-.554 2.51-1.228 3.596a7.475 7.475 0 0 1-1.903 2.084c-1.244.928-2.877 1.482-4.436 1.114a3.916 3.916 0 0 1-.748-.258 4.692 4.692 0 0 1-.779-.45 6.08 6.08 0 0 1-1.244-1.105 6.507 6.507 0 0 1-1.049-1.747 7.366 7.366 0 0 1-.494-2.54c-.03-1.273.225-2.553.854-3.67a6.43 6.43 0 0 1 1.663-1.918c.225-.178.464-.333.704-.479l.016-.007a5.121 5.121 0 0 0-1.441-.12 4.963 4.963 0 0 0-1.228.24c-.359.12-.704.27-1.019.45a6.146 6.146 0 0 0-.733.494c-.211.18-.42.36-.615.555-1.123 1.153-1.768 2.682-2.022 4.256-.15.973-.15 1.96-.091 2.95.105 1.395.391 2.787.945 4.062a8.518 8.518 0 0 0 1.348 2.173 8.14 8.14 0 0 0 3.132 2.23 7.934 7.934 0 0 0 2.113.54c.074.015.149.015.209.015zm-2.934-.398a4.102 4.102 0 0 1-.45-.228 8.5 8.5 0 0 1-2.038-1.534c-1.094-1.137-1.827-2.566-2.247-4.08a15.184 15.184 0 0 1-.495-3.172 12.14 12.14 0 0 1 .046-2.082c.135-1.257.495-2.501 1.124-3.58a6.889 6.889 0 0 1 1.783-2.053 6.23 6.23 0 0 1 1.633-.9 5.363 5.363 0 0 1 3.522-.045c.029 0 .029 0 .045.03.015.015.045.015.06.03.045.016.104.045.165.074.239.12.479.271.704.42a6.294 6.294 0 0 1 2.097 2.502c.42.914.615 1.934.631 2.938.014 1.079-.18 2.157-.645 3.146a6.42 6.42 0 0 1-2.638 2.832c.09.03.18.045.271.075.225.044.449.074.688.074 1.468.045 2.892-.66 3.94-1.647.195-.18.375-.375.54-.585.225-.27.435-.54.614-.823.239-.375.435-.75.614-1.154a8.112 8.112 0 0 0 .509-1.664c.196-1.004.211-2.022.149-3.026-.135-2.022-.673-4.045-1.842-5.724a9.054 9.054 0 0 0-.555-.719 9.868 9.868 0 0 0-1.063-1.034 8.477 8.477 0 0 0-1.363-.915 9.927 9.927 0 0 0-1.692-.598l-.3-.06c-.209-.03-.42-.044-.634-.06a8.453 8.453 0 0 0-1.015.016c-.704.045-1.412.16-2.112.337C5.799 1.227 2.863 3.566 1.3 6.67A11.834 11.834 0 0 0 .238 9.801a11.81 11.81 0 0 0-.104 3.775c.12 1.02.374 2.023.778 2.977.227.57.511 1.124.825 1.648 1.094 1.783 2.683 3.236 4.51 4.24.688.39 1.408.69 2.157.944.226.074.45.15.689.21z',
+      }),
+    ])),
+
+  ts: createIcon((props: IconProps) =>
+    h('svg', {
+      xmlns: 'http://www.w3.org/2000/svg',
+      viewBox: '0 0 24 24',
+      ...props,
+    }, [
+      h('path', {
+        fill: 'currentColor',
+        d: 'M1.125 0C.502 0 0 .502 0 1.125v21.75C0 23.498.502 24 1.125 24h21.75c.623 0 1.125-.502 1.125-1.125V1.125C24 .502 23.498 0 22.875 0zm17.363 9.75c.612 0 1.154.037 1.627.111a6.38 6.38 0 0 1 1.306.34v2.458a3.95 3.95 0 0 0-.643-.361 5.093 5.093 0 0 0-.717-.26 5.453 5.453 0 0 0-1.426-.2c-.3 0-.573.028-.819.086a2.1 2.1 0 0 0-.623.242c-.17.104-.3.229-.393.374a.888.888 0 0 0-.14.49c0 .196.053.373.156.529.104.156.252.304.443.444s.423.276.696.41c.273.135.582.274.926.416.47.197.892.407 1.266.628.374.222.695.473.963.753.268.279.472.598.614.957.142.359.214.776.214 1.253 0 .657-.125 1.21-.373 1.656a3.033 3.033 0 0 1-1.012 1.085 4.38 4.38 0 0 1-1.487.596c-.566.12-1.163.18-1.79.18a9.916 9.916 0 0 1-1.84-.164 5.544 5.544 0 0 1-1.512-.493v-2.63a5.033 5.033 0 0 0 3.237 1.2c.333 0 .624-.03.872-.09.249-.06.456-.144.623-.25.166-.108.29-.234.373-.38a1.023 1.023 0 0 0-.074-1.089 2.12 2.12 0 0 0-.537-.5 5.597 5.597 0 0 0-.807-.444 27.72 27.72 0 0 0-1.007-.436c-.918-.383-1.602-.852-2.053-1.405-.45-.553-.676-1.222-.676-2.005 0-.614.123-1.141.369-1.582.246-.441.58-.804 1.004-1.089a4.494 4.494 0 0 1 1.47-.629 7.536 7.536 0 0 1 1.77-.201zm-15.113.188h9.563v2.166H9.506v9.646H6.789v-9.646H3.375z',
+      }),
+    ])),
+
+  css: createIcon((props: IconProps) =>
+    h('svg', {
+      xmlns: 'http://www.w3.org/2000/svg',
+      viewBox: '0 0 24 24',
+      ...props,
+    }, [
+      h('path', {
+        fill: 'currentColor',
+        d: 'M0 0v20.16A3.84 3.84 0 0 0 3.84 24h16.32A3.84 3.84 0 0 0 24 20.16V3.84A3.84 3.84 0 0 0 20.16 0Zm14.256 13.08c1.56 0 2.28 1.08 2.304 2.64h-1.608c.024-.288-.048-.6-.144-.84-.096-.192-.288-.264-.552-.264-.456 0-.696.264-.696.84-.024.576.288.888.768 1.08.72.288 1.608.744 1.92 1.296q.432.648.432 1.656c0 1.608-.912 2.592-2.496 2.592-1.656 0-2.4-1.032-2.424-2.688h1.68c0 .792.264 1.176.792 1.176.264 0 .456-.072.552-.24.192-.312.24-1.176-.048-1.512-.312-.408-.912-.6-1.32-.816q-.828-.396-1.224-.936c-.24-.36-.36-.888-.36-1.536 0-1.44.936-2.472 2.424-2.448m5.4 0c1.584 0 2.304 1.08 2.328 2.64h-1.608c0-.288-.048-.6-.168-.84-.096-.192-.264-.264-.528-.264-.48 0-.72.264-.72.84s.288.888.792 1.08c.696.288 1.608.744 1.92 1.296.264.432.408.984.408 1.656.024 1.608-.888 2.592-2.472 2.592-1.68 0-2.424-1.056-2.448-2.688h1.68c0 .744.264 1.176.792 1.176.264 0 .456-.072.552-.24.216-.312.264-1.176-.048-1.512-.288-.408-.888-.6-1.32-.816-.552-.264-.96-.576-1.2-.936s-.36-.888-.36-1.536c-.024-1.44.912-2.472 2.4-2.448m-11.031.018c.711-.006 1.419.198 1.839.63.432.432.672 1.128.648 1.992H9.336c.024-.456-.096-.792-.432-.96-.312-.144-.768-.048-.888.24-.12.264-.192.576-.168.864v3.504c0 .744.264 1.128.768 1.128a.65.65 0 0 0 .552-.264c.168-.24.192-.552.168-.84h1.776c.096 1.632-.984 2.712-2.568 2.688-1.536 0-2.496-.864-2.472-2.472v-4.032c0-.816.24-1.44.696-1.848.432-.408 1.146-.624 1.857-.63',
+      }),
+    ])),
+
+  bash: createIcon((props: IconProps) =>
+    h('svg', {
+      xmlns: 'http://www.w3.org/2000/svg',
+      viewBox: '0 0 24 24',
+      ...props,
+    }, [
+      h('path', {
+        fill: 'currentColor',
+        d: 'M21.038 4.9 13.461.402a2.86 2.86 0 0 0-2.923.001L2.961 4.9A3.023 3.023 0 0 0 1.5 7.503v8.995c0 1.073.557 2.066 1.462 2.603l7.577 4.497a2.86 2.86 0 0 0 2.922 0l7.577-4.497a3.023 3.023 0 0 0 1.462-2.603V7.503A3.021 3.021 0 0 0 21.038 4.9zM15.17 18.946l.013.646c.001.078-.05.167-.111.198l-.383.22c-.061.031-.111-.007-.112-.085l-.007-.635c-.328.136-.66.169-.872.084-.04-.016-.057-.075-.041-.142l.139-.584a.24.24 0 0 1 .069-.121.163.163 0 0 1 .036-.026c.022-.011.043-.014.062-.006.229.077.521.041.802-.101.357-.181.596-.545.592-.907-.003-.328-.181-.465-.613-.468-.55.001-1.064-.107-1.072-.917-.007-.667.34-1.361.889-1.8l-.007-.652c-.001-.08.048-.168.111-.2l.37-.236c.061-.031.111.007.112.087l.006.653c.273-.109.511-.138.726-.088.047.012.067.076.048.151l-.144.578a.255.255 0 0 1-.065.116.161.161 0 0 1-.038.028.083.083 0 0 1-.057.009c-.098-.022-.332-.073-.699.113-.385.195-.52.53-.517.778.003.297.155.387.681.396.7.012 1.003.318 1.01 1.023.007.689-.362 1.433-.928 1.888zm3.973-1.087c0 .06-.008.116-.058.145l-1.916 1.164c-.05.029-.09.004-.09-.056v-.494c0-.06.037-.093.087-.122l1.887-1.129c.05-.029.09-.004.09.056v.436zm1.316-11.062-7.168 4.427c-.894.523-1.553 1.109-1.553 2.187v8.833c0 .645.26 1.063.66 1.184a2.304 2.304 0 0 1-.398.039c-.42 0-.833-.114-1.197-.33L3.226 18.64a2.494 2.494 0 0 1-1.201-2.142V7.503c0-.881.46-1.702 1.201-2.142L10.803.863a2.342 2.342 0 0 1 2.394 0l7.577 4.498a2.479 2.479 0 0 1 1.164 1.732c-.252-.536-.818-.682-1.479-.296z',
+      }),
+    ])),
+
+  vue: createIcon((props: IconProps) =>
+    h(
+      'svg',
+      {
+        viewBox: '0 0 261.76 226.69',
+        xmlns: 'http://www.w3.org/2000/svg',
+        class: props.class,
+        style: props.style,
+        ...props,
+      },
+      [
+        h('path', {
+          d: 'M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z',
+          fill: 'currentColor',
+        }),
+        h('path', {
+          d: 'M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z',
+          fill: 'currentColor',
+        }),
+      ],
+    ),
+  ),
+}
+
+export function getIconForLanguageExtension(language: string) {
+  switch (language) {
+    case 'json':
+      return Icons.json
+    case 'css':
+      return Icons.css
+    case 'js':
+    case 'jsx':
+    case 'ts':
+    case 'tsx':
+    case 'typescript':
+      return Icons.ts
+    case 'vue':
+      return Icons.vue
+    default:
+      return FileIcon
+  }
+}
diff --git a/packages/layer/app/components/content/CodeBlockCommand.vue b/packages/layer/app/components/content/CodeBlockCommand.vue
new file mode 100644
index 00000000..9e90da48
--- /dev/null
+++ b/packages/layer/app/components/content/CodeBlockCommand.vue
@@ -0,0 +1,76 @@
+<script setup lang="ts">
+import { TerminalIcon } from 'lucide-vue-next'
+import {
+  Tabs,
+  TabsContent,
+  TabsList,
+  TabsTrigger,
+} from '@/components/ui/tabs'
+
+const props = defineProps<{
+  code: string
+}>()
+
+const tabs = computed(() => {
+  const data = { pnpm: '', npm: '', yarn: '', bun: '' }
+
+  if (props.code.includes('npm install')) {
+    data.npm = props.code
+    data.yarn = props.code.replaceAll('npm install', 'yarn add')
+    data.pnpm = props.code.replaceAll('npm install', 'pnpm add')
+    data.bun = props.code.replaceAll('npm install', 'bun add')
+  }
+  else if (props.code.includes('npx create-')) {
+    data.npm = props.code
+    data.yarn = props.code.replaceAll('npx create-', 'yarn create')
+    data.pnpm = props.code.replaceAll('npx create-', 'pnpm create')
+    data.bun = props.code.replaceAll('npx', 'bunx --bun')
+  }
+  else if (props.code.includes('npm create')) {
+    data.npm = props.code
+    data.yarn = props.code.replaceAll('npm create', 'yarn create')
+    data.pnpm = props.code.replaceAll('npm create', 'pnpm create')
+    data.bun = props.code.replaceAll('npm create', 'bun create')
+  }
+  else if (props.code.includes('npx')) {
+    data.npm = props.code
+    data.yarn = props.code.replaceAll('npx', 'yarn dlx')
+    data.pnpm = props.code.replaceAll('npx', 'pnpm dlx')
+    data.bun = props.code.replaceAll('npx', 'bunx --bun')
+  }
+  else if (props.code.includes('npm run')) {
+    data.npm = props.code
+    data.yarn = props.code.replaceAll('npm run', 'yarn')
+    data.pnpm = props.code.replaceAll('npm run', 'pnpm')
+    data.bun = props.code.replaceAll('npm run', 'bun')
+  }
+
+  return data
+})
+
+const { config } = useConfig()
+</script>
+
+<template>
+  <div class="overflow-x-auto">
+    <Tabs v-model="config.packageManager" class="gap-0">
+      <div class="border-border/50 flex items-center gap-2 border-b px-3 py-1">
+        <div class="bg-foreground flex size-4 items-center justify-center rounded-[1px] opacity-70">
+          <TerminalIcon class="text-code size-3" />
+        </div>
+        <TabsList class="rounded-none bg-transparent p-0">
+          <TabsTrigger v-for="key in Object.keys(tabs)" :key="key" :value="key" class="data-[state=active]:bg-accent data-[state=active]:border-input h-7 border border-transparent pt-0.5 data-[state=active]:shadow-none">
+            {{ key }}
+          </TabsTrigger>
+        </TabsList>
+      </div>
+
+      <div class="no-scrollbar overflow-x-auto">
+        <TabsContent v-for="([key, value]) in Object.entries(tabs)" :key="key" :value="key" class="mt-0 px-4 py-3.5">
+          <pre class="language-bash shiki shiki-themes github-light-default github-dark"><code class="relative font-mono text-sm leading-none"><span class="line"><span>{{ value }}</span></span></code></pre>
+        </TabsContent>
+      </div>
+    </Tabs>
+    <CopyButton class="absolute top-2 right-2 z-10 size-7 opacity-70 hover:opacity-100 focus-visible:opacity-100" :value="tabs[config.packageManager]" />
+  </div>
+</template>
diff --git a/packages/layer/app/components/content/CopyButton.vue b/packages/layer/app/components/content/CopyButton.vue
new file mode 100644
index 00000000..2ffdb970
--- /dev/null
+++ b/packages/layer/app/components/content/CopyButton.vue
@@ -0,0 +1,57 @@
+<script setup lang="ts">
+import type { HTMLAttributes } from 'vue'
+import type { ButtonVariants } from '@/components/ui/button'
+import { IconCheck, IconCopy } from '@tabler/icons-vue'
+import { useClipboard } from '@vueuse/core'
+
+import { toRefs } from 'vue'
+
+import { cn } from '~/lib/utils'
+import { Button } from '@/components/ui/button'
+import {
+  Tooltip,
+  TooltipContent,
+  TooltipProvider,
+  TooltipTrigger,
+} from '@/components/ui/tooltip'
+
+const props = withDefaults(defineProps<{
+  value?: string
+  class?: HTMLAttributes['class']
+  variant?: ButtonVariants['variant']
+  tooltip?: string
+}>(), {
+  value: '',
+  variant: 'ghost',
+  tooltip: 'Copy to Clipboard',
+})
+const { value } = toRefs(props)
+
+const { copy, copied } = useClipboard({ source: value })
+</script>
+
+<template>
+  <TooltipProvider>
+    <Tooltip>
+      <TooltipTrigger as-child>
+        <Button
+          data-slot="copy-button"
+          size="icon"
+          :variant="variant"
+          :class="cn(
+            'bg-code absolute top-3 right-2 z-10 size-7 hover:opacity-100 focus-visible:opacity-100',
+            props.class,
+          )"
+          v-bind="$attrs"
+          @click="copy()"
+        >
+          <span class="sr-only">Copy</span>
+          <IconCheck v-if="copied" /><IconCopy v-else />
+        </Button>
+      </TooltipTrigger>
+      <TooltipContent>
+        {{ copied ? "Copied" : tooltip }}
+      </TooltipContent>
+    </Tooltip>
+  </TooltipProvider>
+</template>
diff --git a/packages/layer/app/components/ui/tooltip/Tooltip.vue b/packages/layer/app/components/ui/tooltip/Tooltip.vue
new file mode 100644
index 00000000..2a393d6d
--- /dev/null
+++ b/packages/layer/app/components/ui/tooltip/Tooltip.vue
@@ -0,0 +1,19 @@
+<script setup lang="ts">
+import type { TooltipRootEmits, TooltipRootProps } from "reka-ui"
+import { TooltipRoot, useForwardPropsEmits } from "reka-ui"
+
+const props = defineProps<TooltipRootProps>()
+const emits = defineEmits<TooltipRootEmits>()
+
+const forwarded = useForwardPropsEmits(props, emits)
+</script>
+
+<template>
+  <TooltipRoot
+    v-slot="slotProps"
+    data-slot="tooltip"
+    v-bind="forwarded"
+  >
+    <slot v-bind="slotProps" />
+  </TooltipRoot>
+</template>
diff --git a/packages/layer/app/components/ui/tooltip/TooltipContent.vue b/packages/layer/app/components/ui/tooltip/TooltipContent.vue
new file mode 100644
index 00000000..c5d2df9c
--- /dev/null
+++ b/packages/layer/app/components/ui/tooltip/TooltipContent.vue
@@ -0,0 +1,34 @@
+<script setup lang="ts">
+import type { TooltipContentEmits, TooltipContentProps } from "reka-ui"
+import type { HTMLAttributes } from "vue"
+import { reactiveOmit } from "@vueuse/core"
+import { TooltipArrow, TooltipContent, TooltipPortal, useForwardPropsEmits } from "reka-ui"
+import { cn } from "@/lib/utils"
+
+defineOptions({
+  inheritAttrs: false,
+})
+
+const props = withDefaults(defineProps<TooltipContentProps & { class?: HTMLAttributes["class"] }>(), {
+  sideOffset: 4,
+})
+
+const emits = defineEmits<TooltipContentEmits>()
+
+const delegatedProps = reactiveOmit(props, "class")
+const forwarded = useForwardPropsEmits(delegatedProps, emits)
+</script>
+
+<template>
+  <TooltipPortal>
+    <TooltipContent
+      data-slot="tooltip-content"
+      v-bind="{ ...forwarded, ...$attrs }"
+      :class="cn('bg-foreground text-background 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 rounded-md px-3 py-1.5 text-xs text-balance', props.class)"
+    >
+      <slot />
+
+      <TooltipArrow class="bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
+    </TooltipContent>
+  </TooltipPortal>
+</template>
diff --git a/packages/layer/app/components/ui/tooltip/TooltipProvider.vue b/packages/layer/app/components/ui/tooltip/TooltipProvider.vue
new file mode 100644
index 00000000..395927d5
--- /dev/null
+++ b/packages/layer/app/components/ui/tooltip/TooltipProvider.vue
@@ -0,0 +1,14 @@
+<script setup lang="ts">
+import type { TooltipProviderProps } from "reka-ui"
+import { TooltipProvider } from "reka-ui"
+
+const props = withDefaults(defineProps<TooltipProviderProps>(), {
+  delayDuration: 0,
+})
+</script>
+
+<template>
+  <TooltipProvider v-bind="props">
+    <slot />
+  </TooltipProvider>
+</template>
diff --git a/packages/layer/app/components/ui/tooltip/TooltipTrigger.vue b/packages/layer/app/components/ui/tooltip/TooltipTrigger.vue
new file mode 100644
index 00000000..3332950e
--- /dev/null
+++ b/packages/layer/app/components/ui/tooltip/TooltipTrigger.vue
@@ -0,0 +1,15 @@
+<script setup lang="ts">
+import type { TooltipTriggerProps } from "reka-ui"
+import { TooltipTrigger } from "reka-ui"
+
+const props = defineProps<TooltipTriggerProps>()
+</script>
+
+<template>
+  <TooltipTrigger
+    data-slot="tooltip-trigger"
+    v-bind="props"
+  >
+    <slot />
+  </TooltipTrigger>
+</template>
diff --git a/packages/layer/app/components/ui/tooltip/index.ts b/packages/layer/app/components/ui/tooltip/index.ts
new file mode 100644
index 00000000..8f8d514d
--- /dev/null
+++ b/packages/layer/app/components/ui/tooltip/index.ts
@@ -0,0 +1,4 @@
+export { default as Tooltip } from "./Tooltip.vue"
+export { default as TooltipContent } from "./TooltipContent.vue"
+export { default as TooltipProvider } from "./TooltipProvider.vue"
+export { default as TooltipTrigger } from "./TooltipTrigger.vue"
diff --git a/packages/layer/app/composables/useConfig.ts b/packages/layer/app/composables/useConfig.ts
new file mode 100644
index 00000000..fa67410f
--- /dev/null
+++ b/packages/layer/app/composables/useConfig.ts
@@ -0,0 +1,23 @@
+import { createSharedComposable } from '@vueuse/core'
+
+export type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun'
+
+const COOKIE_NAME = 'docs_config'
+
+export const useConfig = createSharedComposable(() => {
+  const config = useCookie<{
+    packageManager: PackageManager
+  }>(
+    COOKIE_NAME,
+    {
+      default: () => ({ packageManager: 'pnpm' }),
+      path: '/',
+      maxAge: 31536000,
+      sameSite: 'lax',
+    },
+  )
+
+  return {
+    config,
+  }
+})
diff --git a/packages/layer/content.config.ts b/packages/layer/content.config.ts
index 456be9d3..19873b99 100644
--- a/packages/layer/content.config.ts
+++ b/packages/layer/content.config.ts
@@ -1,4 +1,9 @@
 import { defineCollection, defineContentConfig, z } from '@nuxt/content'
+import { useNuxt } from '@nuxt/kit'
+import { joinURL } from 'ufo'
+
+const { options } = useNuxt()
+const cwd = joinURL(options.rootDir, 'content')
 
 const docsSchema = z.object({
   links: z.array(z.object({
@@ -14,12 +19,14 @@ export default defineContentConfig({
     landing: defineCollection({
       type: 'page',
       source: {
+        cwd,
         include: 'index.md',
       },
     }),
     docs: defineCollection({
       type: 'page',
       source: {
+        cwd,
         include: '**',
         exclude: ['index.md'],
       },
diff --git a/packages/layer/nuxt.config.ts b/packages/layer/nuxt.config.ts
index 0a6d2e4b..7a92c21b 100644
--- a/packages/layer/nuxt.config.ts
+++ b/packages/layer/nuxt.config.ts
@@ -1,9 +1,19 @@
-import { createResolver } from '@nuxt/kit'
+import { addComponentsDir, createResolver } from '@nuxt/kit'
 import tailwindcss from '@tailwindcss/vite'
 
 const { resolve } = createResolver(import.meta.url)
 
 export default defineNuxtConfig({
+  hooks: {
+    'components:dirs': (dirs) => {
+      // Register content components from the layer directory
+      dirs.push({
+        path: resolve('./app/components/content'),
+        pathPrefix: false,
+        global: true,
+      })
+    },
+  },
   modules: [
     resolve('./modules/config'),
     resolve('./modules/css'),
diff --git a/packages/layer/package.json b/packages/layer/package.json
index cc3b87b2..bb404105 100644
--- a/packages/layer/package.json
+++ b/packages/layer/package.json
@@ -41,6 +41,7 @@
     "@nuxt/kit": "^4.2.1",
     "@nuxtjs/color-mode": "^4.0.0",
     "@nuxtjs/mdc": "^0.18.4",
+    "@tabler/icons-vue": "^3.35.0",
     "@vueuse/core": "^14.1.0",
     "class-variance-authority": "^0.7.1",
     "clsx": "^2.1.1",
@@ -53,7 +54,7 @@
     "oxc-parser": "^0.99.0",
     "parse5": "^7.3.0",
     "rehype-raw": "^7.0.0",
-    "reka-ui": "^2.6.0",
+    "reka-ui": "^2.6.1",
     "remark-emoji": "^5.0.1",
     "remark-gfm": "^4.0.1",
     "remark-mdc": "^3.5.1",

From 71f95ddedb1eb511751aa6f06a51732561742af2 Mon Sep 17 00:00:00 2001
From: Minsu Lee <amond@amond.net>
Date: Mon, 1 Dec 2025 16:13:29 +0900
Subject: [PATCH 3/5] fix(layer): resolve Tailwind CSS and component
 registration in multi-layer setup

- Register app/components/app and app/components/docs directories explicitly
- Fix CSS module to import main.css after @source directives
- Remove duplicate tailwindcss import from main.css
- Use @utility directive for container class (Tailwind v4 syntax)
- Add exsolve dependency for module path resolution
---
 .claude/settings.local.json            | 21 ++++++++++++++++
 apps/docs/content/index.md             |  8 +++---
 bun.lock                               |  1 +
 packages/layer/app/assets/css/main.css | 35 ++++++--------------------
 packages/layer/modules/css.ts          | 17 ++++++++++---
 packages/layer/nuxt.config.ts          | 21 +++++++++-------
 packages/layer/package.json            |  1 +
 7 files changed, 59 insertions(+), 45 deletions(-)
 create mode 100644 .claude/settings.local.json

diff --git a/.claude/settings.local.json b/.claude/settings.local.json
new file mode 100644
index 00000000..c2e21fba
--- /dev/null
+++ b/.claude/settings.local.json
@@ -0,0 +1,21 @@
+{
+  "permissions": {
+    "allow": [
+      "mcp__plugin_chrome-devtools-mcp_chrome-devtools__new_page",
+      "mcp__plugin_chrome-devtools-mcp_chrome-devtools__take_snapshot",
+      "mcp__plugin_chrome-devtools-mcp_chrome-devtools__list_console_messages",
+      "mcp__plugin_chrome-devtools-mcp_chrome-devtools__take_screenshot",
+      "mcp__plugin_chrome-devtools-mcp_chrome-devtools__list_network_requests",
+      "mcp__plugin_chrome-devtools-mcp_chrome-devtools__evaluate_script",
+      "mcp__plugin_chrome-devtools-mcp_chrome-devtools__get_network_request",
+      "mcp__plugin_chrome-devtools-mcp_chrome-devtools__navigate_page",
+      "Bash(bun run dev)",
+      "WebFetch(domain:www.shadcn-vue.com)",
+      "WebFetch(domain:shadcn-vue.com)",
+      "Bash(gh label list:*)",
+      "Bash(gh repo view:*)"
+    ],
+    "deny": [],
+    "ask": []
+  }
+}
diff --git a/apps/docs/content/index.md b/apps/docs/content/index.md
index ce3ff5bb..0008f594 100644
--- a/apps/docs/content/index.md
+++ b/apps/docs/content/index.md
@@ -1,9 +1,9 @@
 ---
-title: Welcome to PleaseAI Docs
+title: Welcome to Docs Please
 description: A documentation layer using shadcn-vue and Nuxt Content
 ---
 
-# PleaseAI Docs
+# Docs Please
 
 A modern documentation system built with **shadcn-vue** and **Nuxt Content**.
 
@@ -19,11 +19,11 @@ A modern documentation system built with **shadcn-vue** and **Nuxt Content**.
 
 ```bash
 # Install the layer
-pnpm add @pleaseai/docs-layer
+pnpm add @pleaseai/docs
 
 # Extend in nuxt.config.ts
 export default defineNuxtConfig({
-  extends: ['@pleaseai/docs-layer']
+  extends: ['@pleaseai/docs']
 })
 ```
 
diff --git a/bun.lock b/bun.lock
index ae92a883..440a6bf9 100644
--- a/bun.lock
+++ b/bun.lock
@@ -42,6 +42,7 @@
         "debug": "^4.4.1",
         "defu": "^6.1.4",
         "eslint": "^9.39.1",
+        "exsolve": "^1.0.8",
         "lucide-vue-next": "^0.555.0",
         "nuxt-og-image": "^5.1.12",
         "nuxt-shiki": "^0.3.1",
diff --git a/packages/layer/app/assets/css/main.css b/packages/layer/app/assets/css/main.css
index dcf980b7..712172cd 100644
--- a/packages/layer/app/assets/css/main.css
+++ b/packages/layer/app/assets/css/main.css
@@ -1,4 +1,3 @@
-@import 'tailwindcss';
 @import 'tw-animate-css';
 
 @custom-variant dark (&:is(.dark *));
@@ -136,35 +135,15 @@
 }
 
 /* Utility classes */
-@layer utilities {
-  .container {
-    margin-left: auto;
-    margin-right: auto;
-    max-width: 80rem;
-    padding-left: 1rem;
-    padding-right: 1rem;
-  }
-
-  @media (min-width: 640px) {
-    .container {
-      padding-left: 1.5rem;
-      padding-right: 1.5rem;
-    }
-  }
-
-  @media (min-width: 1024px) {
-    .container {
-      padding-left: 2rem;
-      padding-right: 2rem;
-    }
-  }
+@utility container {
+  @apply mx-auto w-full max-w-[1400px] px-4 lg:px-8;
+}
 
-  .no-scrollbar {
-    -ms-overflow-style: none;
-    scrollbar-width: none;
-  }
+@utility no-scrollbar {
+  -ms-overflow-style: none;
+  scrollbar-width: none;
 
-  .no-scrollbar::-webkit-scrollbar {
+  &::-webkit-scrollbar {
     display: none;
   }
 }
diff --git a/packages/layer/modules/css.ts b/packages/layer/modules/css.ts
index 21fa2b4b..cc82840b 100644
--- a/packages/layer/modules/css.ts
+++ b/packages/layer/modules/css.ts
@@ -1,5 +1,6 @@
 import { addTemplate, createResolver, defineNuxtModule } from '@nuxt/kit'
 import { joinURL } from 'ufo'
+import { resolveModulePath } from 'exsolve'
 
 export default defineNuxtModule({
   meta: {
@@ -11,19 +12,27 @@ export default defineNuxtModule({
 
     const contentDir = joinURL(dir, 'content')
     const layerDir = resolver.resolve('../app')
+    const mainCssPath = resolver.resolve('../app/assets/css/main.css')
+    const tailwindPath = resolveModulePath('tailwindcss', { from: import.meta.url, conditions: ['style'] })
 
     // Create a CSS template that includes source directives for Tailwind
     const cssTemplate = addTemplate({
       filename: 'docs-layer.css',
       getContents: () => {
-        return `/* Auto-generated Tailwind source directives */
+        return `@import ${JSON.stringify(tailwindPath)};
+
 @source "${contentDir.replace(/\\/g, '/')}/**/*";
 @source "${layerDir.replace(/\\/g, '/')}/**/*";
-@source "../../app.config.ts";`
+@source "../../app.config.ts";
+
+@import ${JSON.stringify(mainCssPath)};`
       },
     })
 
-    // Add the generated CSS file to Nuxt
-    nuxt.options.css.push(cssTemplate.dst)
+    // Remove main.css from nuxt.options.css if present (we import it in docs-layer.css)
+    nuxt.options.css = nuxt.options.css.filter(css => !css.includes('main.css'))
+
+    // Add the generated CSS file to Nuxt - unshift to load first
+    nuxt.options.css.unshift(cssTemplate.dst)
   },
 })
diff --git a/packages/layer/nuxt.config.ts b/packages/layer/nuxt.config.ts
index 7a92c21b..53893f2a 100644
--- a/packages/layer/nuxt.config.ts
+++ b/packages/layer/nuxt.config.ts
@@ -6,6 +6,18 @@ const { resolve } = createResolver(import.meta.url)
 export default defineNuxtConfig({
   hooks: {
     'components:dirs': (dirs) => {
+      // Register app components from the layer directory
+      dirs.push({
+        path: resolve('./app/components/app'),
+        pathPrefix: false,
+        global: true,
+      })
+      // Register docs components from the layer directory
+      dirs.push({
+        path: resolve('./app/components/docs'),
+        pathPrefix: false,
+        global: true,
+      })
       // Register content components from the layer directory
       dirs.push({
         path: resolve('./app/components/content'),
@@ -26,15 +38,6 @@ export default defineNuxtConfig({
     '@nuxt/eslint',
   ],
   devtools: { enabled: true },
-  shadcn: {
-    /**
-     * Directory that the component lives in.
-     * Will respect the Nuxt aliases.
-     * @link https://nuxt.com/docs/api/nuxt-config#alias
-     * @default "@/components/ui"
-     */
-    componentDir: '@/components/ui',
-  },
   css: [resolve('./app/assets/css/main.css')],
   content: {
     build: {
diff --git a/packages/layer/package.json b/packages/layer/package.json
index bb404105..5c6180d0 100644
--- a/packages/layer/package.json
+++ b/packages/layer/package.json
@@ -48,6 +48,7 @@
     "debug": "^4.4.1",
     "defu": "^6.1.4",
     "eslint": "^9.39.1",
+    "exsolve": "^1.0.8",
     "lucide-vue-next": "^0.555.0",
     "nuxt-og-image": "^5.1.12",
     "nuxt-shiki": "^0.3.1",

From 85c32d10e0fa64fa3de296a0005b48d0e5ee96d3 Mon Sep 17 00:00:00 2001
From: Minsu Lee <amond@amond.net>
Date: Tue, 2 Dec 2025 09:47:04 +0900
Subject: [PATCH 4/5] fix: add relative positioning to code block containers
 for CopyButton visibility

---
 packages/layer/app/components/content/CodeBlockCommand.vue | 2 +-
 packages/layer/app/components/content/ProsePre.vue         | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/packages/layer/app/components/content/CodeBlockCommand.vue b/packages/layer/app/components/content/CodeBlockCommand.vue
index 6ee64566..99304c7c 100644
--- a/packages/layer/app/components/content/CodeBlockCommand.vue
+++ b/packages/layer/app/components/content/CodeBlockCommand.vue
@@ -52,7 +52,7 @@ const { config } = useConfig()
 </script>
 
 <template>
-  <div class="overflow-x-auto">
+  <div class="relative overflow-x-auto">
     <Tabs v-model="config.packageManager" class="gap-0">
       <div class="border-border/50 flex items-center gap-2 border-b px-3 py-1">
         <div class="bg-foreground flex size-4 items-center justify-center rounded-[1px] opacity-70">
diff --git a/packages/layer/app/components/content/ProsePre.vue b/packages/layer/app/components/content/ProsePre.vue
index c40f8b09..637bed3f 100644
--- a/packages/layer/app/components/content/ProsePre.vue
+++ b/packages/layer/app/components/content/ProsePre.vue
@@ -74,9 +74,9 @@ const codeAttributes = computed(() => isShowingLineNumber.value
         <component :is="IconExtension" v-if="IconExtension" />
         {{ title }}
       </figcaption>
-      <pre :data-language="lang" :class="cn('no-scrollbar min-w-0 overflow-x-auto px-4 py-3.5 outline-none has-[[data-highlighted-line]]:px-0 has-[[data-line-numbers]]:px-0 has-[[data-slot=tabs]]:p-0', props.class)"><CopyButton :value="code" /><code v-bind="codeAttributes" v-html="highlighted" /></pre>
+      <pre :data-language="lang" :class="cn('relative no-scrollbar min-w-0 overflow-x-auto px-4 py-3.5 outline-none has-[[data-highlighted-line]]:px-0 has-[[data-line-numbers]]:px-0 has-[[data-slot=tabs]]:p-0', props.class)"><CopyButton :value="code" /><code v-bind="codeAttributes" v-html="highlighted" /></pre>
     </template>
 
-    <pre v-else :data-language="lang" :class="cn('no-scrollbar min-w-0 overflow-x-auto px-4 py-3.5 outline-none has-[[data-highlighted-line]]:px-0 has-[[data-line-numbers]]:px-0 has-[[data-slot=tabs]]:p-0', props.class)"><CopyButton :value="code" /><code v-bind="codeAttributes" v-html="highlighted" /></pre>
+    <pre v-else :data-language="lang" :class="cn('relative no-scrollbar min-w-0 overflow-x-auto px-4 py-3.5 outline-none has-[[data-highlighted-line]]:px-0 has-[[data-line-numbers]]:px-0 has-[[data-slot=tabs]]:p-0', props.class)"><CopyButton :value="code" /><code v-bind="codeAttributes" v-html="highlighted" /></pre>
   </figure>
 </template>

From 7f2af98ca6c598b6d8f0149e48c141da3f600dc3 Mon Sep 17 00:00:00 2001
From: Minsu Lee <amond@amond.net>
Date: Tue, 2 Dec 2025 09:50:48 +0900
Subject: [PATCH 5/5] feat: Add Gemini settings file to specify context
 filenames for Claude and Gemini.

---
 .gemini/settings.json | 8 ++++++++
 1 file changed, 8 insertions(+)
 create mode 100644 .gemini/settings.json

diff --git a/.gemini/settings.json b/.gemini/settings.json
new file mode 100644
index 00000000..f68e111c
--- /dev/null
+++ b/.gemini/settings.json
@@ -0,0 +1,8 @@
+{
+    "context": {
+        "fileName": [
+            "CLAUDE.md",
+            "GEMINI.md"
+        ]
+    }
+}
\ No newline at end of file
