mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-15 20:48:12 +01:00
Compare commits
3 Commits
fix/form-o
...
pr/3001
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
723065afa7 | ||
|
|
e67305e412 | ||
|
|
33ed3935a3 |
4
.github/ISSUE_TEMPLATE/bug-report-v3.yml
vendored
4
.github/ISSUE_TEMPLATE/bug-report-v3.yml
vendored
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before reporting a bug, please make sure that you have read through our [v3 documentation](https://ui.nuxt.com/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
Before reporting a bug, please make sure that you have read through our [v3 documentation](https://ui3.nuxt.dev/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
- type: textarea
|
||||
id: env
|
||||
attributes:
|
||||
@@ -37,7 +37,7 @@ body:
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
placeholder: v3.0.0
|
||||
placeholder: v3.0.0-alpha.x
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before reporting a bug, please make sure that you have read through our [documentation](https://ui2.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||
Before reporting a bug, please make sure that you have read through our [documentation](https://ui.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||
- type: textarea
|
||||
id: env
|
||||
attributes:
|
||||
|
||||
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before requesting a feature, please make sure that you have read through our [v3 documentation](https://ui.nuxt.com/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
Before requesting a feature, please make sure that you have read through our [v3 documentation](https://ui3.nuxt.dev/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
2
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before requesting a feature, please make sure that you have read through our [documentation](https://ui2.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||
Before requesting a feature, please make sure that you have read through our [documentation](https://ui.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/question-v3.yml
vendored
2
.github/ISSUE_TEMPLATE/question-v3.yml
vendored
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before asking a question, please make sure that you have read through our [v3 documentation](https://ui.nuxt.com/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
Before asking a question, please make sure that you have read through our [v3 documentation](https://ui3.nuxt.dev/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/question.yml
vendored
2
.github/ISSUE_TEMPLATE/question.yml
vendored
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before asking a question, please make sure that you have read through our [documentation](https://ui2.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||
Before asking a question, please make sure that you have read through our [documentation](https://ui.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
2
.github/workflows/docs.yml
vendored
2
.github/workflows/docs.yml
vendored
@@ -42,8 +42,6 @@ jobs:
|
||||
|
||||
- name: Build application
|
||||
run: pnpm run docs:build
|
||||
env:
|
||||
NODE_OPTIONS: '--max-old-space-size=8192'
|
||||
|
||||
- name: Deploy to NuxtHub
|
||||
uses: nuxt-hub/action@v1
|
||||
|
||||
159
.github/workflows/module.yml
vendored
159
.github/workflows/module.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest] # macos-latest
|
||||
os: [ubuntu-latest] # macos-latest, windows-latest
|
||||
node: [22]
|
||||
|
||||
env:
|
||||
@@ -50,165 +50,16 @@ jobs:
|
||||
run: pnpm run typecheck
|
||||
|
||||
- name: Test
|
||||
run: pnpm run test run
|
||||
run: pnpm run test
|
||||
|
||||
- name: Test (vue)
|
||||
run: pnpm run test:vue run
|
||||
run: pnpm run test:vue
|
||||
|
||||
- name: Build
|
||||
run: pnpm run build
|
||||
|
||||
- name: Build playground
|
||||
run: pnpm run dev:build
|
||||
|
||||
- name: Build playground (vue)
|
||||
run: pnpm run dev:vue:build
|
||||
- name: Build vue fixture
|
||||
run: pnpm run test:vue:build
|
||||
|
||||
- name: Publish
|
||||
if: matrix.os != 'windows-latest'
|
||||
run: pnpx pkg-pr-new publish --compact --no-template --pnpm
|
||||
|
||||
starter-nuxt:
|
||||
needs: build
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest] # macos-latest, windows-latest
|
||||
node: [22]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: nuxtlabs/nuxt-ui-starter
|
||||
|
||||
- name: Store commit SHA
|
||||
run: |
|
||||
echo "COMMIT_SHA=$(echo ${{ github.workflow_sha }} | cut -c1-7)" >> $GITHUB_ENV
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
|
||||
- name: Install latest nuxt/ui
|
||||
run: pnpm install https://pkg.pr.new/@nuxt/ui@${{ env.COMMIT_SHA }} --lockfile-only
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Typecheck
|
||||
run: pnpm run typecheck
|
||||
|
||||
- name: Build
|
||||
run: pnpm run build
|
||||
|
||||
starter-vue:
|
||||
needs: build
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest] # macos-latest, windows-latest
|
||||
node: [22]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: nuxtlabs/nuxt-ui-vue-starter
|
||||
|
||||
- name: Store commit SHA
|
||||
run: |
|
||||
echo "COMMIT_SHA=$(echo ${{ github.workflow_sha }} | cut -c1-7)" >> $GITHUB_ENV
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
|
||||
- name: Install latest nuxt/ui
|
||||
run: pnpm install https://pkg.pr.new/@nuxt/ui@${{ env.COMMIT_SHA }} --lockfile-only
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Typecheck
|
||||
run: pnpm run typecheck
|
||||
|
||||
- name: Build
|
||||
run: pnpm run build
|
||||
|
||||
nuxt-ui-pro:
|
||||
needs: build
|
||||
|
||||
# Only run this job if not a fork PR (when push event or PR from same repo)
|
||||
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest] # macos-latest, windows-latest
|
||||
node: [22]
|
||||
|
||||
env:
|
||||
NUXT_UI_PRO_LICENSE: ${{ secrets.NUXT_UI_PRO_LICENSE }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: nuxt/ui-pro
|
||||
token: ${{ secrets.NUXT_GITHUB_TOKEN }}
|
||||
|
||||
- name: Store commit SHA
|
||||
run: |
|
||||
echo "COMMIT_SHA=$(echo ${{ github.workflow_sha }} | cut -c1-7)" >> $GITHUB_ENV
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
|
||||
- name: Install latest nuxt/ui
|
||||
run: pnpm install https://pkg.pr.new/@nuxt/ui@${{ env.COMMIT_SHA }} --lockfile-only
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Prepare
|
||||
run: pnpm run dev:prepare
|
||||
|
||||
- name: Typecheck
|
||||
run: pnpm run typecheck
|
||||
|
||||
- name: Build
|
||||
run: pnpm run build
|
||||
|
||||
16
.github/workflows/stale.yml
vendored
16
.github/workflows/stale.yml
vendored
@@ -10,16 +10,14 @@ jobs:
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
days-before-stale: -1 # Issues and PR will never be flagged stale automatically.
|
||||
stale-issue-label: 'needs reproduction' # Label that flags an issue as stale.
|
||||
only-labels: 'needs reproduction' # Only process these issues
|
||||
days-before-issue-close: 7
|
||||
ignore-updates: true
|
||||
remove-stale-when-updated: false
|
||||
close-issue-message: This issue was closed because it was open for 7 days without a reproduction.
|
||||
close-issue-label: closed-by-bot
|
||||
operations-per-run: 300 #default 30
|
||||
exempt-issue-labels: triage,v3
|
||||
stale-issue-message: 'This issue is stale because it has been open for 30 days with no activity.'
|
||||
stale-issue-label: stale
|
||||
stale-pr-label: stale
|
||||
days-before-stale: 30
|
||||
days-before-close: -1
|
||||
|
||||
1
.npmrc
1
.npmrc
@@ -1,3 +1,4 @@
|
||||
shamefully-hoist=true
|
||||
auto-install-peers=true
|
||||
ignore-workspace-root-check=true
|
||||
shell-emulator=true
|
||||
|
||||
97
CHANGELOG.md
97
CHANGELOG.md
@@ -1,102 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## [3.0.2](https://github.com/nuxt/ui/compare/v3.0.1...v3.0.2) (2025-03-28)
|
||||
|
||||
### Features
|
||||
|
||||
* **Calendar:** allow year and month buttons styling ([#3672](https://github.com/nuxt/ui/issues/3672)) ([4a2b77d](https://github.com/nuxt/ui/commit/4a2b77d86c28806234002340eda39de4dc78cce0))
|
||||
* **locale:** add Armenian language ([#3664](https://github.com/nuxt/ui/issues/3664)) ([c76f590](https://github.com/nuxt/ui/commit/c76f5900970e3f5c451192b1207ccea04771e8b3))
|
||||
* **Table:** add `empty` prop ([afff54f](https://github.com/nuxt/ui/commit/afff54fecd31497238461e0a44abd8668ed734c3))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Avatar:** proxy `$attrs` to default slot ([#3712](https://github.com/nuxt/ui/issues/3712)) ([88f349d](https://github.com/nuxt/ui/commit/88f349d0d74eb1c2ce5066818731759c25a9e83e))
|
||||
* **Button:** use `focus:outline-none` instead of `focus:outline-hidden` ([c231fe5](https://github.com/nuxt/ui/commit/c231fe5f26ca7614df46a7ec8a5ce7f4ec8884e7)), closes [#3658](https://github.com/nuxt/ui/issues/3658)
|
||||
* **CommandPalette:** use `group.id` as key ([bc61d29](https://github.com/nuxt/ui/commit/bc61d29cce531715a6279444845f02a002a22af7))
|
||||
* **components:** improve generic types ([#3331](https://github.com/nuxt/ui/issues/3331)) ([b998354](https://github.com/nuxt/ui/commit/b9983549a4b743724ea3ef99cc4a243f5ca41e53))
|
||||
* **Container:** add `w-full` class ([df00149](https://github.com/nuxt/ui/commit/df001495980647cab1e67fd16154f1bc778de5e2))
|
||||
* **defineLocale/defineShortcuts:** remove `@__NO_SIDE_EFFECTS__` ([82e2665](https://github.com/nuxt/ui/commit/82e26655a40782555299516f32a76046fa0dbd3a))
|
||||
* **Drawer:** remove `fadeFromIndex` prop proxy ([f7604e5](https://github.com/nuxt/ui/commit/f7604e565f717001a4d4c2974cf23559a3f01c21))
|
||||
* **Form:** clear dirty state after submit ([#3692](https://github.com/nuxt/ui/issues/3692)) ([3dd88ba](https://github.com/nuxt/ui/commit/3dd88bacecb2945efba8cc3cb4fe59fcbc056e9a))
|
||||
* **FormField:** add `help` to `aria-describedby` attribute ([#3691](https://github.com/nuxt/ui/issues/3691)) ([20c3392](https://github.com/nuxt/ui/commit/20c33920d005332db3c83f33a8c54c7c227ce0a0))
|
||||
* **InputMenu/SelectMenu:** empty search results ([94b6e52](https://github.com/nuxt/ui/commit/94b6e520f5ccf011204e953421fcc5b44b637e51))
|
||||
* **InputMenu:** reset `searchTerm` on `update:open` ([3074632](https://github.com/nuxt/ui/commit/3074632523e67fa6a0ad3d9a71e5692c285bdc3a)), closes [#3620](https://github.com/nuxt/ui/issues/3620)
|
||||
* **Link:** handle `aria-current` like `NuxtLink` / `RouterLink` ([c531d02](https://github.com/nuxt/ui/commit/c531d0248be7863980a1f676643c2dea8301c009))
|
||||
* **Link:** prevent `active="true"` binding on html ([d73768b](https://github.com/nuxt/ui/commit/d73768b70453d60dd4186a996c1cf808b0294bf6))
|
||||
* **Link:** properly pick all `aria-*` & `data-*` attrs ([ade16b7](https://github.com/nuxt/ui/commit/ade16b76cf535924a8d0f402b4d5d65cb67a55eb))
|
||||
* **Link:** proxy `onClick` ([370054b](https://github.com/nuxt/ui/commit/370054b20c0201c9dba84ddfcd1e916594619b93)), closes [#3631](https://github.com/nuxt/ui/issues/3631)
|
||||
* **NavigationMenu:** add `z-index` on viewport ([0095d89](https://github.com/nuxt/ui/commit/0095d8916bf361c0c89972e2f86b79850510c6a9)), closes [#3654](https://github.com/nuxt/ui/issues/3654)
|
||||
* **Switch:** prevent transition on focus outline ([68787b2](https://github.com/nuxt/ui/commit/68787b26fdf2bd5f9d9e812e5bfddb19abe45d1d))
|
||||
* **Table:** wrong condition on `caption` slot ([4ebb94c](https://github.com/nuxt/ui/commit/4ebb94cd7ef909b3547bce0922f75fe3ff74de4c))
|
||||
* **Tabs:** remove `focus:outline-hidden` class ([1769d5e](https://github.com/nuxt/ui/commit/1769d5ed6ea46b1f7eafdc48cb6456512229f98b))
|
||||
* **types:** add missing export for ButtonGroup ([#3709](https://github.com/nuxt/ui/issues/3709)) ([e7e6745](https://github.com/nuxt/ui/commit/e7e674559981177ad08be42418746060d7737df9))
|
||||
* **useOverlay:** refine `open` method type to infer close emit return type ([#3716](https://github.com/nuxt/ui/issues/3716)) ([bd99c2d](https://github.com/nuxt/ui/commit/bd99c2d850d57baccc51e049c0b578a6fc6ab431))
|
||||
* **vue:** mock `nuxtApp.hooks` & `useRuntimeHook` ([23bfeb9](https://github.com/nuxt/ui/commit/23bfeb937004d619187a67fb43e4c76b13d00069))
|
||||
|
||||
## [3.0.1](https://github.com/nuxt/ui/compare/v3.0.0...v3.0.1) (2025-03-21)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **Form:** drop explicit support for `zod` and `valibot` (#3617)
|
||||
|
||||
### Features
|
||||
|
||||
* **components:** handle events in `content` prop ([5dec0e1](https://github.com/nuxt/ui/commit/5dec0e16e28549b8833aaab17a87fada63d6598c))
|
||||
* **locale:** add Catalan language ([#3550](https://github.com/nuxt/ui/issues/3550)) ([53cf1b4](https://github.com/nuxt/ui/commit/53cf1b4c14a2a0e076e1e77688852e6bd0a28a74))
|
||||
* **locale:** add Central Kurdish language ([#3566](https://github.com/nuxt/ui/issues/3566)) ([b2034cc](https://github.com/nuxt/ui/commit/b2034ccc91eec6a2842c6f83d159e5aa6fd5f2fd))
|
||||
* **locale:** add Romanian language ([#3587](https://github.com/nuxt/ui/issues/3587)) ([0229b0f](https://github.com/nuxt/ui/commit/0229b0fd4644a97db7eb3154c3c87a26634dcfbb))
|
||||
* **locale:** add Urdu language ([#3611](https://github.com/nuxt/ui/issues/3611)) ([126ba23](https://github.com/nuxt/ui/commit/126ba2326f8153e155e1013db92c6ee417117610))
|
||||
* **locale:** add Uzbek language ([#3548](https://github.com/nuxt/ui/issues/3548)) ([302e04b](https://github.com/nuxt/ui/commit/302e04bd77ae8b165046b264c8d23626e92f8fb5))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Calendar:** grey out days outside of displayed month ([#3639](https://github.com/nuxt/ui/issues/3639)) ([a516866](https://github.com/nuxt/ui/commit/a5168666b7dff08e714d57f497737e7a670f457c))
|
||||
* **ContextMenu/DropdownMenu:** remove `any` from `proxySlots` ([#3623](https://github.com/nuxt/ui/issues/3623)) ([764c41a](https://github.com/nuxt/ui/commit/764c41a0c60dd1c12d39a86af9f5f11b9e6cdc8c))
|
||||
* **Modal/Slideover/Toast:** prevent unnecessary close instantiation ([f4c417d](https://github.com/nuxt/ui/commit/f4c417d9ef5409b52084bdf9d8cbccee3139709f))
|
||||
* **module:** handle tailwindcss import without `theme(static)` ([#3630](https://github.com/nuxt/ui/issues/3630)) ([ecff9ab](https://github.com/nuxt/ui/commit/ecff9abc720bdda3a279d5bcfb7b477ff885f2e4))
|
||||
* **module:** mark functions used in exports as pure ([#3604](https://github.com/nuxt/ui/issues/3604)) ([57efc78](https://github.com/nuxt/ui/commit/57efc78a3b3fa4a54bcd13df47d570a18fba2bc4))
|
||||
* **RadioGroup:** handle `disabled` on items ([fe0bd83](https://github.com/nuxt/ui/commit/fe0bd83d11b0dfa53b58d423bc917f8e21d73444)), closes [nuxt/ui-pro#911](https://github.com/nuxt/ui-pro/issues/911)
|
||||
* **Table:** allow links to be opened when [@select](https://github.com/select) is used ([#3580](https://github.com/nuxt/ui/issues/3580)) ([e80cc15](https://github.com/nuxt/ui/commit/e80cc1592fb244dd7692486a4c1ca5b1c2008112))
|
||||
* **types:** add missing export for Icon ([#3568](https://github.com/nuxt/ui/issues/3568)) ([5e62493](https://github.com/nuxt/ui/commit/5e624933216db95cbfd1b8034b2eb0f13846ae55))
|
||||
* **unplugin:** include `@compodium/examples` in auto-imports paths ([#3585](https://github.com/nuxt/ui/issues/3585)) ([cc504b8](https://github.com/nuxt/ui/commit/cc504b8a4b69dd76b49659d5c206ef23dcb9e475))
|
||||
* **useLocale:** unique symbol to use in `@nuxt/ui-pro` ([#3603](https://github.com/nuxt/ui/issues/3603)) ([dec2730](https://github.com/nuxt/ui/commit/dec2730aaea1327434837cfa022ea04056757cbf))
|
||||
* **vue:** missing unhead context ([#3589](https://github.com/nuxt/ui/issues/3589)) ([0897e9e](https://github.com/nuxt/ui/commit/0897e9ef05fbee4f021f317bb7c2d0b7007f1b75))
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* **Form:** drop explicit support for `zod` and `valibot` ([#3617](https://github.com/nuxt/ui/issues/3617)) ([9a4bb34](https://github.com/nuxt/ui/commit/9a4bb34d7d14add0a3199103f4b583e8307d1d6d))
|
||||
|
||||
## [3.0.0](https://github.com/nuxt/ui/compare/v3.0.0-beta.4...v3.0.0) (2025-03-12)
|
||||
|
||||
## [3.0.0-beta.4](https://github.com/nuxt/ui/compare/v3.0.0-beta.3...v3.0.0-beta.4) (2025-03-12)
|
||||
|
||||
### Features
|
||||
|
||||
* **Form:** global errors ([#3482](https://github.com/nuxt/ui/issues/3482)) ([6e03d9c](https://github.com/nuxt/ui/commit/6e03d9c6efc8f4cfc306813e733d7d3e03706323))
|
||||
* **Input/Textarea:** allow `null` value in model ([#3415](https://github.com/nuxt/ui/issues/3415)) ([cfe9b2e](https://github.com/nuxt/ui/commit/cfe9b2ecf34827bc11a5281a069988ab96030047))
|
||||
* **useLocale:** handle generic messages ([#3100](https://github.com/nuxt/ui/issues/3100)) ([a9c8eb3](https://github.com/nuxt/ui/commit/a9c8eb3f60a10d1a71632991c9db594716b0fba1))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Button:** missing import ([21dbf01](https://github.com/nuxt/ui/commit/21dbf01888a161a9d8ac6eb0d957c1342f6cc30d)), closes [nuxt/ui#3417](https://github.com/nuxt/ui/issues/3417)
|
||||
* **Form:** input blur validation on submit ([#3504](https://github.com/nuxt/ui/issues/3504)) ([97c8098](https://github.com/nuxt/ui/commit/97c8098d4a35c392719ae179d36aa008d6f8f78a))
|
||||
* **vue:** prevent calling `useHead` in colors ([5ecd227](https://github.com/nuxt/ui/commit/5ecd2271ca86087cb805548397d75c38763ad412))
|
||||
|
||||
## [3.0.0-beta.3](https://github.com/nuxt/ui/compare/v3.0.0-beta.2...v3.0.0-beta.3) (2025-03-07)
|
||||
|
||||
### Features
|
||||
|
||||
* **Button:** handle `active` state ([bd2d484](https://github.com/nuxt/ui/commit/bd2d4848d246a3d5930f8059913f5a1a0abe29fd)), closes [#3417](https://github.com/nuxt/ui/issues/3417)
|
||||
* **Table:** add `loading` slot ([99e531d](https://github.com/nuxt/ui/commit/99e531d8dfb7954322b7ab7feda3d8814c6d8d02)), closes [#3444](https://github.com/nuxt/ui/issues/3444)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **InputMenu/SelectMenu:** proxy `required` in root props ([60b7e2d](https://github.com/nuxt/ui/commit/60b7e2d69e80afa7e221855dcec46479d0ca5c6c))
|
||||
* **InputMenu:** wrong `required` in multiple mode ([01fa230](https://github.com/nuxt/ui/commit/01fa230eae4b6623c5fd71cc218d114d9f6f0f25)), closes [#2741](https://github.com/nuxt/ui/issues/2741)
|
||||
* **Pagination:** add missing slots ([a47c5ff](https://github.com/nuxt/ui/commit/a47c5ff46616eafee3158cb9801183965f5f9874)), closes [#3441](https://github.com/nuxt/ui/issues/3441)
|
||||
* **Pagination:** wrong next link ([e823022](https://github.com/nuxt/ui/commit/e823022b19bb172d2e5fabb9144b4a4286a25a5f)), closes [#3008](https://github.com/nuxt/ui/issues/3008)
|
||||
* **templates:** prevent overriding existing colors ([ccbd89c](https://github.com/nuxt/ui/commit/ccbd89c908fe8af54c7d723dd12da5b7f3906c8f)), closes [#3426](https://github.com/nuxt/ui/issues/3426)
|
||||
|
||||
## [3.0.0-beta.2](https://github.com/nuxt/ui/compare/v3.0.0-beta.1...v3.0.0-beta.2) (2025-02-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
35
README.md
35
README.md
@@ -11,31 +11,31 @@
|
||||
[![License][license-src]][license-href]
|
||||
[![Nuxt][nuxt-src]][nuxt-href]
|
||||
|
||||
Nuxt UI harnesses the combined strengths of [Reka UI](https://reka-ui.com/), [Tailwind CSS](https://tailwindcss.com/), and [Tailwind Variants](https://www.tailwind-variants.org/) to offer developers an unparalleled set of tools for creating sophisticated, accessible, and highly performant user interfaces.
|
||||
We're thrilled to introduce Nuxt UI v3, a significant upgrade to our UI library that delivers extensive improvements and robust new capabilities. This major update harnesses the combined strengths of [Reka UI](https://reka-ui.com/), [Tailwind CSS v4](https://tailwindcss.com/), and [Tailwind Variants](https://www.tailwind-variants.org/) to offer developers an unparalleled set of tools for creating sophisticated, accessible, and highly performant user interfaces.
|
||||
|
||||
> [!NOTE]
|
||||
> You are on the `v3` development branch, check out the [v2 branch](https://github.com/nuxt/ui/tree/v2) for Nuxt UI v2.
|
||||
> You are on the `v3` development branch, check out the [dev branch](https://github.com/nuxt/ui/tree/dev) for Nuxt UI v2.
|
||||
|
||||
## Documentation
|
||||
|
||||
Visit https://ui.nuxt.com to explore the documentation.
|
||||
Visit https://ui3.nuxt.dev to explore the documentation.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm add @nuxt/ui
|
||||
pnpm add @nuxt/ui@next
|
||||
```
|
||||
|
||||
```bash [yarn]
|
||||
yarn add @nuxt/ui
|
||||
yarn add @nuxt/ui@next
|
||||
```
|
||||
|
||||
```bash [npm]
|
||||
npm install @nuxt/ui
|
||||
npm install @nuxt/ui@next
|
||||
```
|
||||
|
||||
```bash [bun]
|
||||
bun add @nuxt/ui
|
||||
bun add @nuxt/ui@next
|
||||
```
|
||||
|
||||
### Nuxt
|
||||
@@ -51,11 +51,11 @@ export default defineNuxtConfig({
|
||||
2. Import Tailwind CSS and Nuxt UI in your CSS:
|
||||
|
||||
```css [assets/css/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "tailwindcss" theme(static);
|
||||
@import "@nuxt/ui";
|
||||
```
|
||||
|
||||
Learn more in the [installation guide](https://ui.nuxt.com/getting-started/installation/nuxt).
|
||||
Learn more in the [installation guide](https://ui3.nuxt.dev/getting-started/installation/nuxt).
|
||||
|
||||
### Vue
|
||||
|
||||
@@ -98,22 +98,11 @@ app.mount('#app')
|
||||
3. Import Tailwind CSS and Nuxt UI in your CSS:
|
||||
|
||||
```css [assets/main.css]
|
||||
@import "tailwindcss";
|
||||
@import "tailwindcss" theme(static);
|
||||
@import "@nuxt/ui";
|
||||
```
|
||||
|
||||
Learn more in the [installation guide](https://ui.nuxt.com/getting-started/installation/vue).
|
||||
|
||||
## Contribution
|
||||
|
||||
Thank you for considering contributing to Nuxt UI. Here are a few ways you can get involved:
|
||||
|
||||
- Reporting Bugs: If you come across any bugs or issues, please check out the reporting bugs guide to learn how to submit a bug report.
|
||||
- Suggestions: Have any thoughts to enhance Nuxt UI? We'd love to hear them! Check out the [contribution guide](https://ui.nuxt.com/getting-started/contribution) to share your suggestions.
|
||||
|
||||
## Local Development
|
||||
|
||||
Follow the docs to [set up your local development environment](https://ui.nuxt.com/getting-started/contribution#local-development) and contribute.
|
||||
Learn more in the [installation guide](https://ui3.nuxt.dev/getting-started/installation/vue).
|
||||
|
||||
## Credits
|
||||
|
||||
@@ -130,7 +119,7 @@ Follow the docs to [set up your local development environment](https://ui.nuxt.c
|
||||
Licensed under the [MIT license](https://github.com/nuxt/ui/blob/v3/LICENSE.md).
|
||||
|
||||
<!-- Badges -->
|
||||
[npm-version-src]: https://img.shields.io/npm/v/@nuxt/ui/latest.svg?style=flat&colorA=18181B&colorB=28CF8D
|
||||
[npm-version-src]: https://img.shields.io/npm/v/@nuxt/ui/next.svg?style=flat&colorA=18181B&colorB=28CF8D
|
||||
[npm-version-href]: https://npmjs.com/package/@nuxt/ui
|
||||
|
||||
[npm-downloads-src]: https://img.shields.io/npm/dm/@nuxt/ui.svg?style=flat&colorA=18181B&colorB=28CF8D
|
||||
|
||||
@@ -7,13 +7,10 @@ export default defineBuildConfig({
|
||||
'./src/vite'
|
||||
],
|
||||
rollup: {
|
||||
replace: {
|
||||
delimiters: ['', ''],
|
||||
values: {
|
||||
// Used in development to import directly from theme
|
||||
'const isUiDev = true': 'const isUiDev = false'
|
||||
}
|
||||
}
|
||||
emitCJS: true
|
||||
},
|
||||
replace: {
|
||||
'process.env.DEV': 'false'
|
||||
},
|
||||
hooks: {
|
||||
'mkdist:entry:options'(ctx, entry, options) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"citty": "^0.1.6",
|
||||
"consola": "^3.4.2",
|
||||
"consola": "^3.4.0",
|
||||
"pathe": "^2.0.3",
|
||||
"scule": "^1.3.0"
|
||||
}
|
||||
|
||||
@@ -31,10 +31,13 @@ const component = ({ name, primitive, pro, prose, content }) => {
|
||||
? `
|
||||
<script lang="ts">
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/${path}/${prose ? 'prose/' : ''}${content ? 'content/' : ''}${kebabName}'
|
||||
import type { ComponentConfig } from '../types/utils'
|
||||
import { tv } from '${pro ? '#ui/utils/tv' : '../utils/tv'}'
|
||||
|
||||
type ${upperName} = ComponentConfig<typeof theme, AppConfig, ${upperName}${pro ? `, '${key}'` : ''}>
|
||||
const appConfig${camelName} = _appConfig as AppConfig & { ${key}: { ${prose ? 'prose: { ' : ''}${camelName}: Partial<typeof theme> } }${prose ? ' }' : ''}
|
||||
|
||||
const ${camelName} = tv({ extend: tv(theme), ...(appConfig${camelName}.${key}?.${prose ? 'prose?.' : ''}${camelName} || {}) })
|
||||
|
||||
export interface ${upperName}Props {
|
||||
/**
|
||||
@@ -43,7 +46,7 @@ export interface ${upperName}Props {
|
||||
*/
|
||||
as?: any
|
||||
class?: any
|
||||
ui?: ${upperName}['slots']
|
||||
ui?: Partial<typeof ${camelName}.slots>
|
||||
}
|
||||
|
||||
export interface ${upperName}Slots {
|
||||
@@ -52,17 +55,12 @@ export interface ${upperName}Slots {
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { Primitive } from 'reka-ui'
|
||||
import { useAppConfig } from '#imports'
|
||||
import { tv } from '../utils/tv'
|
||||
|
||||
const props = defineProps<${upperName}Props>()
|
||||
defineSlots<${upperName}Slots>()
|
||||
|
||||
const appConfig = useAppConfig() as ${upperName}['AppConfig']
|
||||
|
||||
const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.${camelName} || {}) })())
|
||||
const ui = ${camelName}()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -73,16 +71,22 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.${camelName}
|
||||
`
|
||||
: `
|
||||
<script lang="ts">
|
||||
import type { VariantProps } from 'tailwind-variants'
|
||||
import type { ${upperName}RootProps, ${upperName}RootEmits } from 'reka-ui'
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/${path}/${prose ? 'prose/' : ''}${content ? 'content/' : ''}${kebabName}'
|
||||
import type { ComponentConfig } from '../types/utils'
|
||||
import { tv } from '${pro ? '#ui/utils/tv' : '../utils/tv'}'
|
||||
|
||||
type ${upperName} = ComponentConfig<typeof theme, AppConfig, ${upperName}${pro ? `, '${key}'` : ''}>
|
||||
const appConfig${camelName} = _appConfig as AppConfig & { ${key}: { ${prose ? 'prose: { ' : ''}${camelName}: Partial<typeof theme> } }${prose ? ' }' : ''}
|
||||
|
||||
const ${camelName} = tv({ extend: tv(theme), ...(appConfig${camelName}.${key}?.${prose ? 'prose?.' : ''}${camelName} || {}) })
|
||||
|
||||
type ${upperName}Variants = VariantProps<typeof ${camelName}>
|
||||
|
||||
export interface ${upperName}Props extends Pick<${upperName}RootProps> {
|
||||
class?: any
|
||||
ui?: ${upperName}['slots']
|
||||
ui?: Partial<typeof ${camelName}.slots>
|
||||
}
|
||||
|
||||
export interface ${upperName}Emits extends ${upperName}RootEmits {}
|
||||
@@ -91,21 +95,16 @@ export interface ${upperName}Slots {}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { ${upperName}Root, useForwardPropsEmits } from 'reka-ui'
|
||||
import { reactivePick } from '@vueuse/core'
|
||||
import { useAppConfig } from '#imports'
|
||||
import { tv } from '../utils/tv'
|
||||
|
||||
const props = defineProps<${upperName}Props>()
|
||||
const emits = defineEmits<${upperName}Emits>()
|
||||
const slots = defineSlots<${upperName}Slots>()
|
||||
|
||||
const appConfig = useAppConfig() as ${upperName}['AppConfig']
|
||||
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props), emits)
|
||||
|
||||
const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.${camelName} || {}) })())
|
||||
const ui = ${camelName}()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { withoutTrailingSlash } from 'ufo'
|
||||
// import { withoutTrailingSlash } from 'ufo'
|
||||
import colors from 'tailwindcss/colors'
|
||||
// import { debounce } from 'perfect-debounce'
|
||||
|
||||
const route = useRoute()
|
||||
const appConfig = useAppConfig()
|
||||
@@ -11,8 +12,17 @@ const { data: files } = useLazyAsyncData('search', () => queryCollectionSearchSe
|
||||
server: false
|
||||
})
|
||||
|
||||
const searchTerm = ref('')
|
||||
|
||||
// watch(searchTerm, debounce((query: string) => {
|
||||
// if (!query) {
|
||||
// return
|
||||
// }
|
||||
|
||||
// useTrackEvent('Search', { props: { query: `${query} - ${searchTerm.value?.commandPaletteRef.results.length} results` } })
|
||||
// }, 500))
|
||||
|
||||
const links = useLinks()
|
||||
const searchLinks = useSearchLinks()
|
||||
const color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white')
|
||||
const radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
|
||||
const blackAsPrimary = computed(() => appConfig.theme.blackAsPrimary ? `:root { --ui-primary: black; } .dark { --ui-primary: white; }` : ':root {}')
|
||||
@@ -23,8 +33,8 @@ useHead({
|
||||
{ key: 'theme-color', name: 'theme-color', content: color }
|
||||
],
|
||||
link: [
|
||||
{ rel: 'icon', type: 'image/svg+xml', href: '/icon.svg' },
|
||||
{ rel: 'canonical', href: `https://ui.nuxt.com${withoutTrailingSlash(route.path)}` }
|
||||
{ rel: 'icon', type: 'image/svg+xml', href: '/icon.svg' }
|
||||
// { rel: 'canonical', href: `https://ui.nuxt.com${withoutTrailingSlash(route.path)}` }
|
||||
],
|
||||
style: [
|
||||
{ innerHTML: radius, id: 'nuxt-ui-radius', tagPriority: -2 },
|
||||
@@ -51,7 +61,7 @@ provide('navigation', mappedNavigation)
|
||||
<NuxtLoadingIndicator color="var(--ui-primary)" :height="2" />
|
||||
|
||||
<template v-if="!route.path.startsWith('/examples')">
|
||||
<Banner />
|
||||
<!-- <Banner /> -->
|
||||
|
||||
<Header :links="links" />
|
||||
</template>
|
||||
@@ -65,7 +75,7 @@ provide('navigation', mappedNavigation)
|
||||
|
||||
<ClientOnly>
|
||||
<LazyUContentSearch
|
||||
:links="searchLinks"
|
||||
v-model:search-term="searchTerm"
|
||||
:files="files"
|
||||
:groups="[{
|
||||
id: 'framework',
|
||||
@@ -85,5 +95,5 @@ provide('navigation', mappedNavigation)
|
||||
</template>
|
||||
|
||||
<style>
|
||||
/* Safelist (do not remove): [&>div]:*:my-0 [&>div]:*:w-full h-64 !px-0 !py-0 !pt-0 !pb-0 !p-0 !justify-start !justify-end !min-h-96 h-136 max-h-[341px] */
|
||||
/* Safelist (do not remove): [&>div]:*:my-0 [&>div]:*:w-full h-64 !px-0 !py-0 !pt-0 !pb-0 !p-0 !justify-start !min-h-96 h-136 */
|
||||
</style>
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
const el = ref<HTMLDivElement | null>(null)
|
||||
|
||||
onMounted(() => {
|
||||
if (!el.value) {
|
||||
return
|
||||
}
|
||||
|
||||
const script = document.createElement('script')
|
||||
script.setAttribute('type', 'text/javascript')
|
||||
script.setAttribute('src', 'https://cdn.carbonads.com/carbon.js?serve=CWYIVK3E&placement=uinuxtcom')
|
||||
script.setAttribute('id', '_carbonads_js')
|
||||
|
||||
el.value?.appendChild(script)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="el" class="carbon" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "../assets/css/main.css";
|
||||
|
||||
.carbon :deep(#carbonads) {
|
||||
@apply relative border border-(--ui-border) rounded-[calc(var(--ui-radius)*1.5)] hover:bg-(--ui-bg-elevated)/50 w-full transition-colors min-h-[220px] p-2;
|
||||
|
||||
.carbon-img {
|
||||
@apply flex justify-center w-full;
|
||||
|
||||
& > img {
|
||||
@apply !max-w-full w-full rounded-(--ui-radius);
|
||||
}
|
||||
}
|
||||
|
||||
.carbon-text {
|
||||
@apply text-sm text-(--ui-text-muted) transition-colors text-center text-pretty flex pt-2;
|
||||
}
|
||||
|
||||
.carbon-poweredby {
|
||||
@apply block text-xs text-center text-(--ui-text-muted) pt-2;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.carbon-text {
|
||||
@apply text-(--ui-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,18 +1,7 @@
|
||||
<template>
|
||||
<UBanner
|
||||
id="ui3-launch"
|
||||
icon="i-lucide-rocket"
|
||||
:actions="[
|
||||
{
|
||||
label: 'Discover Nuxt UI Pro',
|
||||
to: '/pro/pricing',
|
||||
trailingIcon: 'i-lucide-arrow-right'
|
||||
}
|
||||
]"
|
||||
close
|
||||
>
|
||||
<UBanner icon="i-lucide-construction" :actions="[{ label: 'Go to Nuxt UI v2', to: 'https://ui.nuxt.com', trailingIcon: 'i-lucide-arrow-right' }]" :close="false">
|
||||
<template #title>
|
||||
<span class="font-semibold">Nuxt UI v3</span> is officially released.
|
||||
You're looking at the documentation for <span class="font-semibold">Nuxt UI v3</span>!
|
||||
</template>
|
||||
</UBanner>
|
||||
</template>
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
const endDate = new Date('2025-03-14T23:59:59Z')
|
||||
const second = 1000
|
||||
const minute = second * 60
|
||||
const hour = minute * 60
|
||||
const day = hour * 24
|
||||
|
||||
function getCountdown() {
|
||||
const distance = Math.floor((endDate.getTime() - Date.now()))
|
||||
return {
|
||||
day: Math.floor(distance / day),
|
||||
hour: Math.floor((distance % (day)) / (hour)),
|
||||
minute: Math.floor((distance % (hour)) / (minute)),
|
||||
second: Math.floor((distance % (minute)) / (second)),
|
||||
distance
|
||||
}
|
||||
}
|
||||
const countdown = ref(getCountdown())
|
||||
let interval: any
|
||||
if (countdown.value.distance > 0) {
|
||||
onMounted(() => {
|
||||
interval = setInterval(() => {
|
||||
countdown.value = getCountdown()
|
||||
if (countdown.value.distance <= 0) {
|
||||
clearInterval(interval)
|
||||
}
|
||||
}, 1000)
|
||||
})
|
||||
}
|
||||
const plural = (value: number) => (value === 1 ? '' : 's')
|
||||
const double = (value: number) => (value < 10 ? `0${value}` : value)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<p class="font-semibold text-gray-900 dark:text-white text-sm mb-3">
|
||||
Nuxt UI v3 launch offer ends in:
|
||||
</p>
|
||||
|
||||
<div class="flex items-center justify-center gap-2 text-center">
|
||||
<template v-for="(value, key) in countdown" :key="key">
|
||||
<div v-if="key !== 'distance'" class="flex flex-col items-center gap-2">
|
||||
<UBadge color="primary" class="w-14 h-14 font-bold text-2xl flex items-center justify-center tabular-nums" variant="subtle">
|
||||
{{ double(value) }}
|
||||
</UBadge>
|
||||
<span class="text-[10px] font-semibold text-gray-900 dark:text-white tracking-wide tabular-nums uppercase">{{ key }}{{ plural(value) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -2,8 +2,8 @@
|
||||
const route = useRoute()
|
||||
|
||||
const links = [{
|
||||
label: 'Team',
|
||||
to: '/team'
|
||||
label: 'Figma',
|
||||
to: '/figma'
|
||||
}, {
|
||||
label: 'Roadmap',
|
||||
to: '/roadmap'
|
||||
|
||||
@@ -22,20 +22,8 @@ onMounted(() => {
|
||||
|
||||
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
||||
|
||||
const githubLink = computed(() => {
|
||||
return `https://github.com/nuxt/${value.value}`
|
||||
})
|
||||
|
||||
const desktopLinks = computed(() => props.links.map(({ icon, ...link }) => link))
|
||||
const mobileLinks = computed(() => [
|
||||
...props.links.map(link => ({ ...link, defaultOpen: link.children && route.path.startsWith(link.to as string) })),
|
||||
{
|
||||
label: 'Open on GitHub',
|
||||
to: githubLink.value,
|
||||
icon: 'i-simple-icons-github',
|
||||
target: '_blank'
|
||||
}
|
||||
])
|
||||
const mobileLinks = computed(() => props.links.map(link => ({ ...link, defaultOpen: link.children && route.path.startsWith(link.to as string) })))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -53,7 +41,7 @@ const mobileLinks = computed(() => [
|
||||
<UDropdownMenu
|
||||
v-slot="{ open }"
|
||||
:modal="false"
|
||||
:items="[{ label: `v${config.version}`, active: true, color: 'primary', checked: true, type: 'checkbox' }, { label: module === 'ui-pro' ? 'v1.7.1' : 'v2.21.1', to: module === 'ui-pro' ? 'https://ui2.nuxt.com/pro' : 'https://ui2.nuxt.com' }]"
|
||||
:items="[{ label: `v${config.version}`, active: true, color: 'primary', checked: true, type: 'checkbox' }, { label: module === 'ui-pro' ? 'v1.5' : 'v2.19', to: module === 'ui-pro' ? 'https://ui.nuxt.com/pro' : 'https://ui.nuxt.com' }]"
|
||||
:ui="{ content: 'w-(--reka-dropdown-menu-trigger-width) min-w-0' }"
|
||||
size="xs"
|
||||
>
|
||||
@@ -85,7 +73,7 @@ const mobileLinks = computed(() => [
|
||||
:key="value"
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
:to="githubLink"
|
||||
:to="`https://github.com/nuxt/${value}`"
|
||||
target="_blank"
|
||||
icon="i-simple-icons-github"
|
||||
aria-label="GitHub"
|
||||
@@ -94,7 +82,7 @@ const mobileLinks = computed(() => [
|
||||
</template>
|
||||
|
||||
<template #body>
|
||||
<UNavigationMenu orientation="vertical" :items="mobileLinks" class="-mx-2.5" />
|
||||
<UNavigationMenu orientation="vertical" :items="mobileLinks" class="-mx-2.5" default-open />
|
||||
|
||||
<USeparator type="dashed" class="mt-4 mb-6" />
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import { kebabCase } from 'scule'
|
||||
|
||||
interface Star {
|
||||
x: number
|
||||
y: number
|
||||
@@ -14,7 +12,6 @@ const props = withDefaults(defineProps<{
|
||||
color?: string
|
||||
size?: { min: number, max: number }
|
||||
speed?: 'slow' | 'normal' | 'fast'
|
||||
isIndex?: boolean
|
||||
}>(), {
|
||||
starCount: 50,
|
||||
color: 'var(--ui-primary)',
|
||||
@@ -22,12 +19,9 @@ const props = withDefaults(defineProps<{
|
||||
min: 1,
|
||||
max: 3
|
||||
}),
|
||||
speed: 'normal',
|
||||
isIndex: false
|
||||
speed: 'normal'
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
// Generate random stars
|
||||
const generateStars = (count: number): Star[] => {
|
||||
return Array.from({ length: count }, () => {
|
||||
@@ -41,7 +35,7 @@ const generateStars = (count: number): Star[] => {
|
||||
}
|
||||
|
||||
// Generate all stars
|
||||
const stars = useState<Star[]>(`${kebabCase(route.path)}-sky`, () => generateStars(props.starCount))
|
||||
const stars = ref<Star[]>(generateStars(props.starCount))
|
||||
|
||||
// Compute twinkle animation duration based on speed
|
||||
const twinkleDuration = computed(() => {
|
||||
@@ -55,21 +49,23 @@ const twinkleDuration = computed(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="absolute pointer-events-none z-[-1] overflow-hidden" :class="isIndex ? 'inset-y-0 left-4 right-4 lg:right-[50%]' : 'inset-0'">
|
||||
<div
|
||||
v-for="star in stars"
|
||||
:key="star.id"
|
||||
class="star absolute"
|
||||
:style="{
|
||||
'left': `${star.x}%`,
|
||||
'top': `${star.y}%`,
|
||||
'transform': 'translate(-50%, -50%)',
|
||||
'--star-size': `${star.size}px`,
|
||||
'--star-color': color,
|
||||
'--twinkle-delay': `${star.twinkleDelay}s`,
|
||||
'--twinkle-duration': twinkleDuration
|
||||
}"
|
||||
/>
|
||||
<div class="absolute pointer-events-none z-[-1] inset-y-0 left-4 right-4 lg:right-[50%] overflow-hidden">
|
||||
<ClientOnly>
|
||||
<div
|
||||
v-for="star in stars"
|
||||
:key="star.id"
|
||||
class="star absolute"
|
||||
:style="{
|
||||
'left': `${star.x}%`,
|
||||
'top': `${star.y}%`,
|
||||
'transform': 'translate(-50%, -50%)',
|
||||
'--star-size': `${star.size}px`,
|
||||
'--star-color': color,
|
||||
'--twinkle-delay': `${star.twinkleDelay}s`,
|
||||
'--twinkle-duration': twinkleDuration
|
||||
}"
|
||||
/>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import { kebabCase } from 'scule'
|
||||
|
||||
interface Star {
|
||||
x: number
|
||||
y: number
|
||||
size: number
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
starCount?: number
|
||||
color?: string
|
||||
@@ -22,10 +14,8 @@ const props = withDefaults(defineProps<{
|
||||
})
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
// Generate random star positions and sizes
|
||||
const generateStars = (count: number): Star[] => {
|
||||
const generateStars = (count: number) => {
|
||||
return Array.from({ length: count }, () => ({
|
||||
x: Math.floor(Math.random() * 2000),
|
||||
y: Math.floor(Math.random() * 2000),
|
||||
@@ -35,58 +25,52 @@ const generateStars = (count: number): Star[] => {
|
||||
}))
|
||||
}
|
||||
|
||||
// Define speed configurations once
|
||||
const speedMap = {
|
||||
slow: { duration: 200, opacity: 0.5, ratio: 0.3 },
|
||||
normal: { duration: 150, opacity: 0.75, ratio: 0.3 },
|
||||
fast: { duration: 100, opacity: 1, ratio: 0.4 }
|
||||
}
|
||||
|
||||
// Use a more efficient approach to generate and store stars
|
||||
const stars = useState<{ slow: Star[], normal: Star[], fast: Star[] }>(`${kebabCase(route.path)}-stars`, () => {
|
||||
return {
|
||||
slow: generateStars(Math.floor(props.starCount * speedMap.slow.ratio)),
|
||||
normal: generateStars(Math.floor(props.starCount * speedMap.normal.ratio)),
|
||||
fast: generateStars(Math.floor(props.starCount * speedMap.fast.ratio))
|
||||
}
|
||||
})
|
||||
|
||||
// Compute star layers with different speeds and opacities
|
||||
const starLayers = computed(() => [
|
||||
{ stars: stars.value.fast, ...speedMap.fast },
|
||||
{ stars: stars.value.normal, ...speedMap.normal },
|
||||
{ stars: stars.value.slow, ...speedMap.slow }
|
||||
])
|
||||
const starLayers = computed(() => {
|
||||
const speedMap = {
|
||||
slow: { duration: 200, opacity: 0.5 },
|
||||
normal: { duration: 150, opacity: 0.75 },
|
||||
fast: { duration: 100, opacity: 1 }
|
||||
}
|
||||
|
||||
return [
|
||||
{ stars: generateStars(props.starCount), ...speedMap.fast },
|
||||
{ stars: generateStars(Math.floor(props.starCount * 0.6)), ...speedMap.normal },
|
||||
{ stars: generateStars(Math.floor(props.starCount * 0.3)), ...speedMap.slow }
|
||||
]
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="absolute pointer-events-none z-[-1] inset-y-0 inset-x-5 sm:inset-x-7 lg:inset-x-9 overflow-hidden">
|
||||
<div class="stars size-full absolute inset-x-0 top-0">
|
||||
<div
|
||||
v-for="(layer, index) in starLayers"
|
||||
:key="index"
|
||||
class="star-layer"
|
||||
:style="{
|
||||
'--star-duration': `${layer.duration}s`,
|
||||
'--star-opacity': layer.opacity,
|
||||
'--star-color': color
|
||||
}"
|
||||
>
|
||||
<ClientOnly>
|
||||
<div class="stars size-full absolute inset-x-0 top-0">
|
||||
<div
|
||||
v-for="(star, starIndex) in layer.stars"
|
||||
:key="starIndex"
|
||||
class="star absolute rounded-full"
|
||||
v-for="(layer, index) in starLayers"
|
||||
:key="index"
|
||||
class="star-layer"
|
||||
:style="{
|
||||
left: `${star.x}px`,
|
||||
top: `${star.y}px`,
|
||||
width: `${star.size}px`,
|
||||
height: `${star.size}px`,
|
||||
backgroundColor: 'var(--star-color)',
|
||||
opacity: 'var(--star-opacity)'
|
||||
'--star-duration': `${layer.duration}s`,
|
||||
'--star-opacity': layer.opacity,
|
||||
'--star-color': color
|
||||
}"
|
||||
/>
|
||||
>
|
||||
<div
|
||||
v-for="(star, starIndex) in layer.stars"
|
||||
:key="starIndex"
|
||||
class="star absolute rounded-full"
|
||||
:style="{
|
||||
left: `${star.x}px`,
|
||||
top: `${star.y}px`,
|
||||
width: `${star.size}px`,
|
||||
height: `${star.size}px`,
|
||||
backgroundColor: 'var(--star-color)',
|
||||
opacity: 'var(--star-opacity)'
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<!-- eslint-disable no-useless-escape -->
|
||||
<script setup lang="ts">
|
||||
import type { ChipProps } from '@nuxt/ui'
|
||||
import json5 from 'json5'
|
||||
import { upperFirst, camelCase, kebabCase } from 'scule'
|
||||
import { hash } from 'ohash'
|
||||
@@ -54,8 +53,6 @@ const props = defineProps<{
|
||||
hide?: string[]
|
||||
/** List of props to externalize in script setup */
|
||||
external?: string[]
|
||||
/** The types of the externalized props */
|
||||
externalTypes?: string[]
|
||||
/** List of props to use with `v-model` */
|
||||
model?: string[]
|
||||
/** List of props to cast from code and selection */
|
||||
@@ -212,21 +209,11 @@ ${props.slots?.default}
|
||||
code += `
|
||||
<script setup lang="ts">
|
||||
`
|
||||
if (props.externalTypes?.length) {
|
||||
const removeArrayBrackets = (type: string): string => type.endsWith('[]') ? removeArrayBrackets(type.slice(0, -2)) : type
|
||||
|
||||
const types = props.externalTypes.map(type => removeArrayBrackets(type))
|
||||
code += `import type { ${types.join(', ')} } from '@nuxt/ui${props.pro ? '-pro' : ''}'
|
||||
|
||||
`
|
||||
}
|
||||
|
||||
for (const [i, key] of props.external.entries()) {
|
||||
for (const key of props.external) {
|
||||
const cast = props.cast?.[key]
|
||||
const value = cast ? castMap[cast]!.template(componentProps[key]) : json5.stringify(componentProps[key], null, 2)?.replace(/,([ |\t\n]+[}|\]])/g, '$1')
|
||||
const type = props.externalTypes?.[i] ? `<${props.externalTypes[i]}>` : ''
|
||||
|
||||
code += `const ${key === 'modelValue' ? 'value' : key} = ref${type}(${value})
|
||||
code += `const ${key === 'modelValue' ? 'value' : key} = ref(${value})
|
||||
`
|
||||
}
|
||||
code += `<\/script>
|
||||
@@ -328,7 +315,7 @@ const { data: ast } = await useAsyncData(`component-code-${name}-${hash({ props:
|
||||
|
||||
<template>
|
||||
<div class="my-5">
|
||||
<div class="relative">
|
||||
<div>
|
||||
<div v-if="options.length" class="flex flex-wrap items-center gap-2.5 border border-(--ui-border-muted) border-b-0 relative rounded-t-[calc(var(--ui-radius)*1.5)] px-4 py-2.5 overflow-x-auto">
|
||||
<template v-for="option in options" :key="option.name">
|
||||
<UFormField
|
||||
@@ -359,7 +346,7 @@ const { data: ast } = await useAsyncData(`component-code-${name}-${hash({ props:
|
||||
inset
|
||||
standalone
|
||||
:color="(modelValue as any)"
|
||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
||||
:size="ui.itemLeadingChipSize()"
|
||||
class="size-2"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { ChipProps } from '@nuxt/ui'
|
||||
import { camelCase } from 'scule'
|
||||
import { useElementSize } from '@vueuse/core'
|
||||
import { get, set } from '#ui/utils'
|
||||
@@ -186,7 +185,7 @@ const urlSearchParams = computed(() => {
|
||||
inset
|
||||
standalone
|
||||
:color="(modelValue as any)"
|
||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
||||
:size="ui.itemLeadingChipSize()"
|
||||
class="size-2"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -11,24 +11,19 @@ function getEmojiFlag(locale: string): string {
|
||||
const languageToCountry: Record<string, string> = {
|
||||
ar: 'sa', // Arabic -> Saudi Arabia
|
||||
bn: 'bd', // Bengali -> Bangladesh
|
||||
ca: 'es', // Catalan -> Spain
|
||||
ckb: 'iq', // Central Kurdish -> Iraq
|
||||
cs: 'cz', // Czech -> Czech Republic (note: modern country code is actually 'cz')
|
||||
da: 'dk', // Danish -> Denmark
|
||||
el: 'gr', // Greek -> Greece
|
||||
en: 'gb', // English -> Great Britain
|
||||
et: 'ee', // Estonian -> Estonia
|
||||
en: 'gb', // English -> Great Britain
|
||||
he: 'il', // Hebrew -> Israel
|
||||
hi: 'in', // Hindi -> India
|
||||
hy: 'am', // Armenian -> Armenia
|
||||
ja: 'jp', // Japanese -> Japan
|
||||
kk: 'kz', // Kazakh -> Kazakhstan
|
||||
km: 'kh', // Khmer -> Cambodia
|
||||
ko: 'kr', // Korean -> South Korea
|
||||
nb: 'no', // Norwegian Bokmål -> Norway
|
||||
sv: 'se', // Swedish -> Sweden
|
||||
uk: 'ua', // Ukrainian -> Ukraine
|
||||
ur: 'pk', // Urdu -> Pakistan
|
||||
vi: 'vn' // Vietnamese -> Vietnam
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { AccordionItem } from '@nuxt/ui'
|
||||
|
||||
const items: AccordionItem[] = [
|
||||
const items = [
|
||||
{
|
||||
label: 'Icons',
|
||||
icon: 'i-lucide-smile'
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { AccordionItem } from '@nuxt/ui'
|
||||
|
||||
const items: AccordionItem[] = [
|
||||
const items = [
|
||||
{
|
||||
label: 'Icons',
|
||||
icon: 'i-lucide-smile'
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { AccordionItem } from '@nuxt/ui'
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: 'Icons',
|
||||
@@ -10,7 +8,7 @@ const items = [
|
||||
{
|
||||
label: 'Colors',
|
||||
icon: 'i-lucide-swatch-book',
|
||||
slot: 'colors' as const,
|
||||
slot: 'colors',
|
||||
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
|
||||
},
|
||||
{
|
||||
@@ -18,7 +16,7 @@ const items = [
|
||||
icon: 'i-lucide-box',
|
||||
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
|
||||
}
|
||||
] satisfies AccordionItem[]
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type { AccordionItem } from '@nuxt/ui'
|
||||
import { useSortable } from '@vueuse/integrations/useSortable'
|
||||
|
||||
const items = shallowRef<AccordionItem[]>([
|
||||
{
|
||||
label: 'Icons',
|
||||
icon: 'i-lucide-smile',
|
||||
content: 'You have nothing to do, @nuxt/icon will handle it automatically.'
|
||||
},
|
||||
{
|
||||
label: 'Colors',
|
||||
icon: 'i-lucide-swatch-book',
|
||||
content: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
|
||||
},
|
||||
{
|
||||
label: 'Components',
|
||||
icon: 'i-lucide-box',
|
||||
content: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
|
||||
}
|
||||
])
|
||||
|
||||
const accordion = useTemplateRef<HTMLElement>('accordion')
|
||||
|
||||
useSortable(accordion, items, {
|
||||
animation: 150
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UAccordion ref="accordion" :items="items" />
|
||||
</template>
|
||||
@@ -1,7 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { AccordionItem } from '@nuxt/ui'
|
||||
|
||||
const items: AccordionItem[] = [
|
||||
const items = [
|
||||
{
|
||||
label: 'Icons',
|
||||
icon: 'i-lucide-smile',
|
||||
|
||||
@@ -1,35 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
import type { BreadcrumbItem } from '@nuxt/ui'
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: 'Home',
|
||||
to: '/'
|
||||
},
|
||||
{
|
||||
slot: 'dropdown' as const,
|
||||
icon: 'i-lucide-ellipsis',
|
||||
children: [
|
||||
{
|
||||
label: 'Documentation'
|
||||
},
|
||||
{
|
||||
label: 'Themes'
|
||||
},
|
||||
{
|
||||
label: 'GitHub'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Components',
|
||||
to: '/components'
|
||||
},
|
||||
{
|
||||
label: 'Breadcrumb',
|
||||
to: '/components/breadcrumb'
|
||||
}
|
||||
] satisfies BreadcrumbItem[]
|
||||
const items = [{
|
||||
label: 'Home',
|
||||
to: '/'
|
||||
}, {
|
||||
slot: 'dropdown',
|
||||
icon: 'i-lucide-ellipsis',
|
||||
children: [{
|
||||
label: 'Documentation'
|
||||
}, {
|
||||
label: 'Themes'
|
||||
}, {
|
||||
label: 'GitHub'
|
||||
}]
|
||||
}, {
|
||||
label: 'Components',
|
||||
to: '/components'
|
||||
}, {
|
||||
label: 'Breadcrumb',
|
||||
to: '/components/breadcrumb'
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import type { BreadcrumbItem } from '@nuxt/ui'
|
||||
|
||||
const items: BreadcrumbItem[] = [
|
||||
{
|
||||
label: 'Home',
|
||||
to: '/'
|
||||
},
|
||||
{
|
||||
label: 'Components',
|
||||
to: '/components'
|
||||
},
|
||||
{
|
||||
label: 'Breadcrumb',
|
||||
to: '/components/breadcrumb'
|
||||
}
|
||||
]
|
||||
const items = [{
|
||||
label: 'Home',
|
||||
to: '/'
|
||||
}, {
|
||||
label: 'Components',
|
||||
to: '/components'
|
||||
}, {
|
||||
label: 'Breadcrumb',
|
||||
to: '/components/breadcrumb'
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,30 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items: DropdownMenuItem[] = [
|
||||
{
|
||||
label: 'Team',
|
||||
icon: 'i-lucide-users'
|
||||
},
|
||||
{
|
||||
label: 'Invite users',
|
||||
icon: 'i-lucide-user-plus',
|
||||
children: [
|
||||
{
|
||||
label: 'Invite by email',
|
||||
icon: 'i-lucide-send-horizontal'
|
||||
},
|
||||
{
|
||||
label: 'Invite by link',
|
||||
icon: 'i-lucide-link'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'New team',
|
||||
icon: 'i-lucide-plus'
|
||||
}
|
||||
]
|
||||
const items = [{
|
||||
label: 'Team',
|
||||
icon: 'i-lucide-users'
|
||||
}, {
|
||||
label: 'Invite users',
|
||||
icon: 'i-lucide-user-plus',
|
||||
children: [{
|
||||
label: 'Invite by email',
|
||||
icon: 'i-lucide-send-horizontal'
|
||||
}, {
|
||||
label: 'Invite by link',
|
||||
icon: 'i-lucide-link'
|
||||
}]
|
||||
}, {
|
||||
label: 'New team',
|
||||
icon: 'i-lucide-plus'
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,79 +1,76 @@
|
||||
<script setup lang="ts">
|
||||
const groups = [
|
||||
{
|
||||
id: 'settings',
|
||||
items: [
|
||||
{
|
||||
label: 'Profile',
|
||||
icon: 'i-lucide-user',
|
||||
kbds: ['meta', 'P']
|
||||
},
|
||||
{
|
||||
label: 'Billing',
|
||||
icon: 'i-lucide-credit-card',
|
||||
kbds: ['meta', 'B'],
|
||||
slot: 'billing' as const
|
||||
},
|
||||
{
|
||||
label: 'Notifications',
|
||||
icon: 'i-lucide-bell'
|
||||
},
|
||||
{
|
||||
label: 'Security',
|
||||
icon: 'i-lucide-lock'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'users',
|
||||
label: 'Users',
|
||||
slot: 'users' as const,
|
||||
items: [
|
||||
{
|
||||
label: 'Benjamin Canac',
|
||||
suffix: 'benjamincanac',
|
||||
to: 'https://github.com/benjamincanac',
|
||||
target: '_blank'
|
||||
},
|
||||
{
|
||||
label: 'Sylvain Marroufin',
|
||||
suffix: 'smarroufin',
|
||||
to: 'https://github.com/smarroufin',
|
||||
target: '_blank'
|
||||
},
|
||||
{
|
||||
label: 'Sébastien Chopin',
|
||||
suffix: 'atinux',
|
||||
to: 'https://github.com/atinux',
|
||||
target: '_blank'
|
||||
},
|
||||
{
|
||||
label: 'Romain Hamel',
|
||||
suffix: 'romhml',
|
||||
to: 'https://github.com/romhml',
|
||||
target: '_blank'
|
||||
},
|
||||
{
|
||||
label: 'Haytham A. Salama',
|
||||
suffix: 'Haythamasalama',
|
||||
to: 'https://github.com/Haythamasalama',
|
||||
target: '_blank'
|
||||
},
|
||||
{
|
||||
label: 'Daniel Roe',
|
||||
suffix: 'danielroe',
|
||||
to: 'https://github.com/danielroe',
|
||||
target: '_blank'
|
||||
},
|
||||
{
|
||||
label: 'Neil Richter',
|
||||
suffix: 'noook',
|
||||
to: 'https://github.com/noook',
|
||||
target: '_blank'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
const groups = [{
|
||||
id: 'settings',
|
||||
items: [
|
||||
{
|
||||
label: 'Profile',
|
||||
icon: 'i-lucide-user',
|
||||
kbds: ['meta', 'P']
|
||||
},
|
||||
{
|
||||
label: 'Billing',
|
||||
icon: 'i-lucide-credit-card',
|
||||
kbds: ['meta', 'B'],
|
||||
slot: 'billing'
|
||||
},
|
||||
{
|
||||
label: 'Notifications',
|
||||
icon: 'i-lucide-bell'
|
||||
},
|
||||
{
|
||||
label: 'Security',
|
||||
icon: 'i-lucide-lock'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
id: 'users',
|
||||
label: 'Users',
|
||||
slot: 'users',
|
||||
items: [
|
||||
{
|
||||
label: 'Benjamin Canac',
|
||||
suffix: 'benjamincanac',
|
||||
to: 'https://github.com/benjamincanac',
|
||||
target: '_blank'
|
||||
},
|
||||
{
|
||||
label: 'Sylvain Marroufin',
|
||||
suffix: 'smarroufin',
|
||||
to: 'https://github.com/smarroufin',
|
||||
target: '_blank'
|
||||
},
|
||||
{
|
||||
label: 'Sébastien Chopin',
|
||||
suffix: 'atinux',
|
||||
to: 'https://github.com/atinux',
|
||||
target: '_blank'
|
||||
},
|
||||
{
|
||||
label: 'Romain Hamel',
|
||||
suffix: 'romhml',
|
||||
to: 'https://github.com/romhml',
|
||||
target: '_blank'
|
||||
},
|
||||
{
|
||||
label: 'Haytham A. Salama',
|
||||
suffix: 'Haythamasalama',
|
||||
to: 'https://github.com/Haythamasalama',
|
||||
target: '_blank'
|
||||
},
|
||||
{
|
||||
label: 'Daniel Roe',
|
||||
suffix: 'danielroe',
|
||||
to: 'https://github.com/danielroe',
|
||||
target: '_blank'
|
||||
},
|
||||
{
|
||||
label: 'Neil Richter',
|
||||
suffix: 'noook',
|
||||
to: 'https://github.com/noook',
|
||||
target: '_blank'
|
||||
}
|
||||
]
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import type { ContextMenuItem } from '@nuxt/ui'
|
||||
|
||||
const showSidebar = ref(true)
|
||||
const showToolbar = ref(false)
|
||||
|
||||
const items = computed<ContextMenuItem[]>(() => [{
|
||||
const items = computed(() => [{
|
||||
label: 'View',
|
||||
type: 'label' as const
|
||||
}, {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { ContextMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items: ContextMenuItem[][] = [
|
||||
const items = [
|
||||
[
|
||||
{
|
||||
label: 'View',
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import type { ContextMenuItem } from '@nuxt/ui'
|
||||
|
||||
const loading = ref(true)
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: 'Refresh the Page',
|
||||
slot: 'refresh' as const
|
||||
},
|
||||
{
|
||||
label: 'Clear Cookies and Refresh'
|
||||
},
|
||||
{
|
||||
label: 'Clear Cache and Refresh'
|
||||
}
|
||||
] satisfies ContextMenuItem[]
|
||||
const items = [{
|
||||
label: 'Refresh the Page',
|
||||
slot: 'refresh'
|
||||
}, {
|
||||
label: 'Clear Cookies and Refresh'
|
||||
}, {
|
||||
label: 'Clear Cache and Refresh'
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { createReusableTemplate, useMediaQuery } from '@vueuse/core'
|
||||
|
||||
const [DefineFormTemplate, ReuseFormTemplate] = createReusableTemplate()
|
||||
const isDesktop = useMediaQuery('(min-width: 768px)')
|
||||
|
||||
const open = ref(false)
|
||||
|
||||
const state = reactive({
|
||||
email: undefined
|
||||
})
|
||||
|
||||
const title = 'Edit profile'
|
||||
const description = 'Make changes to your profile here. Click save when you\'re done.'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DefineFormTemplate>
|
||||
<UForm :state="state" class="space-y-4">
|
||||
<UFormField label="Email" name="email" required>
|
||||
<UInput v-model="state.email" placeholder="shadcn@example.com" required />
|
||||
</UFormField>
|
||||
|
||||
<UButton label="Save changes" type="submit" />
|
||||
</UForm>
|
||||
</DefineFormTemplate>
|
||||
|
||||
<UModal v-if="isDesktop" v-model:open="open" :title="title" :description="description">
|
||||
<UButton label="Edit profile" color="neutral" variant="outline" />
|
||||
|
||||
<template #body>
|
||||
<ReuseFormTemplate />
|
||||
</template>
|
||||
</UModal>
|
||||
|
||||
<UDrawer v-else v-model:open="open" :title="title" :description="description">
|
||||
<UButton label="Edit profile" color="neutral" variant="outline" />
|
||||
|
||||
<template #body>
|
||||
<ReuseFormTemplate />
|
||||
</template>
|
||||
</UDrawer>
|
||||
</template>
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
||||
|
||||
const showBookmarks = ref(true)
|
||||
const showHistory = ref(false)
|
||||
const showDownloads = ref(false)
|
||||
@@ -38,7 +36,7 @@ const items = computed(() => [{
|
||||
onUpdateChecked(checked: boolean) {
|
||||
showDownloads.value = checked
|
||||
}
|
||||
}] satisfies DropdownMenuItem[])
|
||||
}])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items: DropdownMenuItem[][] = [
|
||||
const items = [
|
||||
[
|
||||
{
|
||||
label: 'View',
|
||||
@@ -19,7 +17,7 @@ const items: DropdownMenuItem[][] = [
|
||||
[
|
||||
{
|
||||
label: 'Delete',
|
||||
color: 'error',
|
||||
color: 'error' as const,
|
||||
icon: 'i-lucide-trash'
|
||||
}
|
||||
]
|
||||
@@ -29,5 +27,9 @@ const items: DropdownMenuItem[][] = [
|
||||
<template>
|
||||
<UDropdownMenu :items="items" :ui="{ content: 'w-48' }">
|
||||
<UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" />
|
||||
|
||||
<template #profile-trailing>
|
||||
<UIcon name="i-lucide-badge-check" class="shrink-0 size-5 text-(--ui-primary)" />
|
||||
</template>
|
||||
</UDropdownMenu>
|
||||
</template>
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: 'Profile',
|
||||
icon: 'i-lucide-user',
|
||||
slot: 'profile' as const
|
||||
}, {
|
||||
label: 'Billing',
|
||||
icon: 'i-lucide-credit-card'
|
||||
}, {
|
||||
label: 'Settings',
|
||||
icon: 'i-lucide-cog'
|
||||
}
|
||||
] satisfies DropdownMenuItem[]
|
||||
const items = [{
|
||||
label: 'Profile',
|
||||
icon: 'i-lucide-user',
|
||||
slot: 'profile'
|
||||
}, {
|
||||
label: 'Billing',
|
||||
icon: 'i-lucide-credit-card'
|
||||
}, {
|
||||
label: 'Settings',
|
||||
icon: 'i-lucide-cog'
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
import type { DropdownMenuItem } from '@nuxt/ui'
|
||||
|
||||
const open = ref(false)
|
||||
|
||||
defineShortcuts({
|
||||
o: () => open.value = !open.value
|
||||
})
|
||||
|
||||
const items: DropdownMenuItem[] = [
|
||||
{
|
||||
label: 'Profile',
|
||||
icon: 'i-lucide-user'
|
||||
}, {
|
||||
label: 'Billing',
|
||||
icon: 'i-lucide-credit-card'
|
||||
}, {
|
||||
label: 'Settings',
|
||||
icon: 'i-lucide-cog'
|
||||
}
|
||||
]
|
||||
const items = [{
|
||||
label: 'Profile',
|
||||
icon: 'i-lucide-user'
|
||||
}, {
|
||||
label: 'Billing',
|
||||
icon: 'i-lucide-credit-card'
|
||||
}, {
|
||||
label: 'Settings',
|
||||
icon: 'i-lucide-cog'
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -14,7 +14,7 @@ const validate = (state: any): FormError[] => {
|
||||
}
|
||||
|
||||
const toast = useToast()
|
||||
async function onSubmit(event: FormSubmitEvent<typeof state>) {
|
||||
async function onSubmit(event: FormSubmitEvent<any>) {
|
||||
toast.add({ title: 'Success', description: 'The form has been submitted.', color: 'success' })
|
||||
console.log(event.data)
|
||||
}
|
||||
|
||||
@@ -34,10 +34,9 @@ const schema = z.object({
|
||||
pin: z.string().regex(/^\d$/).array().length(5)
|
||||
})
|
||||
|
||||
type Input = z.input<typeof schema>
|
||||
type Output = z.output<typeof schema>
|
||||
type Schema = z.input<typeof schema>
|
||||
|
||||
const state = reactive<Partial<Input>>({})
|
||||
const state = reactive<Partial<Schema>>({})
|
||||
|
||||
const form = useTemplateRef('form')
|
||||
|
||||
@@ -48,7 +47,7 @@ const items = [
|
||||
]
|
||||
|
||||
const toast = useToast()
|
||||
async function onSubmit(event: FormSubmitEvent<Output>) {
|
||||
async function onSubmit(event: FormSubmitEvent<any>) {
|
||||
toast.add({ title: 'Success', description: 'The form has been submitted.', color: 'success' })
|
||||
console.log(event.data)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ const state = reactive({
|
||||
})
|
||||
|
||||
const toast = useToast()
|
||||
async function onSubmit(event: FormSubmitEvent<typeof state>) {
|
||||
async function onSubmit(event: FormSubmitEvent<any>) {
|
||||
toast.add({ title: 'Success', description: 'The form has been submitted.', color: 'success' })
|
||||
console.log(event.data)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ type NestedSchema = z.output<typeof nestedSchema>
|
||||
const state = reactive<Partial<Schema & NestedSchema>>({ })
|
||||
|
||||
const toast = useToast()
|
||||
async function onSubmit(event: FormSubmitEvent<Schema>) {
|
||||
async function onSubmit(event: FormSubmitEvent<any>) {
|
||||
toast.add({ title: 'Success', description: 'The form has been submitted.', color: 'success' })
|
||||
console.log(event.data)
|
||||
}
|
||||
@@ -39,7 +39,7 @@ async function onSubmit(event: FormSubmitEvent<Schema>) {
|
||||
<UCheckbox v-model="state.news" name="news" label="Register to our newsletter" @update:model-value="state.email = undefined" />
|
||||
</div>
|
||||
|
||||
<UForm v-if="state.news" :state="state" :schema="nestedSchema" nested>
|
||||
<UForm v-if="state.news" :state="state" :schema="nestedSchema">
|
||||
<UFormField label="Email" name="email">
|
||||
<UInput v-model="state.email" placeholder="john@lennon.com" />
|
||||
</UFormField>
|
||||
|
||||
@@ -34,7 +34,7 @@ function removeItem() {
|
||||
|
||||
const toast = useToast()
|
||||
|
||||
async function onSubmit(event: FormSubmitEvent<Schema>) {
|
||||
async function onSubmit(event: FormSubmitEvent<any>) {
|
||||
toast.add({ title: 'Success', description: 'The form has been submitted.', color: 'success' })
|
||||
console.log(event.data)
|
||||
}
|
||||
@@ -51,14 +51,7 @@ async function onSubmit(event: FormSubmitEvent<Schema>) {
|
||||
<UInput v-model="state.customer" placeholder="Wonka Industries" />
|
||||
</UFormField>
|
||||
|
||||
<UForm
|
||||
v-for="item, count in state.items"
|
||||
:key="count"
|
||||
:state="item"
|
||||
:schema="itemSchema"
|
||||
nested
|
||||
class="flex gap-2"
|
||||
>
|
||||
<UForm v-for="item, count in state.items" :key="count" :state="item" :schema="itemSchema" class="flex gap-2">
|
||||
<UFormField :label="!count ? 'Description' : undefined" name="description">
|
||||
<UInput v-model="item.description" />
|
||||
</UFormField>
|
||||
|
||||
@@ -14,7 +14,7 @@ const validate = (state: any): FormError[] => {
|
||||
}
|
||||
|
||||
const toast = useToast()
|
||||
async function onSubmit(event: FormSubmitEvent<typeof state>) {
|
||||
async function onSubmit(event: FormSubmitEvent<any>) {
|
||||
toast.add({ title: 'Success', description: 'The form has been submitted.', color: 'success' })
|
||||
console.log(event.data)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ async function onSubmit(event: FormSubmitEvent<Schema>) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UForm :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
|
||||
<UForm :schema="v.safeParser(schema)" :state="state" class="space-y-4" @submit="onSubmit">
|
||||
<UFormField label="Email" name="email">
|
||||
<UInput v-model="state.email" />
|
||||
</UFormField>
|
||||
|
||||
@@ -16,7 +16,7 @@ function onOpen() {
|
||||
|
||||
<template>
|
||||
<UInputMenu
|
||||
:items="countries"
|
||||
:items="countries || []"
|
||||
:loading="status === 'pending'"
|
||||
label-key="name"
|
||||
:search-input="{ icon: 'i-lucide-search' }"
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users',
|
||||
transform: (data: { id: number, name: string }[]) => {
|
||||
@@ -8,7 +6,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
label: user.name,
|
||||
value: String(user.id),
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
}))
|
||||
})) || []
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
@@ -16,7 +14,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
|
||||
<template>
|
||||
<UInputMenu
|
||||
:items="users"
|
||||
:items="users || []"
|
||||
:loading="status === 'pending'"
|
||||
icon="i-lucide-user"
|
||||
placeholder="Select user"
|
||||
@@ -25,7 +23,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<UAvatar
|
||||
v-if="modelValue"
|
||||
v-bind="modelValue.avatar"
|
||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
||||
:size="ui.leadingAvatarSize()"
|
||||
:class="ui.leadingAvatar()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users-email',
|
||||
transform: (data: { id: number, name: string, email: string }[]) => {
|
||||
@@ -9,7 +7,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
email: user.email,
|
||||
value: String(user.id),
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
}))
|
||||
})) || []
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
@@ -17,7 +15,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
|
||||
<template>
|
||||
<UInputMenu
|
||||
:items="users"
|
||||
:items="users || []"
|
||||
:loading="status === 'pending'"
|
||||
:filter-fields="['label', 'email']"
|
||||
icon="i-lucide-user"
|
||||
@@ -28,7 +26,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<UAvatar
|
||||
v-if="modelValue"
|
||||
v-bind="modelValue.avatar"
|
||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
||||
:size="ui.leadingAvatarSize()"
|
||||
:class="ui.leadingAvatar()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const searchTerm = ref('')
|
||||
const searchTermDebounced = refDebounced(searchTerm, 200)
|
||||
|
||||
@@ -12,7 +10,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
label: user.name,
|
||||
value: String(user.id),
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
}))
|
||||
})) || []
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
@@ -21,7 +19,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<template>
|
||||
<UInputMenu
|
||||
v-model:search-term="searchTerm"
|
||||
:items="users"
|
||||
:items="users || []"
|
||||
:loading="status === 'pending'"
|
||||
ignore-filter
|
||||
icon="i-lucide-user"
|
||||
@@ -31,7 +29,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<UAvatar
|
||||
v-if="modelValue"
|
||||
v-bind="modelValue.avatar"
|
||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
||||
:size="ui.leadingAvatarSize()"
|
||||
:class="ui.leadingAvatar()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { InputMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'benjamincanac',
|
||||
@@ -25,16 +23,8 @@ const items = ref([
|
||||
src: 'https://github.com/noook.png',
|
||||
alt: 'noook'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'sandros94',
|
||||
value: 'sandros94',
|
||||
avatar: {
|
||||
src: 'https://github.com/sandros94.png',
|
||||
alt: 'sandros94'
|
||||
}
|
||||
}
|
||||
] satisfies InputMenuItem[])
|
||||
])
|
||||
const value = ref(items.value[0])
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,30 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import type { InputMenuItem, ChipProps } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'bug',
|
||||
value: 'bug',
|
||||
chip: {
|
||||
color: 'error'
|
||||
color: 'error' as const
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'feature',
|
||||
value: 'feature',
|
||||
chip: {
|
||||
color: 'success'
|
||||
color: 'success' as const
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'enhancement',
|
||||
value: 'enhancement',
|
||||
chip: {
|
||||
color: 'info'
|
||||
color: 'info' as const
|
||||
}
|
||||
}
|
||||
] satisfies InputMenuItem[])
|
||||
|
||||
])
|
||||
const value = ref(items.value[0])
|
||||
</script>
|
||||
|
||||
@@ -36,7 +33,7 @@ const value = ref(items.value[0])
|
||||
v-bind="modelValue.chip"
|
||||
inset
|
||||
standalone
|
||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
||||
:size="ui.itemLeadingChipSize()"
|
||||
:class="ui.itemLeadingChip()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { InputMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'Backlog',
|
||||
@@ -22,8 +20,7 @@ const items = ref([
|
||||
value: 'done',
|
||||
icon: 'i-lucide-circle-check'
|
||||
}
|
||||
] satisfies InputMenuItem[])
|
||||
|
||||
])
|
||||
const value = ref(items.value[0])
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import type { NavigationMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: 'Docs',
|
||||
icon: 'i-lucide-book-open',
|
||||
slot: 'docs' as const,
|
||||
slot: 'docs',
|
||||
children: [
|
||||
{
|
||||
label: 'Icons',
|
||||
@@ -24,7 +22,7 @@ const items = [
|
||||
{
|
||||
label: 'Components',
|
||||
icon: 'i-lucide-box',
|
||||
slot: 'components' as const,
|
||||
slot: 'components',
|
||||
children: [
|
||||
{
|
||||
label: 'Link',
|
||||
@@ -56,7 +54,7 @@ const items = [
|
||||
label: 'GitHub',
|
||||
icon: 'i-simple-icons-github'
|
||||
}
|
||||
] satisfies NavigationMenuItem[]
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import type { NavigationMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: 'Guide',
|
||||
icon: 'i-lucide-book-open'
|
||||
|
||||
},
|
||||
{
|
||||
label: 'Composables',
|
||||
icon: 'i-lucide-database'
|
||||
|
||||
},
|
||||
{
|
||||
label: 'Components',
|
||||
icon: 'i-lucide-box',
|
||||
slot: 'components' as const
|
||||
slot: 'components'
|
||||
}
|
||||
] satisfies NavigationMenuItem[]
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { NavigationMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items: NavigationMenuItem[] = [
|
||||
const items = [
|
||||
{
|
||||
label: 'Guide',
|
||||
icon: 'i-lucide-book-open',
|
||||
|
||||
@@ -40,7 +40,7 @@ const label = ref([])
|
||||
multiple
|
||||
placeholder="Search labels..."
|
||||
:groups="[{ id: 'labels', items }]"
|
||||
:ui="{ input: '[&>input]:h-8 [&>input]:text-sm' }"
|
||||
:ui="{ input: '[&>input]:h-8' }"
|
||||
/>
|
||||
</template>
|
||||
</UPopover>
|
||||
|
||||
@@ -4,7 +4,8 @@ const { data: countries, status, execute } = await useLazyFetch<{
|
||||
code: string
|
||||
emoji: string
|
||||
}[]>('/api/countries.json', {
|
||||
immediate: false
|
||||
immediate: false,
|
||||
default: () => []
|
||||
})
|
||||
|
||||
function onOpen() {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users',
|
||||
transform: (data: { id: number, name: string }[]) => {
|
||||
@@ -8,7 +6,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
label: user.name,
|
||||
value: String(user.id),
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
}))
|
||||
})) || []
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
@@ -16,7 +14,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
|
||||
<template>
|
||||
<USelectMenu
|
||||
:items="users"
|
||||
:items="users || []"
|
||||
:loading="status === 'pending'"
|
||||
icon="i-lucide-user"
|
||||
placeholder="Select user"
|
||||
@@ -26,7 +24,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<UAvatar
|
||||
v-if="modelValue"
|
||||
v-bind="modelValue.avatar"
|
||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
||||
:size="ui.leadingAvatarSize()"
|
||||
:class="ui.leadingAvatar()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users-email',
|
||||
transform: (data: { id: number, name: string, email: string }[]) => {
|
||||
@@ -9,7 +7,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
email: user.email,
|
||||
value: String(user.id),
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
}))
|
||||
})) || []
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
@@ -17,7 +15,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
|
||||
<template>
|
||||
<USelectMenu
|
||||
:items="users"
|
||||
:items="users || []"
|
||||
:loading="status === 'pending'"
|
||||
:filter-fields="['label', 'email']"
|
||||
icon="i-lucide-user"
|
||||
@@ -28,7 +26,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<UAvatar
|
||||
v-if="modelValue"
|
||||
v-bind="modelValue.avatar"
|
||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
||||
:size="ui.leadingAvatarSize()"
|
||||
:class="ui.leadingAvatar()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const searchTerm = ref('')
|
||||
const searchTermDebounced = refDebounced(searchTerm, 200)
|
||||
|
||||
@@ -12,7 +10,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
label: user.name,
|
||||
value: String(user.id),
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
}))
|
||||
})) || []
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
@@ -21,7 +19,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<template>
|
||||
<USelectMenu
|
||||
v-model:search-term="searchTerm"
|
||||
:items="users"
|
||||
:items="users || []"
|
||||
:loading="status === 'pending'"
|
||||
ignore-filter
|
||||
icon="i-lucide-user"
|
||||
@@ -32,7 +30,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
<UAvatar
|
||||
v-if="modelValue"
|
||||
v-bind="modelValue.avatar"
|
||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
||||
:size="ui.leadingAvatarSize()"
|
||||
:class="ui.leadingAvatar()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'benjamincanac',
|
||||
@@ -25,16 +23,8 @@ const items = ref([
|
||||
src: 'https://github.com/noook.png',
|
||||
alt: 'noook'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'sandros94',
|
||||
value: 'sandros94',
|
||||
avatar: {
|
||||
src: 'https://github.com/sandros94.png',
|
||||
alt: 'sandros94'
|
||||
}
|
||||
}
|
||||
] satisfies SelectMenuItem[])
|
||||
])
|
||||
const value = ref(items.value[0])
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectMenuItem, ChipProps } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'bug',
|
||||
value: 'bug',
|
||||
chip: {
|
||||
color: 'error'
|
||||
color: 'error' as const
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'feature',
|
||||
value: 'feature',
|
||||
chip: {
|
||||
color: 'success'
|
||||
color: 'success' as const
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'enhancement',
|
||||
value: 'enhancement',
|
||||
chip: {
|
||||
color: 'info'
|
||||
color: 'info' as const
|
||||
}
|
||||
}
|
||||
] satisfies SelectMenuItem[])
|
||||
])
|
||||
const value = ref(items.value[0])
|
||||
</script>
|
||||
|
||||
@@ -35,7 +33,7 @@ const value = ref(items.value[0])
|
||||
v-bind="modelValue.chip"
|
||||
inset
|
||||
standalone
|
||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
||||
:size="ui.itemLeadingChipSize()"
|
||||
:class="ui.itemLeadingChip()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectMenuItem } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'Backlog',
|
||||
@@ -22,7 +20,7 @@ const items = ref([
|
||||
value: 'done',
|
||||
icon: 'i-lucide-circle-check'
|
||||
}
|
||||
] satisfies SelectMenuItem[])
|
||||
])
|
||||
const value = ref(items.value[0])
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { AvatarProps } from '@nuxt/ui'
|
||||
|
||||
const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
|
||||
key: 'typicode-users',
|
||||
transform: (data: { id: number, name: string }[]) => {
|
||||
@@ -8,7 +6,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
|
||||
label: user.name,
|
||||
value: String(user.id),
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
}))
|
||||
})) || []
|
||||
},
|
||||
lazy: true
|
||||
})
|
||||
@@ -20,18 +18,17 @@ function getUserAvatar(value: string) {
|
||||
|
||||
<template>
|
||||
<USelect
|
||||
:items="users"
|
||||
:items="users || []"
|
||||
:loading="status === 'pending'"
|
||||
icon="i-lucide-user"
|
||||
placeholder="Select user"
|
||||
class="w-48"
|
||||
value-key="value"
|
||||
>
|
||||
<template #leading="{ modelValue, ui }">
|
||||
<UAvatar
|
||||
v-if="modelValue"
|
||||
v-bind="getUserAvatar(modelValue)"
|
||||
:size="(ui.leadingAvatarSize() as AvatarProps['size'])"
|
||||
v-bind="getUserAvatar(modelValue as string)"
|
||||
:size="ui.leadingAvatarSize()"
|
||||
:class="ui.leadingAvatar()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectItem } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'benjamincanac',
|
||||
@@ -25,21 +23,13 @@ const items = ref([
|
||||
src: 'https://github.com/noook.png',
|
||||
alt: 'noook'
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'sandros94',
|
||||
value: 'sandros94',
|
||||
avatar: {
|
||||
src: 'https://github.com/sandros94.png',
|
||||
alt: 'sandros94'
|
||||
}
|
||||
}
|
||||
] satisfies SelectItem[])
|
||||
])
|
||||
const value = ref(items.value[0]?.value)
|
||||
|
||||
const avatar = computed(() => items.value.find(item => item.value === value.value)?.avatar)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelect v-model="value" :items="items" value-key="value" :avatar="avatar" class="w-48" />
|
||||
<USelect v-model="value" :avatar="avatar" :items="items" class="w-48" />
|
||||
</template>
|
||||
|
||||
@@ -1,30 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectItem, ChipProps } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'bug',
|
||||
value: 'bug',
|
||||
chip: {
|
||||
color: 'error'
|
||||
color: 'error' as const
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'feature',
|
||||
value: 'feature',
|
||||
chip: {
|
||||
color: 'success'
|
||||
color: 'success' as const
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'enhancement',
|
||||
value: 'enhancement',
|
||||
chip: {
|
||||
color: 'info'
|
||||
color: 'info' as const
|
||||
}
|
||||
}
|
||||
] satisfies SelectItem[])
|
||||
|
||||
])
|
||||
const value = ref(items.value[0]?.value)
|
||||
|
||||
function getChip(value: string) {
|
||||
@@ -33,14 +30,14 @@ function getChip(value: string) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelect v-model="value" :items="items" value-key="value" class="w-48">
|
||||
<USelect v-model="value" :items="items" class="w-48">
|
||||
<template #leading="{ modelValue, ui }">
|
||||
<UChip
|
||||
v-if="modelValue"
|
||||
v-bind="getChip(modelValue)"
|
||||
v-bind="getChip(modelValue as string)"
|
||||
inset
|
||||
standalone
|
||||
:size="(ui.itemLeadingChipSize() as ChipProps['size'])"
|
||||
:size="ui.itemLeadingChipSize()"
|
||||
:class="ui.itemLeadingChip()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectItem } from '@nuxt/ui'
|
||||
|
||||
const items = ref([
|
||||
{
|
||||
label: 'Backlog',
|
||||
@@ -22,12 +20,12 @@ const items = ref([
|
||||
value: 'done',
|
||||
icon: 'i-lucide-circle-check'
|
||||
}
|
||||
] satisfies SelectItem[])
|
||||
])
|
||||
const value = ref(items.value[0]?.value)
|
||||
|
||||
const icon = computed(() => items.value.find(item => item.value === value.value)?.icon)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelect v-model="value" :items="items" value-key="value" :icon="icon" class="w-48" />
|
||||
<USelect v-model="value" :icon="icon" :items="items" class="w-48" />
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { StepperItem } from '@nuxt/ui'
|
||||
|
||||
const items: StepperItem[] = [
|
||||
const items = [
|
||||
{
|
||||
title: 'Address',
|
||||
description: 'Add your address here',
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import type { StepperItem } from '@nuxt/ui'
|
||||
|
||||
const items = [
|
||||
{
|
||||
slot: 'address' as const,
|
||||
slot: 'address',
|
||||
title: 'Address',
|
||||
description: 'Add your address here',
|
||||
icon: 'i-lucide-house'
|
||||
}, {
|
||||
slot: 'shipping' as const,
|
||||
slot: 'shipping',
|
||||
title: 'Shipping',
|
||||
description: 'Set your preferred shipping method',
|
||||
icon: 'i-lucide-truck'
|
||||
}, {
|
||||
slot: 'checkout' as const,
|
||||
slot: 'checkout',
|
||||
title: 'Checkout',
|
||||
description: 'Confirm your order'
|
||||
}
|
||||
] satisfies StepperItem[]
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import type { StepperItem } from '@nuxt/ui'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const items: StepperItem[] = [
|
||||
const items = [
|
||||
{
|
||||
title: 'Address',
|
||||
description: 'Add your address here',
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import type { StepperItem } from '@nuxt/ui'
|
||||
|
||||
const items: StepperItem[] = [
|
||||
const items = [
|
||||
{
|
||||
slot: 'address',
|
||||
title: 'Address',
|
||||
description: 'Add your address here',
|
||||
icon: 'i-lucide-house'
|
||||
}, {
|
||||
slot: 'shipping',
|
||||
title: 'Shipping',
|
||||
description: 'Set your preferred shipping method',
|
||||
icon: 'i-lucide-truck'
|
||||
}, {
|
||||
slot: 'checkout',
|
||||
title: 'Checkout',
|
||||
description: 'Confirm your order'
|
||||
}
|
||||
|
||||
@@ -97,11 +97,10 @@ function getHeader(column: Column<Payment>, label: string) {
|
||||
const isSorted = column.getIsSorted()
|
||||
|
||||
return h(UDropdownMenu, {
|
||||
'content': {
|
||||
content: {
|
||||
align: 'start'
|
||||
},
|
||||
'aria-label': 'Actions dropdown',
|
||||
'items': [{
|
||||
items: [{
|
||||
label: 'Asc',
|
||||
type: 'checkbox',
|
||||
icon: 'i-lucide-arrow-up-narrow-wide',
|
||||
@@ -127,12 +126,11 @@ function getHeader(column: Column<Payment>, label: string) {
|
||||
}
|
||||
}]
|
||||
}, () => h(UButton, {
|
||||
'color': 'neutral',
|
||||
'variant': 'ghost',
|
||||
color: 'neutral',
|
||||
variant: 'ghost',
|
||||
label,
|
||||
'icon': isSorted ? (isSorted === 'asc' ? 'i-lucide-arrow-up-narrow-wide' : 'i-lucide-arrow-down-wide-narrow') : 'i-lucide-arrow-up-down',
|
||||
'class': '-mx-2.5 data-[state=open]:bg-(--ui-bg-elevated)',
|
||||
'aria-label': `Sort by ${isSorted === 'asc' ? 'descending' : 'ascending'}`
|
||||
icon: isSorted ? (isSorted === 'asc' ? 'i-lucide-arrow-up-narrow-wide' : 'i-lucide-arrow-down-wide-narrow') : 'i-lucide-arrow-up-down',
|
||||
class: '-mx-2.5 data-[state=open]:bg-(--ui-bg-elevated)'
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -145,12 +145,12 @@ const columns: TableColumn<Payment>[] = [{
|
||||
header: ({ table }) => h(UCheckbox, {
|
||||
'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(),
|
||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value),
|
||||
'aria-label': 'Select all'
|
||||
'ariaLabel': 'Select all'
|
||||
}),
|
||||
cell: ({ row }) => h(UCheckbox, {
|
||||
'modelValue': row.getIsSelected(),
|
||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
|
||||
'aria-label': 'Select row'
|
||||
'ariaLabel': 'Select row'
|
||||
}),
|
||||
enableSorting: false,
|
||||
enableHiding: false
|
||||
@@ -242,17 +242,15 @@ const columns: TableColumn<Payment>[] = [{
|
||||
}]
|
||||
|
||||
return h('div', { class: 'text-right' }, h(UDropdownMenu, {
|
||||
'content': {
|
||||
content: {
|
||||
align: 'end'
|
||||
},
|
||||
items,
|
||||
'aria-label': 'Actions dropdown'
|
||||
items
|
||||
}, () => h(UButton, {
|
||||
'icon': 'i-lucide-ellipsis-vertical',
|
||||
'color': 'neutral',
|
||||
'variant': 'ghost',
|
||||
'class': 'ml-auto',
|
||||
'aria-label': 'Actions dropdown'
|
||||
icon: 'i-lucide-ellipsis-vertical',
|
||||
color: 'neutral',
|
||||
variant: 'ghost',
|
||||
class: 'ml-auto'
|
||||
})))
|
||||
}
|
||||
}]
|
||||
@@ -296,7 +294,6 @@ function randomize() {
|
||||
variant="outline"
|
||||
trailing-icon="i-lucide-chevron-down"
|
||||
class="ml-auto"
|
||||
aria-label="Columns select dropdown"
|
||||
/>
|
||||
</UDropdownMenu>
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,7 @@ const { data, status } = await useFetch<User[]>('https://jsonplaceholder.typicod
|
||||
transform: (data) => {
|
||||
return data?.map(user => ({
|
||||
...user,
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, alt: `${user.name} avatar` }
|
||||
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
|
||||
})) || []
|
||||
},
|
||||
lazy: true
|
||||
|
||||
@@ -97,17 +97,15 @@ const columns: TableColumn<Payment>[] = [{
|
||||
id: 'actions',
|
||||
cell: ({ row }) => {
|
||||
return h('div', { class: 'text-right' }, h(UDropdownMenu, {
|
||||
'content': {
|
||||
content: {
|
||||
align: 'end'
|
||||
},
|
||||
'items': getRowItems(row),
|
||||
'aria-label': 'Actions dropdown'
|
||||
items: getRowItems(row)
|
||||
}, () => h(UButton, {
|
||||
'icon': 'i-lucide-ellipsis-vertical',
|
||||
'color': 'neutral',
|
||||
'variant': 'ghost',
|
||||
'class': 'ml-auto',
|
||||
'aria-label': 'Actions dropdown'
|
||||
icon: 'i-lucide-ellipsis-vertical',
|
||||
color: 'neutral',
|
||||
variant: 'ghost',
|
||||
class: 'ml-auto'
|
||||
})))
|
||||
}
|
||||
}]
|
||||
|
||||
@@ -48,15 +48,14 @@ const data = ref<Payment[]>([{
|
||||
const columns: TableColumn<Payment>[] = [{
|
||||
id: 'expand',
|
||||
cell: ({ row }) => h(UButton, {
|
||||
'color': 'neutral',
|
||||
'variant': 'ghost',
|
||||
'icon': 'i-lucide-chevron-down',
|
||||
'square': true,
|
||||
'aria-label': 'Expand',
|
||||
'ui': {
|
||||
color: 'neutral',
|
||||
variant: 'ghost',
|
||||
icon: 'i-lucide-chevron-down',
|
||||
square: true,
|
||||
ui: {
|
||||
leadingIcon: ['transition-transform', row.getIsExpanded() ? 'duration-200 rotate-180' : '']
|
||||
},
|
||||
'onClick': () => row.toggleExpanded()
|
||||
onClick: () => row.toggleExpanded()
|
||||
})
|
||||
}, {
|
||||
accessorKey: 'id',
|
||||
|
||||
@@ -50,12 +50,12 @@ const columns: TableColumn<Payment>[] = [{
|
||||
header: ({ table }) => h(UCheckbox, {
|
||||
'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(),
|
||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value),
|
||||
'aria-label': 'Select all'
|
||||
'ariaLabel': 'Select all'
|
||||
}),
|
||||
cell: ({ row }) => h(UCheckbox, {
|
||||
'modelValue': row.getIsSelected(),
|
||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
|
||||
'aria-label': 'Select row'
|
||||
'ariaLabel': 'Select row'
|
||||
})
|
||||
}, {
|
||||
accessorKey: 'date',
|
||||
|
||||
@@ -50,12 +50,12 @@ const columns: TableColumn<Payment>[] = [{
|
||||
header: ({ table }) => h(UCheckbox, {
|
||||
'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(),
|
||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value),
|
||||
'aria-label': 'Select all'
|
||||
'ariaLabel': 'Select all'
|
||||
}),
|
||||
cell: ({ row }) => h(UCheckbox, {
|
||||
'modelValue': row.getIsSelected(),
|
||||
'onUpdate:modelValue': (value: boolean | 'indeterminate') => row.toggleSelected(!!value),
|
||||
'aria-label': 'Select row'
|
||||
'ariaLabel': 'Select row'
|
||||
})
|
||||
}, {
|
||||
accessorKey: 'date',
|
||||
|
||||
@@ -95,7 +95,7 @@ function getDropdownActions(user: User): DropdownMenuItem[][] {
|
||||
<UTable :data="data" :columns="columns" class="flex-1">
|
||||
<template #name-cell="{ row }">
|
||||
<div class="flex items-center gap-3">
|
||||
<UAvatar :src="`https://i.pravatar.cc/120?img=${row.original.id}`" size="lg" :alt="`${row.original.name} avatar`" />
|
||||
<UAvatar :src="`https://i.pravatar.cc/120?img=${row.original.id}`" size="lg" />
|
||||
<div>
|
||||
<p class="font-medium text-(--ui-text-highlighted)">
|
||||
{{ row.original.name }}
|
||||
@@ -108,7 +108,7 @@ function getDropdownActions(user: User): DropdownMenuItem[][] {
|
||||
</template>
|
||||
<template #action-cell="{ row }">
|
||||
<UDropdownMenu :items="getDropdownActions(row.original)">
|
||||
<UButton icon="i-lucide-ellipsis-vertical" color="neutral" variant="ghost" aria-label="Actions" />
|
||||
<UButton icon="i-lucide-ellipsis-vertical" color="neutral" variant="ghost" />
|
||||
</UDropdownMenu>
|
||||
</template>
|
||||
</UTable>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { TabsItem } from '@nuxt/ui'
|
||||
|
||||
const items: TabsItem[] = [
|
||||
const items = [
|
||||
{
|
||||
label: 'Account',
|
||||
icon: 'i-lucide-user'
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import type { TabsItem } from '@nuxt/ui'
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: 'Account',
|
||||
description: 'Make changes to your account here. Click save when you\'re done.',
|
||||
icon: 'i-lucide-user',
|
||||
slot: 'account' as const
|
||||
slot: 'account'
|
||||
},
|
||||
{
|
||||
label: 'Password',
|
||||
description: 'Change your password here. After saving, you\'ll be logged out.',
|
||||
icon: 'i-lucide-lock',
|
||||
slot: 'password' as const
|
||||
slot: 'password'
|
||||
}
|
||||
] satisfies TabsItem[]
|
||||
]
|
||||
|
||||
const state = reactive({
|
||||
name: 'Benjamin Canac',
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { TabsItem } from '@nuxt/ui'
|
||||
|
||||
const items: TabsItem[] = [
|
||||
const items = [
|
||||
{
|
||||
label: 'Account'
|
||||
},
|
||||
|
||||
@@ -1,32 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
import type { TreeItem } from '@nuxt/ui'
|
||||
|
||||
const items = [
|
||||
const items: TreeItem[] = [
|
||||
{
|
||||
label: 'app/',
|
||||
slot: 'app' as const,
|
||||
slot: 'app',
|
||||
defaultExpanded: true,
|
||||
children: [
|
||||
{
|
||||
label: 'composables/',
|
||||
children: [
|
||||
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
|
||||
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'components/',
|
||||
defaultExpanded: true,
|
||||
children: [
|
||||
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
|
||||
]
|
||||
}
|
||||
]
|
||||
children: [{
|
||||
label: 'composables/',
|
||||
children: [
|
||||
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
|
||||
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'components/',
|
||||
defaultExpanded: true,
|
||||
children: [
|
||||
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
|
||||
]
|
||||
}]
|
||||
},
|
||||
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
||||
] satisfies TreeItem[]
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -5,24 +5,22 @@ const items: TreeItem[] = [
|
||||
{
|
||||
label: 'app/',
|
||||
value: 'app',
|
||||
children: [
|
||||
{
|
||||
label: 'composables/',
|
||||
value: 'composables',
|
||||
children: [
|
||||
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
|
||||
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'components/',
|
||||
value: 'components',
|
||||
children: [
|
||||
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
|
||||
]
|
||||
}
|
||||
]
|
||||
children: [{
|
||||
label: 'composables/',
|
||||
value: 'composables',
|
||||
children: [
|
||||
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
|
||||
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'components/',
|
||||
value: 'components',
|
||||
children: [
|
||||
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
|
||||
]
|
||||
}]
|
||||
},
|
||||
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
||||
|
||||
@@ -5,29 +5,27 @@ const items: TreeItem[] = [
|
||||
{
|
||||
label: 'app/',
|
||||
defaultExpanded: true,
|
||||
children: [
|
||||
{
|
||||
label: 'composables/',
|
||||
children: [
|
||||
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
|
||||
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'components/',
|
||||
defaultExpanded: true,
|
||||
children: [
|
||||
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
|
||||
]
|
||||
}
|
||||
]
|
||||
children: [{
|
||||
label: 'composables/',
|
||||
children: [
|
||||
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
|
||||
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'components/',
|
||||
defaultExpanded: true,
|
||||
children: [
|
||||
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
|
||||
]
|
||||
}]
|
||||
},
|
||||
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
||||
]
|
||||
|
||||
const value = ref()
|
||||
const value = ref(items[items.length - 1])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -8,23 +8,21 @@ const items: TreeItem[] = [
|
||||
onSelect: (e: Event) => {
|
||||
e.preventDefault()
|
||||
},
|
||||
children: [
|
||||
{
|
||||
label: 'composables/',
|
||||
children: [
|
||||
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
|
||||
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'components/',
|
||||
defaultExpanded: true,
|
||||
children: [
|
||||
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
|
||||
]
|
||||
}
|
||||
]
|
||||
children: [{
|
||||
label: 'composables/',
|
||||
children: [
|
||||
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
|
||||
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'components/',
|
||||
defaultExpanded: true,
|
||||
children: [
|
||||
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
|
||||
]
|
||||
}]
|
||||
},
|
||||
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
||||
|
||||
@@ -8,23 +8,21 @@ const items: TreeItem[] = [
|
||||
onToggle: (e: Event) => {
|
||||
e.preventDefault()
|
||||
},
|
||||
children: [
|
||||
{
|
||||
label: 'composables/',
|
||||
children: [
|
||||
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
|
||||
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'components/',
|
||||
defaultExpanded: true,
|
||||
children: [
|
||||
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
|
||||
]
|
||||
}
|
||||
]
|
||||
children: [{
|
||||
label: 'composables/',
|
||||
children: [
|
||||
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
|
||||
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'components/',
|
||||
defaultExpanded: true,
|
||||
children: [
|
||||
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
|
||||
]
|
||||
}]
|
||||
},
|
||||
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
|
||||
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
|
||||
|
||||
@@ -3,7 +3,7 @@ withDefaults(defineProps<{
|
||||
title: string
|
||||
description: string
|
||||
component: string
|
||||
module?: string
|
||||
module: string
|
||||
}>(), {
|
||||
module: ''
|
||||
})
|
||||
|
||||
@@ -3,8 +3,8 @@ withDefaults(defineProps<{
|
||||
title: string
|
||||
description: string
|
||||
headline: string
|
||||
framework?: string
|
||||
module?: string
|
||||
framework: string
|
||||
module: string
|
||||
}>(), {
|
||||
framework: 'nuxt',
|
||||
module: ''
|
||||
|
||||
@@ -81,6 +81,7 @@ function setBlackAsPrimary(value: boolean) {
|
||||
|
||||
<div class="grid grid-cols-3 gap-1 -mx-2">
|
||||
<ThemePickerButton
|
||||
chip="primary"
|
||||
label="Black"
|
||||
:selected="appConfig.theme.blackAsPrimary"
|
||||
@click="setBlackAsPrimary(true)"
|
||||
@@ -89,7 +90,6 @@ function setBlackAsPrimary(value: boolean) {
|
||||
<span class="inline-block w-2 h-2 rounded-full bg-black dark:bg-white" />
|
||||
</template>
|
||||
</ThemePickerButton>
|
||||
|
||||
<ThemePickerButton
|
||||
v-for="color in primaryColors"
|
||||
:key="color"
|
||||
@@ -111,7 +111,7 @@ function setBlackAsPrimary(value: boolean) {
|
||||
v-for="color in neutralColors"
|
||||
:key="color"
|
||||
:label="color"
|
||||
:chip="color === 'neutral' ? 'old-neutral' : color"
|
||||
:chip="color"
|
||||
:selected="neutral === color"
|
||||
@click="neutral = color"
|
||||
/>
|
||||
|
||||
@@ -5,10 +5,6 @@ defineProps<{
|
||||
chip?: string
|
||||
selected?: boolean
|
||||
}>()
|
||||
|
||||
const slots = defineSlots<{
|
||||
leading: () => any
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -21,7 +17,7 @@ const slots = defineSlots<{
|
||||
class="capitalize ring-(--ui-border) rounded-[calc(var(--ui-radius))] text-[11px]"
|
||||
:class="[selected ? 'bg-(--ui-bg-elevated)' : 'hover:bg-(--ui-bg-elevated)/50']"
|
||||
>
|
||||
<template v-if="chip || !!slots.leading" #leading>
|
||||
<template v-if="chip" #leading>
|
||||
<slot name="leading">
|
||||
<span
|
||||
class="inline-block size-2 rounded-full"
|
||||
|
||||
@@ -84,10 +84,10 @@ export function useLinks() {
|
||||
label: 'Community',
|
||||
icon: 'i-lucide-users',
|
||||
children: [{
|
||||
icon: 'i-lucide-presentation',
|
||||
label: 'Showcase',
|
||||
description: 'Check out some amazing projects built with Nuxt UI.',
|
||||
to: '/showcase'
|
||||
label: 'Roadmap',
|
||||
description: 'Track our development progress in real-time.',
|
||||
icon: 'i-lucide-map',
|
||||
to: '/roadmap'
|
||||
}, {
|
||||
label: 'Devtools Integration',
|
||||
description: 'Integrate Nuxt UI with Nuxt Devtools with Compodium.',
|
||||
@@ -112,5 +112,5 @@ export function useLinks() {
|
||||
icon: 'i-lucide-rocket',
|
||||
to: 'https://github.com/nuxt/ui/releases',
|
||||
target: '_blank'
|
||||
}])
|
||||
}].filter(Boolean))
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
export function useSearchLinks() {
|
||||
return [{
|
||||
label: 'Docs',
|
||||
icon: 'i-lucide-square-play',
|
||||
to: '/getting-started'
|
||||
}, {
|
||||
label: 'Components',
|
||||
icon: 'i-lucide-square-code',
|
||||
to: '/components'
|
||||
}, {
|
||||
icon: 'i-lucide-sparkles',
|
||||
label: 'Pro > Features',
|
||||
description: 'A collection of premium Vue components.',
|
||||
to: '/pro'
|
||||
}, {
|
||||
icon: 'i-lucide-credit-card',
|
||||
label: 'Pro > Pricing',
|
||||
description: 'Free in development, buy when ready to launch.',
|
||||
to: '/pro/pricing'
|
||||
}, {
|
||||
icon: 'i-lucide-panels-top-left',
|
||||
label: 'Pro > Templates',
|
||||
description: 'Official templates made with Nuxt UI Pro.',
|
||||
to: '/pro/templates'
|
||||
}, {
|
||||
icon: 'i-lucide-circle-check',
|
||||
label: 'Pro > Activate',
|
||||
description: 'Enable Nuxt UI Pro in your production projects.',
|
||||
to: '/pro/activate'
|
||||
}, {
|
||||
label: 'Figma',
|
||||
icon: 'i-simple-icons-figma',
|
||||
to: '/figma'
|
||||
}, {
|
||||
icon: 'i-lucide-presentation',
|
||||
label: 'Community > Showcase',
|
||||
description: 'Check out some of the amazing projects built with Nuxt UI.',
|
||||
to: '/showcase'
|
||||
}, {
|
||||
label: 'Community > Contribution',
|
||||
description: 'A comprehensive guide on contributing to Nuxt UI, including project structure, development workflow, and best practices.',
|
||||
icon: 'i-lucide-git-pull-request-arrow',
|
||||
to: '/getting-started/contribution'
|
||||
}, {
|
||||
label: 'Community > Roadmap',
|
||||
description: 'Track our development progress in real-time.',
|
||||
icon: 'i-lucide-map',
|
||||
to: '/roadmap'
|
||||
}, {
|
||||
label: 'Community > Devtools',
|
||||
description: 'Integrate Nuxt UI with Nuxt Devtools with Compodium.',
|
||||
icon: 'i-lucide-code',
|
||||
to: 'https://github.com/romhml/compodium',
|
||||
target: '_blank'
|
||||
}, {
|
||||
label: 'Community > Team',
|
||||
description: 'Meet the team behind Nuxt UI.',
|
||||
icon: 'i-lucide-users',
|
||||
to: '/team'
|
||||
}, {
|
||||
label: 'Releases',
|
||||
icon: 'i-lucide-rocket',
|
||||
to: 'https://github.com/nuxt/ui/releases',
|
||||
target: '_blank'
|
||||
}]
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import colors from 'tailwindcss/colors'
|
||||
// import { debounce } from 'perfect-debounce'
|
||||
import type { NuxtError } from '#app'
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -14,8 +15,17 @@ const { data: files } = useLazyAsyncData('search', () => queryCollectionSearchSe
|
||||
server: false
|
||||
})
|
||||
|
||||
const searchTerm = ref('')
|
||||
|
||||
// watch(searchTerm, debounce((query: string) => {
|
||||
// if (!query) {
|
||||
// return
|
||||
// }
|
||||
|
||||
// useTrackEvent('Search', { props: { query: `${query} - ${searchTerm.value?.commandPaletteRef.results.length} results` } })
|
||||
// }, 500))
|
||||
|
||||
const links = useLinks()
|
||||
const searchLinks = useSearchLinks()
|
||||
const color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white')
|
||||
const radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
|
||||
const blackAsPrimary = computed(() => appConfig.theme.blackAsPrimary ? `:root { --ui-primary: black; } .dark { --ui-primary: white; }` : ':root {}')
|
||||
@@ -38,7 +48,7 @@ useHead({
|
||||
})
|
||||
|
||||
useSeoMeta({
|
||||
titleTemplate: '%s - Nuxt UI',
|
||||
titleTemplate: '%s - Nuxt UI v3',
|
||||
title: String(props.error.statusCode)
|
||||
})
|
||||
|
||||
@@ -57,17 +67,17 @@ provide('navigation', mappedNavigation)
|
||||
<UApp>
|
||||
<NuxtLoadingIndicator color="#FFF" />
|
||||
|
||||
<Banner />
|
||||
<!-- <Banner /> -->
|
||||
|
||||
<Header :links="links" />
|
||||
|
||||
<UError :error="error" />
|
||||
|
||||
<Footer />
|
||||
<!-- <Footer /> -->
|
||||
|
||||
<ClientOnly>
|
||||
<LazyUContentSearch
|
||||
:links="searchLinks"
|
||||
v-model:search-term="searchTerm"
|
||||
:files="files"
|
||||
:groups="[{
|
||||
id: 'framework',
|
||||
|
||||
@@ -97,7 +97,7 @@ design_system:
|
||||
```
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "tailwindcss" theme(static);
|
||||
@import "@nuxt/ui";
|
||||
|
||||
:root {
|
||||
@@ -176,11 +176,7 @@ community:
|
||||
links:
|
||||
- label: Star on GitHub
|
||||
color: neutral
|
||||
variant: outline
|
||||
to: https://github.com/nuxt/ui
|
||||
target: _blank
|
||||
icon: i-lucide-star
|
||||
- label: Meet the team
|
||||
color: neutral
|
||||
variant: outline
|
||||
to: /team
|
||||
trailingIcon: i-lucide-arrow-right
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user