Merge remote-tracking branch 'upstream' into feat/cli/overwrite-existing
This commit is contained in:
commit
b08cc50bf8
|
|
@ -11,5 +11,6 @@ module.exports = {
|
|||
'symbol-description': 'off',
|
||||
'no-console': 'warn',
|
||||
'no-tabs': 'off',
|
||||
'no-invalid-character': 'off',
|
||||
},
|
||||
}
|
||||
|
|
|
|||
72
.github/workflows/publish.yaml
vendored
Normal file
72
.github/workflows/publish.yaml
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
name: Publish www
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- 'apps/www/**'
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- 'apps/www/**'
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
deployments: write
|
||||
name: Publish to Cloudflare Pages
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Run a build step here
|
||||
- name: Setup Node.js environment
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 8
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ env.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm i --frozen-lockfile
|
||||
|
||||
- name: Build www
|
||||
run: pnpm build
|
||||
|
||||
# Run a action to publish docs
|
||||
- name: Publish to Cloudflare Pages
|
||||
uses: cloudflare/pages-action@v1.5.0
|
||||
with:
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
projectName: shadcn-vue
|
||||
directory: .vitepress/dist
|
||||
# Optional: Enable this if you want to have GitHub Deployments triggered
|
||||
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Optional: Switch what branch you are publishing to.
|
||||
# By default this will be the branch which triggered this workflow
|
||||
# branch: main
|
||||
# Optional: Change the working directory
|
||||
workingDirectory: apps/www
|
||||
wranglerVersion: '3'
|
||||
52
.github/workflows/test.yaml
vendored
Normal file
52
.github/workflows/test.yaml
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- 'packages/**'
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- 'packages/**'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Node.js environment
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 8
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ env.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm i --frozen-lockfile
|
||||
|
||||
- name: Test
|
||||
run: pnpm test
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -7,6 +7,7 @@ yarn-error.log*
|
|||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
.nuxt
|
||||
.env
|
||||
node_modules
|
||||
.DS_Store
|
||||
|
|
|
|||
158
CONTRIBUTING.md
Normal file
158
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
# Contributing
|
||||
|
||||
Thanks for your interest in contributing to shadcn-vue.com. We're happy to have you here.
|
||||
|
||||
Please take a moment to review this document before submitting your first pull request. We also strongly recommend that you check for open issues and pull requests to see if someone else is working on something similar.
|
||||
|
||||
If you need any help, feel free to reach out to the core team on [Discord](https://chat.radix-vue.com/).
|
||||
|
||||
## About this repository
|
||||
|
||||
This repository is a monorepo.
|
||||
|
||||
- We use [pnpm](https://pnpm.io) and [`workspaces`](https://pnpm.io/workspaces) for development.
|
||||
|
||||
## Structure
|
||||
|
||||
This repository is structured as follows:
|
||||
|
||||
```
|
||||
apps
|
||||
└── www
|
||||
├── src
|
||||
│ └── content
|
||||
└── registry
|
||||
├── default
|
||||
│ ├── example
|
||||
│ └── ui
|
||||
└── new-york
|
||||
├── example
|
||||
└── ui
|
||||
packages
|
||||
└── cli
|
||||
```
|
||||
|
||||
| Path | Description |
|
||||
| --------------------- | ---------------------------------------- |
|
||||
| `apps/www/app` | The Next.js application for the website. |
|
||||
| `apps/www/content` | The content for the website. |
|
||||
| `apps/www/registry` | The registry for the components. |
|
||||
| `packages/cli` | The `shadcn-vue` package. |
|
||||
|
||||
## Development
|
||||
|
||||
### Start by cloning the repository:
|
||||
|
||||
```
|
||||
git clone git@github.com:radix-vue/shadcn-vue.git
|
||||
```
|
||||
|
||||
### Install dependencies
|
||||
|
||||
```
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### Run a workspace
|
||||
|
||||
You can use the `pnpm --filter=[WORKSPACE]` command to start the development process for a workspace or some of the shortcut command that we have setup.
|
||||
|
||||
#### Examples
|
||||
|
||||
1. To run the `shadcn-vue.com` website:
|
||||
|
||||
```
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
2. To run the `shadcn-vue` cli package:
|
||||
|
||||
```
|
||||
pnpm dev:cli
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
The documentation for this project is located in the `www` workspace. You can run the documentation locally by running the following command:
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
Documentation is written using [md](https://vitepress.dev/guide/markdown). You can find the documentation files in the `apps/www/content/docs` directory.
|
||||
|
||||
## Components
|
||||
|
||||
We use a registry system for developing components. You can find the source code for the components under `apps/www/registry`. The components are organized by styles.
|
||||
|
||||
```bash
|
||||
apps
|
||||
└── www
|
||||
└── registry
|
||||
├── default
|
||||
│ ├── example
|
||||
│ └── ui
|
||||
└── new-york
|
||||
├── example
|
||||
└── ui
|
||||
```
|
||||
|
||||
When adding or modifying components, please ensure that:
|
||||
|
||||
1. You make the changes for every style.
|
||||
2. You update the documentation.
|
||||
3. You run `pnpm build:registry` to update the registry.
|
||||
|
||||
## Commit Convention
|
||||
|
||||
Before you create a Pull Request, please check whether your commits comply with
|
||||
the commit conventions used in this repository.
|
||||
|
||||
When you create a commit we kindly ask you to follow the convention
|
||||
`category(scope or module): message` in your commit message while using one of
|
||||
the following categories:
|
||||
|
||||
- `feat / feature`: all changes that introduce completely new code or new
|
||||
features
|
||||
- `fix`: changes that fix a bug (ideally you will additionally reference an
|
||||
issue if present)
|
||||
- `refactor`: any code related change that is not a fix nor a feature
|
||||
- `docs`: changing existing or creating new documentation (i.e. README, docs for
|
||||
usage of a lib or cli usage)
|
||||
- `build`: all changes regarding the build of the software, changes to
|
||||
dependencies or the addition of new dependencies
|
||||
- `test`: all changes regarding tests (adding new tests or changing existing
|
||||
ones)
|
||||
- `ci`: all changes regarding the configuration of continuous integration (i.e.
|
||||
github actions, ci system)
|
||||
- `chore`: all changes to the repository that do not fit into any of the above
|
||||
categories
|
||||
|
||||
e.g. `feat(components): add new prop to the avatar component`
|
||||
|
||||
|
||||
If you are interested in the detailed specification you can visit
|
||||
https://www.conventionalcommits.org/ or check out the
|
||||
[Angular Commit Message Guidelines](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines).
|
||||
|
||||
|
||||
|
||||
## Requests for new components
|
||||
|
||||
If you have a request for a new component, please open a discussion on GitHub. We'll be happy to help you out.
|
||||
|
||||
## CLI
|
||||
|
||||
The `shadcn-vue` package is a CLI for adding components to your project. You can find the documentation for the CLI [here](https://shadcn-vue.com/docs/cli).
|
||||
|
||||
Any changes to the CLI should be made in the `packages/cli` directory. If you can, it would be great if you could add tests for your changes.
|
||||
|
||||
## Testing
|
||||
|
||||
Tests are written using [Vitest](https://vitest.dev). You can run all the tests from the root of the repository.
|
||||
|
||||
```bash
|
||||
pnpm test
|
||||
```
|
||||
|
||||
Please ensure that the tests are passing when submitting a pull request. If you're adding new features, please include tests.
|
||||
10
README.md
10
README.md
|
|
@ -15,19 +15,19 @@ Accessible and customizable components that you can copy and paste into your app
|
|||
|
||||
## Documentation
|
||||
|
||||
Visit https://shadcn-vue.com/docs to view the documentation.
|
||||
[View documentation here](https://www.shadcn-vue.com/docs/introduction.html)
|
||||
|
||||
## Credits
|
||||
|
||||
All credits go to these open-source works and resources
|
||||
|
||||
- [Shadnc UI](https://ui.shadcn.com) for creating this beautiful project
|
||||
- [Shadnc Svelte](https://shadcn-svelte.com) for some inspiration for registry
|
||||
- [Radix Vue](https://radix-vue.com) for doing all the hard work to make sure components are accessible
|
||||
- [Shadcn UI](https://ui.shadcn.com) for creating this beautiful project.
|
||||
- [Shadcn Svelte](https://shadcn-svelte.com) for some inspiration for registry.
|
||||
- [Radix Vue](https://radix-vue.com) for doing all the hard work to make sure components are accessible.
|
||||
- [VueUse](https://vueuse.org) for providing many useful utilities.
|
||||
|
||||
- [ahmedmayara](https://github.com/ahmedmayara/shadcn-vue) for populating many components
|
||||
|
||||
## License
|
||||
|
||||
Licensed under the [MIT license](https://github.com/shadcn/ui/blob/main/LICENSE.md).
|
||||
Licensed under the [MIT license](https://github.com/shadcn/ui/blob/main/LICENSE.md).
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import path from 'node:path'
|
||||
import { defineConfig } from 'vitepress'
|
||||
import Icons from 'unplugin-icons/vite'
|
||||
import tailwind from 'tailwindcss'
|
||||
import autoprefixer from 'autoprefixer'
|
||||
import { siteConfig } from './theme/config/site'
|
||||
import ComponentPreviewPlugin from './theme/plugins/previewer'
|
||||
|
||||
|
|
@ -54,8 +56,16 @@ export default defineConfig({
|
|||
'content/(.*)': '(.*)',
|
||||
},
|
||||
vite: {
|
||||
css: {
|
||||
postcss: {
|
||||
plugins: [
|
||||
tailwind(),
|
||||
autoprefixer(),
|
||||
],
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
Icons({ compiler: 'vue3', autoInstall: true }) as any,
|
||||
Icons({ compiler: 'vue3', autoInstall: true }),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ const { style } = useConfigStore()
|
|||
<StyleSwitcher />
|
||||
</div>
|
||||
<div
|
||||
:class="cn('preview flex min-h-[350px] w-full justify-center p-10', {
|
||||
:class="cn('preview flex min-h-[350px] w-full justify-center p-6 lg:p-10', {
|
||||
'items-center': align === 'center',
|
||||
'items-start': align === 'start',
|
||||
'items-end': align === 'end',
|
||||
|
|
|
|||
60
apps/www/.vitepress/theme/components/CustomizerCode.vue
Normal file
60
apps/www/.vitepress/theme/components/CustomizerCode.vue
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { useConfigStore } from '@/stores/config'
|
||||
import { themes } from '@/lib/registry'
|
||||
import { Button } from '@/lib/registry/new-york/ui/button'
|
||||
import CheckIcon from '~icons/radix-icons/check'
|
||||
import CopyIcon from '~icons/radix-icons/copy'
|
||||
|
||||
const { theme, config } = useConfigStore()
|
||||
|
||||
const activeTheme = computed(() => themes.find(i => i.name === theme.value))
|
||||
|
||||
const { copy, copied } = useClipboard()
|
||||
|
||||
const codeRef = ref<HTMLElement>()
|
||||
async function copyCode() {
|
||||
await copy(codeRef.value?.innerText ?? '')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative">
|
||||
<pre class="max-h-[450px] overflow-x-auto rounded-lg border bg-zinc-950 !py-0 dark:bg-zinc-900">
|
||||
<code ref="codeRef" class="relative block rounded font-mono text-sm">
|
||||
<span class="line">@layer base {</span>
|
||||
<span class="line">:root {</span>
|
||||
<span class="line"> --background: {{ activeTheme?.cssVars.light.background }};</span>
|
||||
<span class="line"> --foreground: {{ activeTheme?.cssVars.light.foreground }};</span>
|
||||
<template v-for="prefix in (['card', 'popover', 'primary', 'secondary', 'muted', 'accent', 'destructive'] as const)" :key="prefix">
|
||||
<span class="line">--{{ prefix }}: {{ activeTheme?.cssVars.light[prefix] }};</span>
|
||||
<span class="line">--{{ prefix }}-foreground: {{ activeTheme?.cssVars.light[ `${prefix}-foreground`] }};</span>
|
||||
</template>
|
||||
<span class="line"> --border:{{ activeTheme?.cssVars.light.border }};</span>
|
||||
<span class="line"> --input:{{ activeTheme?.cssVars.light.input }};</span>
|
||||
<span class="line"> --ring:{{ activeTheme?.cssVars.light.ring }};</span>
|
||||
<span class="line"> --radius: {{ config.radius }}rem;</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line"> </span>
|
||||
<span class="line">.dark {</span>
|
||||
<span class="line"> --background:{{ activeTheme?.cssVars.dark.background }};</span>
|
||||
<span class="line"> --foreground:{{ activeTheme?.cssVars.dark.foreground }};</span>
|
||||
<template v-for="prefix in (['card', 'popover', 'primary', 'secondary', 'muted', 'accent', 'destructive'] as const)" :key="prefix">
|
||||
<span class="line">--{{ prefix }}:{{ activeTheme?.cssVars.dark[ prefix] }};</span>
|
||||
<span class="line">--{{ prefix }}-foreground:{{ activeTheme?.cssVars.dark[ `${prefix}-foreground`] }};</span>
|
||||
</template>
|
||||
<span class="line"> --border:{{ activeTheme?.cssVars.dark.border }};</span>
|
||||
<span class="line"> --input:{{ activeTheme?.cssVars.dark.input }};</span>
|
||||
<span class="line"> --ring:{{ activeTheme?.cssVars.dark.ring }};</span>
|
||||
<span class="line">}</span>
|
||||
<span class="line">}</span>
|
||||
</code>
|
||||
</pre>
|
||||
<Button size="sm" class="absolute right-4 top-4 bg-muted text-muted-foreground hover:bg-muted hover:text-muted-foreground" @click="copyCode">
|
||||
<CheckIcon v-if="copied" class="mr-2 h-4 w-4" />
|
||||
<CopyIcon v-else class="mr-2 h-4 w-4" />
|
||||
{{ copied ? 'Copied' : 'Copy' }}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -30,7 +30,7 @@ const examples = [
|
|||
},
|
||||
{
|
||||
name: 'Forms',
|
||||
href: '/examples/forms',
|
||||
href: '/examples/forms/forms',
|
||||
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/forms',
|
||||
},
|
||||
{
|
||||
|
|
|
|||
37
apps/www/.vitepress/theme/components/Kbd.vue
Normal file
37
apps/www/.vitepress/theme/components/Kbd.vue
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<script setup lang="ts">
|
||||
import { cva } from 'class-variance-authority'
|
||||
import { computed } from 'vue'
|
||||
|
||||
interface KbdProps {
|
||||
as?: string
|
||||
size?: 'xs' | 'sm' | 'md'
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<KbdProps>(), {
|
||||
as: 'kbd',
|
||||
size: 'sm',
|
||||
})
|
||||
|
||||
const kbdClass = computed(() => {
|
||||
return cva(
|
||||
'inline-flex items-center pointer-events-none h-5 select-none items-center gap-1 rounded border border-border bg-muted font-sans font-medium',
|
||||
{
|
||||
variants: {
|
||||
size: {
|
||||
xs: 'min-h-[16px] text-[10px] h-4 px-1',
|
||||
sm: 'min-h-[20px] text-[11px] h-5 px-1',
|
||||
md: 'min-h-[24px] text-[12px] h-6 px-1.5',
|
||||
},
|
||||
},
|
||||
},
|
||||
)({
|
||||
size: props.size,
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component :is="props.as" :class="kbdClass">
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
|
|
@ -19,12 +19,11 @@ import DashboardExample from '@/examples/dashboard/Example.vue'
|
|||
href="/docs/changelog"
|
||||
class="inline-flex items-center rounded-lg bg-muted px-3 py-1 text-sm font-medium"
|
||||
>
|
||||
🎉 <Separator class="mx-2 h-4" orientation="vertical" />
|
||||
<span class="sm:hidden">Style, a new CLI and more.</span>
|
||||
<span class="hidden sm:inline">
|
||||
Introducing Style, a new CLI and more.
|
||||
🚧 <Separator class="mx-2 h-4" orientation="vertical" />
|
||||
<span class="sm:hidden">WIP</span>
|
||||
<span class="hidden sm:inline">WIP
|
||||
</span>
|
||||
<ArrowRightIcon class="ml-1 h-4 w-4" />
|
||||
<!-- <ArrowRightIcon class="ml-1 h-4 w-4" /> -->
|
||||
</a>
|
||||
<PageHeaderHeading>Build your component library.</PageHeaderHeading>
|
||||
<PageHeaderDescription>
|
||||
|
|
|
|||
9
apps/www/.vitepress/theme/components/LinkedCard.vue
Normal file
9
apps/www/.vitepress/theme/components/LinkedCard.vue
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a :class="cn('flex w-full flex-col items-center rounded-xl border bg-card p-6 text-card-foreground shadow transition-colors hover:bg-muted/50 sm:p-10', $attrs.class ?? '')">
|
||||
<slot />
|
||||
</a>
|
||||
</template>
|
||||
|
|
@ -20,9 +20,7 @@ const { config } = useConfigStore()
|
|||
<Select v-model="config.style">
|
||||
<SelectTrigger :class="cn('h-7 w-[145px] text-xs [&_svg]:h-4 [&_svg]:w-4', props.class)">
|
||||
<span class="text-muted-foreground">Style: </span>
|
||||
<SelectValue placeholder="Select style">
|
||||
{{ styles.find(s => s.name === config.style)?.label }}
|
||||
</SelectValue>
|
||||
<SelectValue placeholder="Select style" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem v-for="style in styles" :key="style.name" :value="style.name" class="text-xs">
|
||||
|
|
|
|||
39
apps/www/.vitepress/theme/components/TabPreview.vue
Normal file
39
apps/www/.vitepress/theme/components/TabPreview.vue
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<script setup lang="ts">
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/lib/registry/default/ui/tabs'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
name: string
|
||||
align?: 'center' | 'start' | 'end'
|
||||
sfcTsCode?: string
|
||||
sfcTsHtml?: string
|
||||
}>(), { align: 'center' })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Tabs :default-value="props.name" class="relative mr-auto w-full">
|
||||
<div class="flex items-center justify-between pb-3">
|
||||
<TabsList class="w-full justify-start rounded-none border-b bg-transparent p-0">
|
||||
<TabsTrigger
|
||||
value="CLI"
|
||||
class="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
|
||||
>
|
||||
CLI
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="Manual"
|
||||
class="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none"
|
||||
>
|
||||
Manual
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
<TabsContent value="CLI" class="relative space-y-10">
|
||||
<slot name="CLI" />
|
||||
</TabsContent>
|
||||
<TabsContent value="Manual">
|
||||
<slot name="Manual" />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -42,6 +42,9 @@ function getHeadingsWithHierarchy(divId: string) {
|
|||
else if (level === 3 && currentLevel?.items) {
|
||||
currentLevel.items.push(item)
|
||||
}
|
||||
else {
|
||||
hierarchy.items.push(item)
|
||||
}
|
||||
})
|
||||
return hierarchy
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
export { default as ComponentPreview } from './ComponentPreview.vue'
|
||||
export { default as TabPreview } from './TabPreview.vue'
|
||||
export { default as Callout } from './Callout.vue'
|
||||
export { default as LinkedCard } from './LinkedCard.vue'
|
||||
export { default as ManualInstall } from './ManualInstall.vue'
|
||||
export { default as Steps } from './Steps.vue'
|
||||
export { default as VPImage } from './VPImage.vue'
|
||||
|
|
|
|||
|
|
@ -376,30 +376,24 @@ const range = ref({
|
|||
<CardContent>
|
||||
<div class="space-y-4">
|
||||
<div
|
||||
class="flex w-max max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm bg-secondary"
|
||||
class="flex w-auto max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm bg-muted"
|
||||
>
|
||||
<p class="text-foreground">
|
||||
Hi There!, I'm Bear, the founder of Bear Studios. I'm here
|
||||
to help you with anything you need.
|
||||
</p>
|
||||
Hi, how can I help you today?
|
||||
</div>
|
||||
<div
|
||||
class="flex w-max max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm ml-auto bg-primary text-primary-foreground"
|
||||
class="flex w-auto max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm ml-auto bg-primary text-primary-foreground"
|
||||
>
|
||||
<p>Hey, I'm having trouble with my account.</p>
|
||||
Hey, I'm having trouble with my account.
|
||||
</div>
|
||||
<div
|
||||
class="flex w-max max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm bg-secondary"
|
||||
class="flex w-auto max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm bg-muted"
|
||||
>
|
||||
<p class="text-foreground">
|
||||
Sure, I can help you with that. What seems to be the
|
||||
problem?
|
||||
</p>
|
||||
Sure, I can help you with that. What seems to be the problem?
|
||||
</div>
|
||||
<div
|
||||
class="flex w-max max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm ml-auto bg-primary text-primary-foreground"
|
||||
class="flex w-auto max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm ml-auto bg-primary text-primary-foreground"
|
||||
>
|
||||
<p>I can't log in.</p>
|
||||
I can't log in.
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
|
|
|||
|
|
@ -95,6 +95,31 @@ export const docsConfig: DocsConfig = {
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Installation',
|
||||
items: [
|
||||
{
|
||||
title: 'Vite',
|
||||
href: '/docs/installation/vite',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: 'Nuxt',
|
||||
href: '/docs/installation/nuxt',
|
||||
items: [],
|
||||
},
|
||||
// {
|
||||
// title: 'Astro',
|
||||
// href: '/docs/installation/astro',
|
||||
// items: [],
|
||||
// },
|
||||
{
|
||||
title: 'Laravel',
|
||||
href: '/docs/installation/laravel',
|
||||
items: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Components',
|
||||
items: [
|
||||
|
|
@ -155,18 +180,16 @@ export const docsConfig: DocsConfig = {
|
|||
},
|
||||
{
|
||||
title: 'Combobox',
|
||||
disabled: true,
|
||||
label: 'Soon',
|
||||
href: '#',
|
||||
href: '/docs/components/combobox',
|
||||
label: 'New',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: 'Command',
|
||||
href: '/docs/components/command',
|
||||
label: 'New',
|
||||
items: [],
|
||||
},
|
||||
// {
|
||||
// title: "Command",
|
||||
// href: "#",
|
||||
// label: "Soon",
|
||||
// disabled: true,
|
||||
// items: []
|
||||
// },
|
||||
{
|
||||
title: 'Context Menu',
|
||||
href: '/docs/components/context-menu',
|
||||
|
|
|
|||
|
|
@ -1,19 +1,25 @@
|
|||
<script setup lang="ts">
|
||||
import { useToggle } from '@vueuse/core'
|
||||
import { Content, useData, useRoute } from 'vitepress'
|
||||
import { onMounted } from 'vue'
|
||||
import { docsConfig } from '../config/docs'
|
||||
import { useMagicKeys, useToggle } from '@vueuse/core'
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import { Content, useData, useRoute, useRouter } from 'vitepress'
|
||||
import { SearchIcon } from 'lucide-vue-next'
|
||||
import { type NavItem, docsConfig } from '../config/docs'
|
||||
import Logo from '../components/Logo.vue'
|
||||
import MobileNav from '../components/MobileNav.vue'
|
||||
|
||||
// import { Button } from '@/lib/registry/default/ui/button'
|
||||
// import { Kbd } from '@/lib/registry/default/ui/kbd'
|
||||
// import LucideSearch from '~icons/lucide/search'
|
||||
import Kbd from '../components/Kbd.vue'
|
||||
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator } from '@/lib/registry/default/ui/command'
|
||||
|
||||
import { Button } from '@/lib/registry/default/ui/button'
|
||||
import RadixIconsGithubLogo from '~icons/radix-icons/github-logo'
|
||||
import TablerBrandX from '~icons/tabler/brand-x'
|
||||
import RadixIconsMoon from '~icons/radix-icons/moon'
|
||||
import RadixIconsSun from '~icons/radix-icons/sun'
|
||||
import { useConfigStore } from '@/stores/config'
|
||||
import { Dialog, DialogContent } from '@/lib/registry/default/ui/dialog'
|
||||
|
||||
import File from '~icons/radix-icons/file'
|
||||
import Circle from '~icons/radix-icons/circle'
|
||||
|
||||
const { radius, theme } = useConfigStore()
|
||||
// Whenever the component is mounted, update the document class list
|
||||
|
|
@ -25,20 +31,48 @@ onMounted(() => {
|
|||
const { frontmatter, isDark } = useData()
|
||||
|
||||
const $route = useRoute()
|
||||
const $router = useRouter()
|
||||
const toggleDark = useToggle(isDark)
|
||||
|
||||
const links = [
|
||||
{
|
||||
name: 'GitHub',
|
||||
href: 'https://github.com/radix-vue',
|
||||
href: 'https://github.com/radix-vue/shadcn-vue',
|
||||
icon: RadixIconsGithubLogo,
|
||||
},
|
||||
{
|
||||
name: 'X',
|
||||
href: 'https://x.com',
|
||||
icon: TablerBrandX,
|
||||
},
|
||||
// {
|
||||
// name: 'X',
|
||||
// href: 'https://x.com',
|
||||
// icon: TablerBrandX,
|
||||
// },
|
||||
]
|
||||
|
||||
const isOpen = ref(false)
|
||||
const { Meta_K, Ctrl_K } = useMagicKeys()
|
||||
|
||||
watch([Meta_K, Ctrl_K], (v) => {
|
||||
if (v[0] || v[1])
|
||||
isOpen.value = true
|
||||
})
|
||||
|
||||
function handleSelectLink(item: NavItem) {
|
||||
if (item.external)
|
||||
window.open(item.href, '_blank')
|
||||
else
|
||||
$router.go(item.href)
|
||||
|
||||
isOpen.value = false
|
||||
}
|
||||
|
||||
watch(() => $route.path, (n) => {
|
||||
// @ts-expect-error View Transition API not supported by all the browser yet
|
||||
if (document.startViewTransition) {
|
||||
// @ts-expect-error View Transition API not supported by all the browser yet
|
||||
document.startViewTransition(() => {
|
||||
console.log('soft navigating to: ', n)
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -71,19 +105,19 @@ const links = [
|
|||
</div>
|
||||
|
||||
<div class=" flex items-center justify-end space-x-4 ">
|
||||
<!-- <Button
|
||||
<Button
|
||||
variant="outline"
|
||||
class="w-72 h-8 px-3 hidden lg:flex lg:justify-between lg:items-center"
|
||||
@click="isOpen = true"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<LucideSearch class="w-4 h-4 mr-2 text-muted-foreground" />
|
||||
<SearchIcon class="w-4 h-4 mr-2 text-muted-foreground" />
|
||||
<span class="text-muted-foreground"> Search for anything... </span>
|
||||
</div>
|
||||
<div class="flex items-center gap-x-1">
|
||||
<Kbd>⌘</Kbd>
|
||||
<Kbd>K</Kbd>
|
||||
<Kbd> <span>⌘</span>K </Kbd>
|
||||
</div>
|
||||
</Button> -->
|
||||
</Button>
|
||||
|
||||
<div
|
||||
v-for="link in links"
|
||||
|
|
@ -110,18 +144,26 @@ const links = [
|
|||
</header>
|
||||
|
||||
<div class="flex-1 bg-background">
|
||||
<component :is="'docs'" v-if="$route.path.includes('docs')">
|
||||
<Content />
|
||||
</component>
|
||||
<component :is="'examples'" v-else-if="$route.path.includes('examples')">
|
||||
<Content />
|
||||
</component>
|
||||
<component :is="frontmatter.layout" v-else-if="frontmatter.layout">
|
||||
<slot />
|
||||
</component>
|
||||
<main v-else class="container">
|
||||
<Content />
|
||||
</main>
|
||||
<Transition name="fade" mode="out-in">
|
||||
<component :is="'docs'" v-if="$route.path.includes('docs')">
|
||||
<Transition name="fade" mode="out-in">
|
||||
<Content :key="$route.path" />
|
||||
</Transition>
|
||||
</component>
|
||||
<component :is="'examples'" v-else-if="$route.path.includes('examples')">
|
||||
<Transition name="fade" mode="out-in">
|
||||
<Content :key="$route.path" />
|
||||
</Transition>
|
||||
</component>
|
||||
<component :is="frontmatter.layout" v-else-if="frontmatter.layout">
|
||||
<slot />
|
||||
</component>
|
||||
<main v-else class="container">
|
||||
<Transition name="fade" mode="out-in">
|
||||
<Content :key="$route.path" />
|
||||
</Transition>
|
||||
</main>
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<footer class="py-6 md:px-8 md:py-0">
|
||||
|
|
@ -162,5 +204,77 @@ const links = [
|
|||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<Dialog v-model:open="isOpen">
|
||||
<DialogContent class="p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandEmpty>
|
||||
No results found.
|
||||
</CommandEmpty>
|
||||
<CommandList
|
||||
@escape-key-down=" isOpen = false"
|
||||
>
|
||||
<CommandGroup heading="Links">
|
||||
<CommandItem
|
||||
v-for="item in docsConfig.mainNav"
|
||||
:key="item.title"
|
||||
:heading="item.title"
|
||||
:value="item.title"
|
||||
class="py-3"
|
||||
@select="handleSelectLink(item)"
|
||||
>
|
||||
<File class="mr-2 h-5 w-5" />
|
||||
<span>{{ item.title }}</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup v-for="item in docsConfig.sidebarNav" :key="item.title" :heading="item.title">
|
||||
<CommandItem
|
||||
v-for="subItem in item.items"
|
||||
:key="subItem.title"
|
||||
:heading="subItem.title"
|
||||
:value="subItem.title"
|
||||
class="py-3"
|
||||
@select="
|
||||
handleSelectLink(subItem)"
|
||||
>
|
||||
<Circle class="mr-2 h-4 w-4" />
|
||||
<span>{{ subItem.title }}</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Theme">
|
||||
<CommandItem
|
||||
value="light-theme"
|
||||
class="py-3"
|
||||
@select="
|
||||
() => {
|
||||
isDark = false;
|
||||
isOpen = false;
|
||||
}
|
||||
"
|
||||
>
|
||||
<RadixIconsSun class="mr-2 h-5 w-5" />
|
||||
<span>Light Theme</span>
|
||||
</CommandItem>
|
||||
<CommandItem
|
||||
value="dark-theme"
|
||||
class="py-3"
|
||||
@select="
|
||||
() => {
|
||||
isDark = true;
|
||||
isOpen = false;
|
||||
}
|
||||
"
|
||||
>
|
||||
<RadixIconsMoon class="mr-2 h-5 w-5" />
|
||||
<span>Dark Theme</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { useData } from 'vitepress'
|
|||
import PageHeader from '../components/PageHeader.vue'
|
||||
import PageHeaderHeading from '../components/PageHeaderHeading.vue'
|
||||
import PageHeaderDescription from '../components/PageHeaderDescription.vue'
|
||||
import CustomizerCode from '../components/CustomizerCode.vue'
|
||||
import { RADII, useConfigStore } from '@/stores/config'
|
||||
import { colors } from '@/lib/registry'
|
||||
import { Button } from '@/lib/registry/new-york/ui/button'
|
||||
|
|
@ -231,6 +232,7 @@ watch(radius, (radius) => {
|
|||
Copy and paste the following code into your CSS file.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<CustomizerCode />
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -145,3 +145,8 @@ pre code .line {
|
|||
.line-number {
|
||||
@apply min-h-[1.375rem] !text-sm !inline-block text-muted-foreground;
|
||||
}
|
||||
|
||||
::view-transition-old(root),
|
||||
::view-transition-new(root) {
|
||||
animation-duration: 0.3s;
|
||||
}
|
||||
|
|
@ -86,6 +86,20 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/default/example/CollapsibleDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/CollapsibleDemo.vue'],
|
||||
},
|
||||
ComboboxDemo: {
|
||||
name: 'ComboboxDemo',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['utils', 'button', 'command', 'popover'],
|
||||
component: () => import('../src/lib/registry/default/example/ComboboxDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/ComboboxDemo.vue'],
|
||||
},
|
||||
CommandDemo: {
|
||||
name: 'CommandDemo',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['command'],
|
||||
component: () => import('../src/lib/registry/default/example/CommandDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/CommandDemo.vue'],
|
||||
},
|
||||
ContextMenuDemo: {
|
||||
name: 'ContextMenuDemo',
|
||||
type: 'components:example',
|
||||
|
|
@ -466,6 +480,20 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/new-york/example/CollapsibleDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/CollapsibleDemo.vue'],
|
||||
},
|
||||
ComboboxDemo: {
|
||||
name: 'ComboboxDemo',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['utils', 'button', 'command', 'popover'],
|
||||
component: () => import('../src/lib/registry/new-york/example/ComboboxDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/ComboboxDemo.vue'],
|
||||
},
|
||||
CommandDemo: {
|
||||
name: 'CommandDemo',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['command'],
|
||||
component: () => import('../src/lib/registry/new-york/example/CommandDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/CommandDemo.vue'],
|
||||
},
|
||||
ContextMenuDemo: {
|
||||
name: 'ContextMenuDemo',
|
||||
type: 'components:example',
|
||||
|
|
@ -666,99 +694,99 @@ export const Index = {
|
|||
name: 'TypographyBlockquote',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyBlockquote.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyBlockquote.vue'],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyBlockquote.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyBlockquote.vue'],
|
||||
},
|
||||
TypographyDemo: {
|
||||
name: 'TypographyDemo',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyDemo.vue'],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyDemo.vue'],
|
||||
},
|
||||
TypographyH1: {
|
||||
name: 'TypographyH1',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyH1.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyH1.vue'],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyH1.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyH1.vue'],
|
||||
},
|
||||
TypographyH2: {
|
||||
name: 'TypographyH2',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyH2.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyH2.vue'],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyH2.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyH2.vue'],
|
||||
},
|
||||
TypographyH3: {
|
||||
name: 'TypographyH3',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyH3.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyH3.vue'],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyH3.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyH3.vue'],
|
||||
},
|
||||
TypographyH4: {
|
||||
name: 'TypographyH4',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyH4.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyH4.vue'],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyH4.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyH4.vue'],
|
||||
},
|
||||
TypographyInlineCode: {
|
||||
name: 'TypographyInlineCode',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyInlineCode.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyInlineCode.vue'],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyInlineCode.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyInlineCode.vue'],
|
||||
},
|
||||
TypographyLarge: {
|
||||
name: 'TypographyLarge',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyLarge.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyLarge.vue'],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyLarge.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyLarge.vue'],
|
||||
},
|
||||
TypographyLead: {
|
||||
name: 'TypographyLead',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyLead.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyLead.vue'],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyLead.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyLead.vue'],
|
||||
},
|
||||
TypographyList: {
|
||||
name: 'TypographyList',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyList.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyList.vue'],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyList.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyList.vue'],
|
||||
},
|
||||
TypographyMuted: {
|
||||
name: 'TypographyMuted',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyMuted.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyMuted.vue'],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyMuted.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyMuted.vue'],
|
||||
},
|
||||
TypographyP: {
|
||||
name: 'TypographyP',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyP.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyP.vue'],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyP.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyP.vue'],
|
||||
},
|
||||
TypographySmall: {
|
||||
name: 'TypographySmall',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographySmall.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographySmall.vue'],
|
||||
component: () => import('../src/lib/registry/default/example/TypographySmall.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographySmall.vue'],
|
||||
},
|
||||
TypographyTable: {
|
||||
name: 'TypographyTable',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyTable.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyTable.vue'],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyTable.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyTable.vue'],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,21 +9,19 @@
|
|||
"dev": "vitepress dev",
|
||||
"build": "vitepress build",
|
||||
"preview": "vitepress preview",
|
||||
"build:registry": "ts-node --esm --project ./tsconfig.scripts.json ./scripts/build-registry.ts"
|
||||
"build:registry": "tsx ./scripts/build-registry.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@morev/vue-transitions": "^2.3.6",
|
||||
"@tanstack/vue-table": "^8.9.3",
|
||||
"@tanstack/vue-table": "^8.9.9",
|
||||
"@unovis/ts": "^1.2.1",
|
||||
"@vitejs/plugin-vue-jsx": "^3.0.2",
|
||||
"@vueuse/core": "^10.2.1",
|
||||
"class-variance-authority": "^0.6.1",
|
||||
"@vueuse/core": "^10.4.1",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
"date-fns": "^2.30.0",
|
||||
"lucide-vue-next": "^0.268.0",
|
||||
"tailwindcss-animate": "^1.0.6",
|
||||
"lucide-vue-next": "^0.276.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"v-calendar": "^3.0.3",
|
||||
"vitepress": "^1.0.0-rc.10",
|
||||
"vue": "^3.3.4",
|
||||
"vue-wrap-balancer": "^1.1.3",
|
||||
"zod": "^3.22.2"
|
||||
|
|
@ -34,21 +32,22 @@
|
|||
"@iconify/json": "^2.2.108",
|
||||
"@iconify/vue": "^4.1.1",
|
||||
"@types/lodash.template": "^4.5.1",
|
||||
"@types/node": "^20.5.7",
|
||||
"@vitejs/plugin-vue": "^4.1.0",
|
||||
"@types/node": "^20.6.0",
|
||||
"@vitejs/plugin-vue": "^4.3.4",
|
||||
"@vitejs/plugin-vue-jsx": "^3.0.2",
|
||||
"@vue/compiler-core": "^3.3.4",
|
||||
"@vue/compiler-dom": "^3.3.4",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"lodash.template": "^4.5.0",
|
||||
"postcss": "^8.4.24",
|
||||
"radix-vue": "^0.1.32",
|
||||
"radix-vue": "^0.2.2",
|
||||
"rimraf": "^5.0.1",
|
||||
"tailwind-merge": "^1.14.0",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.0.2",
|
||||
"unplugin-icons": "^0.16.6",
|
||||
"vite": "^4.3.9",
|
||||
"vue-tsc": "^1.4.2"
|
||||
"tsx": "^3.12.10",
|
||||
"typescript": "^5.2.2",
|
||||
"unplugin-icons": "^0.17.0",
|
||||
"vite": "^4.4.9",
|
||||
"vitepress": "^1.0.0-rc.13",
|
||||
"vue-tsc": "^1.8.11"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
|
|
@ -17,15 +17,14 @@ You will be asked a few questions to configure `components.json`:
|
|||
|
||||
```txt:line-numbers
|
||||
Would you like to use TypeScript (recommended)? no / yes
|
||||
Which framework are you using? Vite + Vue / Nuxt
|
||||
Which framework are you using? Vite / Nuxt / Laravel
|
||||
Which style would you like to use? › Default
|
||||
Which color would you like to use as base color? › Slate
|
||||
Where is your global CSS file? › › src/index.css
|
||||
Do you want to use CSS variables for colors? › no / yes
|
||||
Where is your tailwind.config.js located? › tailwind.config.js
|
||||
Configure the import alias for components: › @/components
|
||||
Configure the import alias for utils: › @/lib/utils
|
||||
Are you using React Server Components? › no / yes (no)
|
||||
Configure the import alias for utils: › @/lib/utils
|
||||
```
|
||||
|
||||
### Options
|
||||
|
|
|
|||
|
|
@ -8,38 +8,64 @@ primitive: https://www.radix-vue.com/components/accordion.html
|
|||
|
||||
<ComponentPreview name="AccordionDemo" class="[&_.accordion]:sm:max-w-[70%]" />
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
<Steps>
|
||||
|
||||
### Run the following command
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add accordion
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
### Update `tailwind.config.js`
|
||||
|
||||
1. Install `radix-vue`:
|
||||
Add the following animations to your `tailwind.config.js` file:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```js title="tailwind.config.js" {5-18}
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
theme: {
|
||||
extend: {
|
||||
keyframes: {
|
||||
'accordion-down': {
|
||||
from: { height: 0 },
|
||||
to: { height: 'var(--radix-accordion-content-height)' },
|
||||
},
|
||||
'accordion-up': {
|
||||
from: { height: 'var(--radix-accordion-content-height)' },
|
||||
to: { height: 0 },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
'accordion-down': 'accordion-down 0.2s ease-out',
|
||||
'accordion-up': 'accordion-up 0.2s ease-out',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
</Steps>
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/lib/registry/default/ui/accordion'
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'
|
||||
</script>
|
||||
|
||||
<AccordionRoot>
|
||||
<AccordionItem value="item-1">
|
||||
<AccordionTrigger>Is it accessible?</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It adheres to the WAI-ARIA design pattern.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</AccordionRoot>
|
||||
```
|
||||
<template>
|
||||
<Accordion type="single" collapsible>
|
||||
<AccordionItem value="item-1">
|
||||
<AccordionTrigger>Is it accessible?</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It adheres to the WAI-ARIA design pattern.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</template>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -7,27 +7,15 @@ primitive: https://www.radix-vue.com/components/alert-dialog.html
|
|||
|
||||
|
||||
<ComponentPreview name="AlertDialogDemo" />
|
||||
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add alert-dialog
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
npx shadcn-vue@latest add alert-dialog
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
|
|
@ -42,20 +30,18 @@ import {
|
|||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from '@/lib/registry/default/ui/alert-dialog'
|
||||
} from '@/components/ui/alert-dialog'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger>
|
||||
Open
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogTrigger>Open</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This action cannot be undone. This will permanently delete your
|
||||
account and remove your data from our servers.
|
||||
This action cannot be undone. This will permanently delete your account
|
||||
and remove your data from our servers.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
|
|
|
|||
|
|
@ -6,30 +6,18 @@ description: Displays a callout for user attention.
|
|||
|
||||
<ComponentPreview name="AlertDemo" />
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add alert
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/lib/registry/default/ui/alert'
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -10,33 +10,45 @@ primitive: https://www.radix-vue.com/components/aspect-ratio.html
|
|||
|
||||
## Installation
|
||||
|
||||
<TabPreview name="CLI">
|
||||
<template #CLI>
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add aspect-ratio
|
||||
```
|
||||
</template>
|
||||
|
||||
<ManualInstall>
|
||||
<template #Manual>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
<Steps>
|
||||
|
||||
### Install the following dependency:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
### Copy and paste the following code into your project:
|
||||
|
||||
<<< @/lib/registry/default/ui/aspect-ratio/AspectRatio.vue
|
||||
|
||||
</Steps>
|
||||
|
||||
</template>
|
||||
</TabPreview>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { AspectRatio } from '@/lib/registry/default/ui/aspect-ratio'
|
||||
import { AspectRatio } from '@/components/ui/aspect-ratio'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AspectRatio>
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1588345921523-c2dcdb7f1dcd?w=800&dpr=2&q=80"
|
||||
>
|
||||
</AspectRatio>
|
||||
<div class="w-[450px]">
|
||||
<AspectRatio :ratio="16 / 9">
|
||||
<img src="..." alt="Image" class="rounded-md object-cover">
|
||||
</AspectRatio>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
|
@ -11,31 +11,21 @@ primitive: https://www.radix-vue.com/components/avatar.html
|
|||
|
||||
## Installation
|
||||
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add avatar
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/lib/registry/default/ui/avatar'
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Avatar>
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarImage src="https://github.com/radix-vue.png" alt="@radix-vue" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -6,29 +6,73 @@ description: Displays a badge or a component that looks like a badge.
|
|||
|
||||
<ComponentPreview name="BadgeDemo" />
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
<TabPreview name="CLI">
|
||||
<template #CLI>
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add badge
|
||||
```
|
||||
</template>
|
||||
|
||||
<ManualInstall>
|
||||
<template #Manual>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
<Steps>
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
### Copy and paste the following code into your project
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
defineProps<Props>()
|
||||
|
||||
const badgeVariants = cva(
|
||||
'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
|
||||
secondary:
|
||||
'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
destructive:
|
||||
'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
|
||||
outline: 'text-foreground',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
interface BadgeVariantProps extends VariantProps<typeof badgeVariants> {}
|
||||
|
||||
interface Props {
|
||||
variant?: BadgeVariantProps['variant']
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn(badgeVariants({ variant }), $attrs.class ?? '')">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
</Steps>
|
||||
|
||||
</template>
|
||||
</TabPreview>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Badge } from '@/lib/registry/default/ui/badge'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -8,26 +8,85 @@ description: Displays a button or a component that looks like a button.
|
|||
|
||||
## Installation
|
||||
|
||||
<TabPreview name="CLI">
|
||||
<template #CLI>
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add button
|
||||
```
|
||||
</template>
|
||||
|
||||
<ManualInstall>
|
||||
<template #Manual>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
<Steps>
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
### Copy and paste the following code into your project
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { cva } from 'class-variance-authority'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const buttonVariants = cva(
|
||||
'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
||||
destructive:
|
||||
'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
||||
outline:
|
||||
'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
|
||||
secondary:
|
||||
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
||||
link: 'text-primary underline-offset-4 hover:underline',
|
||||
},
|
||||
size: {
|
||||
default: 'h-10 px-4 py-2',
|
||||
sm: 'h-9 rounded-md px-3',
|
||||
lg: 'h-11 rounded-md px-8',
|
||||
icon: 'h-10 w-10',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
size: 'default',
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
interface Props {
|
||||
variant?: NonNullable<Parameters<typeof buttonVariants>[0]>['variant']
|
||||
size?: NonNullable<Parameters<typeof buttonVariants>[0]>['size']
|
||||
as?: string
|
||||
}
|
||||
|
||||
// eslint-disable-next-line vue/define-macros-order
|
||||
withDefaults(defineProps<Props>(), {
|
||||
as: 'button',
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component
|
||||
:is="as"
|
||||
:class="cn(buttonVariants({ variant, size }), $attrs.class ?? '')"
|
||||
>
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
</Steps>
|
||||
</template>
|
||||
</TabPreview>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Button } from '@/lib/registry/default/ui/button'
|
||||
import { Button } from '@/components/ui/button'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -11,27 +11,42 @@ description: A date field component that allows users to enter and edit date.
|
|||
The `Calendar` component is built on top of [VCalendar](https://vcalendar.io/getting-started/installation.html).
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
<TabPreview name="CLI">
|
||||
<template #CLI>
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add calendar
|
||||
```
|
||||
</template>
|
||||
|
||||
<ManualInstall>
|
||||
<template #Manual>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
<Steps>
|
||||
|
||||
### Install the following dependency
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
npm install v-calendar
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
### Copy and paste the following code into your project
|
||||
|
||||
|
||||
<<< @/lib/registry/default/ui/calendar/Calendar.vue
|
||||
|
||||
|
||||
</Steps>
|
||||
|
||||
|
||||
</template>
|
||||
</TabPreview>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Calendar } from '@/lib/registry/default/ui/calendar'
|
||||
import { Calendar } from '@/components/ui/calendar'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -6,23 +6,13 @@ description: Displays a card with header, content, and footer.
|
|||
|
||||
<ComponentPreview name="CardDemo" />
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add card
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
@ -35,7 +25,7 @@ import {
|
|||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from '@/lib/registry/default/ui/card'
|
||||
} from '@/components/ui/card'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -10,30 +10,26 @@ primitive: https://www.radix-vue.com/components/checkbox.html
|
|||
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add checkbox
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Checkbox } from '@/lib/registry/default/ui/checkbox'
|
||||
import { Checkbox } from '@/components/ui/checkbox'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Checkbox id="terms" />
|
||||
</template>
|
||||
```
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### With text
|
||||
|
||||
<ComponentPreview name="CheckboxDisabled" />
|
||||
|
|
@ -8,47 +8,33 @@ primitive: https://www.radix-vue.com/components/collapsible.html
|
|||
|
||||
<ComponentPreview name="CollapsibleDemo" />
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add collapsible
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from '@/lib/registry/default/ui/collapsible'
|
||||
} from '@/components/ui/collapsible'
|
||||
|
||||
const isOpen = ref(false)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Collapsible
|
||||
v-model:open="isOpen"
|
||||
>
|
||||
<CollapsibleTrigger>
|
||||
Trigger
|
||||
</CollapsibleTrigger>
|
||||
<Collapsible v-model:open="isOpen">
|
||||
<CollapsibleTrigger>Can I use this in my project?</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
Content
|
||||
Yes. Free to use for personal and commercial projects. No attribution
|
||||
required.
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
</template>
|
||||
|
|
|
|||
89
apps/www/src/content/docs/components/combobox.md
Normal file
89
apps/www/src/content/docs/components/combobox.md
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
---
|
||||
title: Combobox
|
||||
description: Autocomplete input and command palette with a list of suggestions.
|
||||
component: true
|
||||
---
|
||||
|
||||
<ComponentPreview name="ComboboxDemo" />
|
||||
|
||||
## Installation
|
||||
|
||||
The Combobox is built using a composition of the `<Popover />` and the `<Command />` components.
|
||||
|
||||
See installation instructions for the [Popover](/docs/components/popover#installation) and the [Command](/docs/components/command#installation) components.
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Check, ChevronsUpDown } from 'lucide-vue-next'
|
||||
|
||||
import { ref } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
} from '@/components/ui/command'
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/components/ui/popover'
|
||||
|
||||
const frameworks = [
|
||||
{ value: 'next.js', label: 'Next.js' },
|
||||
{ value: 'sveltekit', label: 'SvelteKit' },
|
||||
{ value: 'nuxt.js', label: 'Nuxt.js' },
|
||||
{ value: 'remix', label: 'Remix' },
|
||||
{ value: 'astro', label: 'Astro' },
|
||||
]
|
||||
|
||||
const open = ref(false)
|
||||
const value = ref({})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Popover v-model:open="open">
|
||||
<PopoverTrigger as-child>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
:aria-expanded="open"
|
||||
class="w-[200px] justify-between"
|
||||
>
|
||||
{{ value ? frameworks.find((framework) => framework.value === value)?.label : 'Select framework...' }}
|
||||
|
||||
<ChevronsUpDown class="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-[200px] p-0">
|
||||
<Command v-model="value">
|
||||
<CommandInput placeholder="Search framework..." />
|
||||
<CommandEmpty>No framework found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
v-for="framework in frameworks"
|
||||
:key="framework.value"
|
||||
:value="framework"
|
||||
@select="open = false"
|
||||
>
|
||||
<Check
|
||||
:class="cn(
|
||||
'mr-2 h-4 w-4',
|
||||
value === framework.value ? 'opacity-100' : 'opacity-0',
|
||||
)"
|
||||
/>
|
||||
{{ framework.label }}
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</template>
|
||||
```
|
||||
|
||||
|
||||
54
apps/www/src/content/docs/components/command.md
Normal file
54
apps/www/src/content/docs/components/command.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
title: Command
|
||||
description: Fast, composable, unstyled command menu.
|
||||
source: apps/www/src/lib/registry/default/ui/command
|
||||
primitive: https://www.radix-vue.com/components/combobox.html
|
||||
---
|
||||
|
||||
|
||||
<ComponentPreview name="CommandDemo" />
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add command
|
||||
```
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
CommandShortcut,
|
||||
} from '@/components/ui/command'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Command>
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup heading="Suggestions">
|
||||
<CommandItem>Calendar</CommandItem>
|
||||
<CommandItem>Search Emoji</CommandItem>
|
||||
<CommandItem>Calculator</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Settings">
|
||||
<CommandItem>Profile</CommandItem>
|
||||
<CommandItem>Billing</CommandItem>
|
||||
<CommandItem>Settings</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</template>```
|
||||
|
|
@ -8,24 +8,11 @@ primitive: https://www.radix-vue.com/components/context-menu.html
|
|||
|
||||
<ComponentPreview name="ContextMenuDemo" />
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add context-menu
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
@ -45,7 +32,7 @@ import {
|
|||
ContextMenuSubContent,
|
||||
ContextMenuSubTrigger,
|
||||
ContextMenuTrigger,
|
||||
} from '@/lib/registry/default/ui/context-menu'
|
||||
} from '@/components/ui/context-menu'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -21,13 +21,13 @@ import { Calendar as CalendarIcon } from 'lucide-vue-next'
|
|||
|
||||
import { ref } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Button } from '@/lib/registry/default/ui/button'
|
||||
import { Calendar } from '@/lib/registry/default/ui/calendar'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Calendar } from '@/components/ui/calendar'
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/lib/registry/default/ui/popover'
|
||||
} from '@/components/ui/popover'
|
||||
|
||||
const date = ref<Date>()
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -7,25 +7,12 @@ primitive: https://www.radix-vue.com/components/dialog.html
|
|||
|
||||
|
||||
<ComponentPreview name="DialogDemo" />
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
## Installation
|
||||
```bash
|
||||
npx shadcn-vue@latest add dialog
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
|
|
@ -38,7 +25,7 @@ import {
|
|||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@/lib/registry/default/ui/dialog'
|
||||
} from '@/components/ui/dialog'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -8,24 +8,11 @@ primitive: https://www.radix-vue.com/components/dropdown-menu.html
|
|||
|
||||
<ComponentPreview name="DropdownMenuDemo" />
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add dropdown-menu
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
```
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
|
|
@ -37,7 +24,7 @@ import {
|
|||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/lib/registry/default/ui/dropdown-menu'
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -8,24 +8,11 @@ primitive: https://www.radix-vue.com/components/hover-card.html
|
|||
|
||||
<ComponentPreview name="HoverCardDemo" />
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add hover-card
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
```
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
|
|
@ -34,14 +21,14 @@ import {
|
|||
HoverCard,
|
||||
HoverCardContent,
|
||||
HoverCardTrigger,
|
||||
} from '@/lib/registry/default/ui/hover-card'
|
||||
} from '@/components/ui/hover-card'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<HoverCard>
|
||||
<HoverCardTrigger>Hover</HoverCardTrigger>
|
||||
<HoverCardContent>
|
||||
The React Framework – created and maintained by @vercel.
|
||||
The Vue Framework – created and maintained by @vuejs.
|
||||
</HoverCardContent>
|
||||
</HoverCard>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -6,30 +6,36 @@ description: Displays a form input field or a component that looks like an input
|
|||
|
||||
<ComponentPreview name="InputDemo" class="[&_input]:max-w-xs" />
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
<TabPreview name="CLI">
|
||||
<template #CLI>
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add input
|
||||
```
|
||||
</template>
|
||||
|
||||
<ManualInstall>
|
||||
<template #Manual>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
<Steps>
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
### Copy and paste the following code into your project:
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
<<< @/lib/registry/default/ui/input/Input.vue
|
||||
|
||||
</Steps>
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
</TabPreview>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Input } from '@/lib/registry/default/ui/input'
|
||||
import { Input } from '@/components/ui/input'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -10,26 +10,38 @@ primitive: https://www.radix-vue.com/components/label.html
|
|||
|
||||
## Installation
|
||||
|
||||
<TabPreview name="CLI">
|
||||
<template #CLI>
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add input
|
||||
npx shadcn-vue@latest add label
|
||||
```
|
||||
</template>
|
||||
|
||||
<ManualInstall>
|
||||
<template #Manual>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
<Steps>
|
||||
|
||||
### Install the following dependency:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
### Copy and paste the following code into your project:
|
||||
|
||||
<<< @/lib/registry/default/ui/label/Label.vue
|
||||
|
||||
</Steps>
|
||||
|
||||
</template>
|
||||
</TabPreview>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Label } from '@/lib/registry/default/ui/label'
|
||||
import { Label } from '@/components/ui/label'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -7,25 +7,13 @@ primitive: https://www.radix-vue.com/components/menubar.html
|
|||
|
||||
<ComponentPreview name="MenubarDemo" />
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add menubar
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
|
|
@ -38,7 +26,7 @@ import {
|
|||
MenubarSeparator,
|
||||
MenubarShortcut,
|
||||
MenubarTrigger,
|
||||
} from '@/lib/registry/default/ui/menubar'
|
||||
} from '@/components/ui/menubar'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -7,24 +7,12 @@ primitive: https://www.radix-vue.com/components/navigation-menu.html
|
|||
|
||||
<ComponentPreview name="NavigationMenuDemo" />
|
||||
|
||||
|
||||
## Installation
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add navigation-menu
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
|
|
@ -38,7 +26,7 @@ import {
|
|||
NavigationMenuList,
|
||||
NavigationMenuTrigger,
|
||||
NavigationMenuViewport,
|
||||
} from '@/lib/registry/default/ui/navigation-menu'
|
||||
} from '@/components/ui/navigation-menu'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -8,25 +8,13 @@ primitive: https://www.radix-vue.com/components/popover.html
|
|||
|
||||
<ComponentPreview name="PopoverDemo" />
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add popover
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
|
|
@ -35,7 +23,7 @@ import {
|
|||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/lib/registry/default/ui/popover'
|
||||
} from '@/components/ui/popover'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -11,26 +11,38 @@ primitive: https://www.radix-vue.com/components/progress.html
|
|||
|
||||
## Installation
|
||||
|
||||
<TabPreview name="CLI">
|
||||
<template #CLI>
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add progress
|
||||
```
|
||||
</template>
|
||||
|
||||
<ManualInstall>
|
||||
<template #Manual>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
<Steps>
|
||||
|
||||
### Install the following dependency:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
### Copy and paste the following code into your project:
|
||||
|
||||
<<< @/lib/registry/default/ui/progress/Progress.vue
|
||||
|
||||
</Steps>
|
||||
|
||||
</template>
|
||||
</TabPreview>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Progress } from '@/lib/registry/default/ui/progress'
|
||||
import { Progress } from '@/components/ui/progress'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -7,31 +7,19 @@ primitive: https://www.radix-vue.com/components/radio-group.html
|
|||
|
||||
<ComponentPreview name="RadioGroupDemo" />
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add radio-group
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Label } from '@/lib/registry/default/ui/label'
|
||||
import { RadioGroup, RadioGroupItem } from '@/lib/registry/default/ui/radio-group'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -7,30 +7,17 @@ primitive: https://www.radix-vue.com/components/scroll-area.html
|
|||
|
||||
<ComponentPreview name="ScrollAreaDemo" />
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add scroll-area
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { ScrollArea } from '@/lib/registry/default/ui/scroll-area'
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -8,25 +8,13 @@ primitive: https://www.radix-vue.com/components/popover.html
|
|||
|
||||
<ComponentPreview name="SelectDemo" />
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add select
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
|
|
@ -39,7 +27,7 @@ import {
|
|||
SelectLabel,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/lib/registry/default/ui/select'
|
||||
} from '@/components/ui/select'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -8,29 +8,41 @@ primitive: https://www.radix-vue.com/components/separator.html
|
|||
<ComponentPreview name="SeparatorDemo" />
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
<TabPreview name="CLI">
|
||||
<template #CLI>
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add separator
|
||||
```
|
||||
</template>
|
||||
|
||||
<ManualInstall>
|
||||
<template #Manual>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
<Steps>
|
||||
|
||||
### Install the following dependency
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
### Copy and paste the following code into your project
|
||||
|
||||
<<< @/lib/registry/default/ui/separator/Separator.vue
|
||||
|
||||
|
||||
</Steps>
|
||||
|
||||
</template>
|
||||
</TabPreview>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Separator } from '@/lib/registry/default/ui/separator'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -9,22 +9,11 @@ primitive: https://www.radix-vue.com/components/dialog.html
|
|||
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add sheet
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
|
|
@ -36,7 +25,7 @@ import {
|
|||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from '@/lib/registry/default/ui/sheet'
|
||||
} from '@/components/ui/sheet'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -5,29 +5,35 @@ description: Use to show a placeholder while content is loading.
|
|||
|
||||
<ComponentPreview name="SkeletonDemo" />
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
<TabPreview name="CLI">
|
||||
<template #CLI>
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add skeleton
|
||||
```
|
||||
</template>
|
||||
|
||||
<ManualInstall>
|
||||
<template #Manual>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
<Steps>
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
### Copy and paste the following code into your project
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
<<< @/lib/registry/default/ui/skeleton/Skeleton.vue
|
||||
|
||||
</Steps>
|
||||
|
||||
</template>
|
||||
</TabPreview>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Skeleton } from '@/lib/registry/default/ui/skeleton'
|
||||
import { Skeleton } from '@/components/ui/skeleton'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -7,30 +7,17 @@ primitive: https://www.radix-vue.com/components/slider.html
|
|||
|
||||
<ComponentPreview name="SliderDemo" />
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add slider
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Slider } from '@/lib/registry/default/ui/slider'
|
||||
import { Slider } from '@/components/ui/slider'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -10,26 +10,38 @@ primitive: https://www.radix-vue.com/components/switch.html
|
|||
|
||||
## Installation
|
||||
|
||||
<TabPreview name="CLI">
|
||||
<template #CLI>
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add switch
|
||||
```
|
||||
</template>
|
||||
|
||||
<ManualInstall>
|
||||
<template #Manual>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
<Steps>
|
||||
|
||||
### Install the following dependency:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
### Copy and paste the following code into your project
|
||||
|
||||
<<< @/lib/registry/default/ui/switch/Switch.vue
|
||||
|
||||
</Steps>
|
||||
|
||||
</template>
|
||||
</TabPreview>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Switch } from '@/lib/registry/default/ui/switch'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -12,17 +12,6 @@ description: A responsive table component.
|
|||
npx shadcn-vue@latest add table
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
|
|
@ -35,7 +24,7 @@ import {
|
|||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/lib/registry/default/ui/table'
|
||||
} from '@/components/ui/table'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -10,26 +10,17 @@ primitive: https://www.radix-vue.com/components/tabs.html
|
|||
|
||||
## Installation
|
||||
|
||||
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add tabs
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/lib/registry/default/ui/tabs'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -8,26 +8,38 @@ description: Displays a form textarea or a component that looks like a textarea.
|
|||
|
||||
## Installation
|
||||
|
||||
<TabPreview name="CLI">
|
||||
<template #CLI>
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add textarea
|
||||
```
|
||||
</template>
|
||||
|
||||
<ManualInstall>
|
||||
<template #Manual>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
<Steps>
|
||||
|
||||
### Install the following dependency:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
### Copy and paste the following code into your project
|
||||
|
||||
<<< @/lib/registry/default/ui/textarea/Textarea.vue
|
||||
|
||||
</Steps>
|
||||
|
||||
</template>
|
||||
</TabPreview>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Textarea } from '@/lib/registry/default/ui/textarea'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -11,26 +11,38 @@ primitive: https://www.radix-vue.com/components/toggle.html
|
|||
|
||||
## Installation
|
||||
|
||||
<TabPreview name="CLI">
|
||||
<template #CLI>
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add toggle
|
||||
```
|
||||
</template>
|
||||
|
||||
<ManualInstall>
|
||||
<template #Manual>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
<Steps>
|
||||
|
||||
### Install the following dependencies:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
### Copy and paste the following code into your project
|
||||
|
||||
<<< @/lib/registry/default/ui/toggle/Toggle.vue
|
||||
|
||||
</Steps>
|
||||
|
||||
</template>
|
||||
</TabPreview>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Toggle } from '@/lib/registry/default/ui/toggle'
|
||||
import { Toggle } from '@/components/ui/toggle'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -14,17 +14,6 @@ primitive: https://www.radix-vue.com/components/tooltip.html
|
|||
npx shadcn-vue@latest add tooltip
|
||||
```
|
||||
|
||||
<ManualInstall>
|
||||
|
||||
1. Install `radix-vue`:
|
||||
|
||||
```bash
|
||||
npm install radix-vue
|
||||
```
|
||||
|
||||
2. Copy and paste the component source files linked at the top of this page into your project.
|
||||
</ManualInstall>
|
||||
|
||||
## Usage
|
||||
|
||||
```vue
|
||||
|
|
@ -34,7 +23,7 @@ import {
|
|||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger
|
||||
} from '@/lib/registry/default/ui/tooltip'
|
||||
} from '@/components/ui/tooltip'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -18,4 +18,8 @@ The Figma UI Kit is open sourced by [Pietro Schirano](https://twitter.com/skiran
|
|||
|
||||
## Grab a copy
|
||||
|
||||
https://www.figma.com/community/file/1203061493325953101
|
||||
<div class="break-words">
|
||||
|
||||
https://www.figma.com/community/file/1203061493325953101
|
||||
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,128 +2,94 @@
|
|||
title: Installation
|
||||
description: How to install dependencies and structure your app.
|
||||
---
|
||||
|
||||
<script setup>
|
||||
import { Alert, AlertDescription } from "@/lib/registry/default/ui/alert";
|
||||
</script>
|
||||
|
||||
Unlike the original [shadcn/ui](https://ui.shadcn.com) for React, where the full components can exist in a single file, components in this port are split into multiple files due to majority vote from [Vue community](https://twitter.com/zernonia/status/1694351679540580524) to use `SFC` rather than `h()` render function or `JSX`, so utilizing the CLI to add components will be the optimal approach.
|
||||
|
||||
|
||||
## Frameworks
|
||||
|
||||
The CLI will create a folder for _each_ component, which will sometimes just contain a single Vue file, and in other times, multiple files. Within each folder, there will be an `index.ts` file that exports the component(s), so you can import them from a single file.
|
||||
<div class="grid sm:grid-cols-2 gap-4 mt-8 sm:gap-6 not-docs">
|
||||
<LinkedCard href="/docs/installation/vite">
|
||||
<svg
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-10 h-10"
|
||||
fill="currentColor"
|
||||
>
|
||||
<title>Vite</title>
|
||||
<path d="m8.286 10.578.512-8.657a.306.306 0 0 1 .247-.282L17.377.006a.306.306 0 0 1 .353.385l-1.558 5.403a.306.306 0 0 0 .352.385l2.388-.46a.306.306 0 0 1 .332.438l-6.79 13.55-.123.19a.294.294 0 0 1-.252.14c-.177 0-.35-.152-.305-.369l1.095-5.301a.306.306 0 0 0-.388-.355l-1.433.435a.306.306 0 0 1-.389-.354l.69-3.375a.306.306 0 0 0-.37-.36l-2.32.536a.306.306 0 0 1-.374-.316zm14.976-7.926L17.284 3.74l-.544 1.887 2.077-.4a.8.8 0 0 1 .84.369.8.8 0 0 1 .034.783L12.9 19.93l-.013.025-.015.023-.122.19a.801.801 0 0 1-.672.37.826.826 0 0 1-.634-.302.8.8 0 0 1-.16-.67l1.029-4.981-1.12.34a.81.81 0 0 1-.86-.262.802.802 0 0 1-.165-.67l.63-3.08-2.027.468a.808.808 0 0 1-.768-.233.81.81 0 0 1-.217-.6l.389-6.57-7.44-1.33a.612.612 0 0 0-.64.906L11.58 23.691a.612.612 0 0 0 1.066-.004l11.26-20.135a.612.612 0 0 0-.644-.9z" />
|
||||
</svg>
|
||||
<p class="font-medium mt-2">Vite</p>
|
||||
</LinkedCard>
|
||||
<LinkedCard href="/docs/installation/nuxt">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-12 h-12" viewBox="0 0 900 900" fill="none">
|
||||
<title>Nuxt</title>
|
||||
<path d="M504.908 750H839.476C850.103 750.001 860.542 747.229 869.745 741.963C878.948 736.696 886.589 729.121 891.9 719.999C897.211 710.876 900.005 700.529 900 689.997C899.995 679.465 897.193 669.12 891.873 660.002L667.187 274.289C661.876 265.169 654.237 257.595 645.036 252.329C635.835 247.064 625.398 244.291 614.773 244.291C604.149 244.291 593.711 247.064 584.511 252.329C575.31 257.595 567.67 265.169 562.36 274.289L504.908 372.979L392.581 179.993C387.266 170.874 379.623 163.301 370.42 158.036C361.216 152.772 350.777 150 340.151 150C329.525 150 319.086 152.772 309.883 158.036C300.679 163.301 293.036 170.874 287.721 179.993L8.12649 660.002C2.80743 669.12 0.00462935 679.465 5.72978e-06 689.997C-0.00461789 700.529 2.78909 710.876 8.10015 719.999C13.4112 729.121 21.0523 736.696 30.255 741.963C39.4576 747.229 49.8973 750.001 60.524 750H270.538C353.748 750 415.112 713.775 457.336 643.101L559.849 467.145L614.757 372.979L779.547 655.834H559.849L504.908 750ZM267.114 655.737L120.551 655.704L340.249 278.586L449.87 467.145L376.474 593.175C348.433 639.03 316.577 655.737 267.114 655.737Z" fill="white"/>
|
||||
</svg>
|
||||
<p class="font-medium mt-2">Nuxt</p>
|
||||
</LinkedCard>
|
||||
<!-- <LinkedCard href="/docs/installation/astro">
|
||||
<svg
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-10 h-10"
|
||||
fill="currentColor"
|
||||
>
|
||||
<title>Astro</title>
|
||||
<path
|
||||
d="M16.074 16.86C15.354 17.476 13.917 17.895 12.262 17.895C10.23 17.895 8.527 17.263 8.075 16.412C7.914 16.9 7.877 17.458 7.877 17.814C7.877 17.814 7.771 19.564 8.988 20.782C8.988 20.15 9.501 19.637 10.133 19.637C11.216 19.637 11.215 20.582 11.214 21.349V21.418C11.214 22.582 11.925 23.579 12.937 24C12.7812 23.6794 12.7005 23.3275 12.701 22.971C12.701 21.861 13.353 21.448 14.111 20.968C14.713 20.585 15.383 20.161 15.844 19.308C16.0926 18.8493 16.2225 18.3357 16.222 17.814C16.2221 17.4903 16.1722 17.1685 16.074 16.86ZM15.551 0.6C15.747 0.844 15.847 1.172 16.047 1.829L20.415 16.176C18.7743 15.3246 17.0134 14.7284 15.193 14.408L12.35 4.8C12.3273 4.72337 12.2803 4.65616 12.2162 4.60844C12.152 4.56072 12.0742 4.53505 11.9943 4.53528C11.9143 4.5355 11.8366 4.56161 11.7727 4.60969C11.7089 4.65777 11.6623 4.72524 11.64 4.802L8.83 14.405C7.00149 14.724 5.23264 15.3213 3.585 16.176L7.974 1.827C8.174 1.171 8.274 0.843 8.471 0.6C8.64406 0.385433 8.86922 0.218799 9.125 0.116C9.415 0 9.757 0 10.443 0H13.578C14.264 0 14.608 0 14.898 0.117C15.1529 0.219851 15.3783 0.386105 15.551 0.6Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<p class="font-medium mt-2">Astro</p>
|
||||
</LinkedCard> -->
|
||||
<LinkedCard href="/docs/installation/laravel">
|
||||
<svg
|
||||
role="img"
|
||||
viewBox="0 0 62 65"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-10 h-10"
|
||||
>
|
||||
<path d="M61.8548 14.6253C61.8778 14.7102 61.8895 14.7978 61.8897 14.8858V28.5615C61.8898 28.737 61.8434 28.9095 61.7554 29.0614C61.6675 29.2132 61.5409 29.3392 61.3887 29.4265L49.9104 36.0351V49.1337C49.9104 49.4902 49.7209 49.8192 49.4118 49.9987L25.4519 63.7916C25.3971 63.8227 25.3372 63.8427 25.2774 63.8639C25.255 63.8714 25.2338 63.8851 25.2101 63.8913C25.0426 63.9354 24.8666 63.9354 24.6991 63.8913C24.6716 63.8838 24.6467 63.8689 24.6205 63.8589C24.5657 63.8389 24.5084 63.8215 24.456 63.7916L0.501061 49.9987C0.348882 49.9113 0.222437 49.7853 0.134469 49.6334C0.0465019 49.4816 0.000120578 49.3092 0 49.1337L0 8.10652C0 8.01678 0.0124642 7.92953 0.0348998 7.84477C0.0423783 7.8161 0.0598282 7.78993 0.0697995 7.76126C0.0884958 7.70891 0.105946 7.65531 0.133367 7.6067C0.152063 7.5743 0.179485 7.54812 0.20192 7.51821C0.230588 7.47832 0.256763 7.43719 0.290416 7.40229C0.319084 7.37362 0.356476 7.35243 0.388883 7.32751C0.425029 7.29759 0.457436 7.26518 0.498568 7.2415L12.4779 0.345059C12.6296 0.257786 12.8015 0.211853 12.9765 0.211853C13.1515 0.211853 13.3234 0.257786 13.475 0.345059L25.4531 7.2415H25.4556C25.4955 7.26643 25.5292 7.29759 25.5653 7.32626C25.5977 7.35119 25.6339 7.37362 25.6625 7.40104C25.6974 7.43719 25.7224 7.47832 25.7523 7.51821C25.7735 7.54812 25.8021 7.5743 25.8196 7.6067C25.8483 7.65656 25.8645 7.70891 25.8844 7.76126C25.8944 7.78993 25.9118 7.8161 25.9193 7.84602C25.9423 7.93096 25.954 8.01853 25.9542 8.10652V33.7317L35.9355 27.9844V14.8846C35.9355 14.7973 35.948 14.7088 35.9704 14.6253C35.9792 14.5954 35.9954 14.5692 36.0053 14.5405C36.0253 14.4882 36.0427 14.4346 36.0702 14.386C36.0888 14.3536 36.1163 14.3274 36.1375 14.2975C36.1674 14.2576 36.1923 14.2165 36.2272 14.1816C36.2559 14.1529 36.292 14.1317 36.3244 14.1068C36.3618 14.0769 36.3942 14.0445 36.4341 14.0208L48.4147 7.12434C48.5663 7.03694 48.7383 6.99094 48.9133 6.99094C49.0883 6.99094 49.2602 7.03694 49.4118 7.12434L61.3899 14.0208C61.4323 14.0457 61.4647 14.0769 61.5021 14.1055C61.5333 14.1305 61.5694 14.1529 61.5981 14.1803C61.633 14.2165 61.6579 14.2576 61.6878 14.2975C61.7103 14.3274 61.7377 14.3536 61.7551 14.386C61.7838 14.4346 61.8 14.4882 61.8199 14.5405C61.8312 14.5692 61.8474 14.5954 61.8548 14.6253ZM59.893 27.9844V16.6121L55.7013 19.0252L49.9104 22.3593V33.7317L59.8942 27.9844H59.893ZM47.9149 48.5566V37.1768L42.2187 40.4299L25.953 49.7133V61.2003L47.9149 48.5566ZM1.99677 9.83281V48.5566L23.9562 61.199V49.7145L12.4841 43.2219L12.4804 43.2194L12.4754 43.2169C12.4368 43.1945 12.4044 43.1621 12.3682 43.1347C12.3371 43.1097 12.3009 43.0898 12.2735 43.0624L12.271 43.0586C12.2386 43.0275 12.2162 42.9888 12.1887 42.9539C12.1638 42.9203 12.1339 42.8916 12.114 42.8567L12.1127 42.853C12.0903 42.8156 12.0766 42.7707 12.0604 42.7283C12.0442 42.6909 12.023 42.656 12.013 42.6161C12.0005 42.5688 11.998 42.5177 11.9931 42.4691C11.9881 42.4317 11.9781 42.3943 11.9781 42.3569V15.5801L6.18848 12.2446L1.99677 9.83281ZM12.9777 2.36177L2.99764 8.10652L12.9752 13.8513L22.9541 8.10527L12.9752 2.36177H12.9777ZM18.1678 38.2138L23.9574 34.8809V9.83281L19.7657 12.2459L13.9749 15.5801V40.6281L18.1678 38.2138ZM48.9133 9.14105L38.9344 14.8858L48.9133 20.6305L58.8909 14.8846L48.9133 9.14105ZM47.9149 22.3593L42.124 19.0252L37.9323 16.6121V27.9844L43.7219 31.3174L47.9149 33.7317V22.3593ZM24.9533 47.987L39.59 39.631L46.9065 35.4555L36.9352 29.7145L25.4544 36.3242L14.9907 42.3482L24.9533 47.987Z" />
|
||||
</svg>
|
||||
<p class="font-medium mt-2">Laravel</p>
|
||||
</LinkedCard>
|
||||
</div>
|
||||
|
||||
For example, the Accordion component is split into four `.vue` files:
|
||||
|
||||
- `Accordion.vue`
|
||||
- `AccordionContent.vue`
|
||||
- `AccordionItem.vue`
|
||||
- `AccordionTrigger.vue`
|
||||
|
||||
They can then be imported from the `accordion/index.ts` file like so:
|
||||
## TypeScript
|
||||
|
||||
```ts
|
||||
import * as Accordion from '@/components/ui/accordion'
|
||||
This project and the components are written in TypeScript. We recommend using TypeScript for your project as well.
|
||||
|
||||
// or
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger
|
||||
} from '@/components/ui/accordion'
|
||||
```
|
||||
However we provide a JavaScript version of the components as well. The JavaScript version is available via the [cli](/docs/cli).
|
||||
|
||||
Regardless of the import approach you take, the components will be tree-shaken by Rollup, so you don't have to worry about unused components being bundled into your app.
|
||||
To opt-out of TypeScript, you can use the `typescript` flag in your `components.json` file.
|
||||
|
||||
## New Project
|
||||
|
||||
<Steps>
|
||||
|
||||
### Create project
|
||||
|
||||
Use the Vue CLI to create a new project.
|
||||
|
||||
```bash
|
||||
npm create vue@latest
|
||||
```
|
||||
|
||||
### Add Tailwind and its configuration
|
||||
|
||||
Install `tailwindcss` and its peer dependencies, then generate your `tailwind.config.js` and `postcss.config.js` files:
|
||||
|
||||
```bash
|
||||
npm install -D tailwindcss postcss autoprefixer
|
||||
|
||||
npx tailwindcss init -p
|
||||
```
|
||||
|
||||
### Install dependencies
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### Run the CLI
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest init
|
||||
```
|
||||
|
||||
### Configure components.json
|
||||
|
||||
You will be asked a few questions to configure `components.json`:
|
||||
|
||||
```txt:line-numbers
|
||||
Would you like to use TypeScript (recommended)? no / yes
|
||||
Which framework are you using? Vite + Vue / Nuxt
|
||||
Which style would you like to use? › Default
|
||||
Which color would you like to use as base color? › Slate
|
||||
Where is your global CSS file? › › src/index.css
|
||||
Do you want to use CSS variables for colors? › no / yes
|
||||
Where is your tailwind.config.js located? › tailwind.config.js
|
||||
Configure the import alias for components: › @/components
|
||||
Configure the import alias for utils: › @/lib/utils
|
||||
Are you using React Server Components? › no / yes (no)
|
||||
```
|
||||
|
||||
### Edit tsconfig.json
|
||||
|
||||
By default your `tsconfig.json` for new project should be configured nicely. However, make sure the code below is added in the compilerOptions of your tsconfig.json so your app can resolve paths without error
|
||||
|
||||
```json
|
||||
```json {9} title="components.json"
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
"style": "default",
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "src/app/globals.css",
|
||||
"baseColor": "zinc",
|
||||
"cssVariables": true
|
||||
},
|
||||
"typescript": false,
|
||||
"aliases": {
|
||||
"utils": "~/lib/utils",
|
||||
"components": "~/components"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To configure import aliases, you can use the following `jsconfig.json`:
|
||||
|
||||
### That's it
|
||||
|
||||
You can now start adding components to your project.
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add button
|
||||
```
|
||||
|
||||
The command above will add the `Button` component to your project. You can then import it like this:
|
||||
|
||||
```vue {2,7}
|
||||
<script setup lang="ts">
|
||||
import { Button } from '@/components/ui/button'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Button>Click me</Button>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
</Steps>
|
||||
|
||||
```json {4} title="jsconfig.json"
|
||||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
149
apps/www/src/content/docs/installation/astro.md
Normal file
149
apps/www/src/content/docs/installation/astro.md
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
---
|
||||
title: Astro
|
||||
description: Install and configure Astro.
|
||||
---
|
||||
|
||||
<Steps>
|
||||
|
||||
### Create project
|
||||
|
||||
Start by creating a new Astro project:
|
||||
|
||||
```bash
|
||||
npm create astro@latest
|
||||
```
|
||||
|
||||
### Configure your Astro project
|
||||
|
||||
You will be asked a few questions to configure your project:
|
||||
|
||||
```txt showLineNumbers
|
||||
- Where should we create your new project?
|
||||
./your-app-name
|
||||
- How would you like to start your new project?
|
||||
Choose a starter template (or Empty)
|
||||
- Install dependencies?
|
||||
Yes
|
||||
- Do you plan to write TypeScript?
|
||||
Yes
|
||||
- How strict should TypeScript be?
|
||||
Strict
|
||||
- Initialize a new git repository? (optional)
|
||||
Yes/No
|
||||
```
|
||||
|
||||
### Add React to your project
|
||||
|
||||
Install React using the Astro CLI:
|
||||
|
||||
```bash
|
||||
npx astro add react
|
||||
```
|
||||
|
||||
<Callout className="mt-4">
|
||||
|
||||
Answer `Yes` to all the question prompted by the CLI when installing React.
|
||||
|
||||
</Callout>
|
||||
|
||||
### Add Tailwind CSS to your project
|
||||
|
||||
Install Tailwind CSS using the Astro CLI:
|
||||
|
||||
```bash
|
||||
npx astro add tailwind
|
||||
```
|
||||
|
||||
<Callout className="mt-4">
|
||||
|
||||
Answer `Yes` to all the question prompted by the CLI when installing Tailwind CSS.
|
||||
|
||||
</Callout>
|
||||
|
||||
### Edit tsconfig.json file
|
||||
|
||||
Add the code below to the tsconfig.json file to resolve paths:
|
||||
|
||||
```json {2-7} showLineNumbers
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Run the CLI
|
||||
|
||||
Run the `shadcn-ui` init command to setup your project:
|
||||
|
||||
```bash
|
||||
npx shadcn-ui@latest init
|
||||
```
|
||||
|
||||
### Configure components.json
|
||||
|
||||
You will be asked a few questions to configure `components.json`:
|
||||
|
||||
```txt showLineNumbers
|
||||
Would you like to use TypeScript (recommended)? no / yes
|
||||
Which style would you like to use? › Default
|
||||
Which color would you like to use as base color? › Slate
|
||||
Where is your global CSS file? › › ./src/styles/globals.css
|
||||
Do you want to use CSS variables for colors? › no / yes
|
||||
Where is your tailwind.config.js located? › tailwind.config.cjs
|
||||
Configure the import alias for components: › @/components
|
||||
Configure the import alias for utils: › @/lib/utils
|
||||
Are you using React Server Components? › no
|
||||
```
|
||||
|
||||
### Import the globals.css file
|
||||
|
||||
Import the `globals.css` file in the `src/index.astro` file:
|
||||
|
||||
```ts {2} showLineNumbers
|
||||
import '@/styles/globals.css'
|
||||
```
|
||||
|
||||
### Update astro tailwind config
|
||||
|
||||
To prevent serving the Tailwind base styles twice, we need to tell Astro not to apply the base styles, since we already include them in our own `globals.css` file. To do this, set the `applyBaseStyles` config option for the tailwind plugin in `astro.config.mjs` to `false`.
|
||||
|
||||
```ts {3-5} showLineNumbers
|
||||
export default defineConfig({
|
||||
integrations: [
|
||||
tailwind({
|
||||
applyBaseStyles: false,
|
||||
}),
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
### That's it
|
||||
|
||||
You can now start adding components to your project.
|
||||
|
||||
```bash
|
||||
npx shadcn-ui@latest add button
|
||||
```
|
||||
|
||||
The command above will add the `Button` component to your project. You can then import it like this:
|
||||
|
||||
```astro {2,10} showLineNumbers
|
||||
---
|
||||
import { Button } from "@/components/ui/button"
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Astro</title>
|
||||
</head>
|
||||
<body>
|
||||
<Button>Hello World</Button>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</Steps>
|
||||
153
apps/www/src/content/docs/installation/laravel.md
Normal file
153
apps/www/src/content/docs/installation/laravel.md
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
---
|
||||
title: Laravel
|
||||
description: Install and configure Laravel with Inertia
|
||||
---
|
||||
|
||||
<Steps>
|
||||
|
||||
### Create project
|
||||
|
||||
Start by creating a new Laravel project with Inertia and Vue using the Laravel installer `laravel new my-app`:
|
||||
|
||||
```bash
|
||||
laravel new my-app --typescript --breeze --stack=vue --git --no-interaction
|
||||
```
|
||||
|
||||
### Run the CLI
|
||||
|
||||
Run the `shadcn-vue` init command to setup your project:
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest init
|
||||
```
|
||||
|
||||
### Configure components.json
|
||||
|
||||
You will be asked a few questions to configure `components.json`:
|
||||
|
||||
```txt showLineNumbers
|
||||
Would you like to use TypeScript (recommended)? no / yes
|
||||
Which framework are you using? Vite / Nuxt / Laravel
|
||||
Which style would you like to use? › Default
|
||||
Which color would you like to use as base color? › Slate
|
||||
Where is your global CSS file? › resources/css/app.css
|
||||
Do you want to use CSS variables for colors? › no / yes
|
||||
Where is your tailwind.config.js located? › tailwind.config.js
|
||||
Configure the import alias for components: › @/Components
|
||||
Configure the import alias for utils: › @/lib/utils
|
||||
```
|
||||
|
||||
### Update tailwind.config.js
|
||||
|
||||
The `shadcn-vue` CLI will automatically overwrite your `tailwind.config.js`. Update it to look like this:
|
||||
|
||||
```js
|
||||
import forms from '@tailwindcss/forms'
|
||||
import defaultTheme from 'tailwindcss/defaultTheme'
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
darkMode: 'class',
|
||||
content: [
|
||||
'./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',
|
||||
'./storage/framework/views/*.php',
|
||||
'./resources/views/**/*.blade.php',
|
||||
'./resources/js/**/*.tsx',
|
||||
],
|
||||
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: '2rem',
|
||||
screens: {
|
||||
'2xl': '1400px',
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
border: 'hsl(var(--border))',
|
||||
input: 'hsl(var(--input))',
|
||||
ring: 'hsl(var(--ring))',
|
||||
background: 'hsl(var(--background))',
|
||||
foreground: 'hsl(var(--foreground))',
|
||||
primary: {
|
||||
DEFAULT: 'hsl(var(--primary))',
|
||||
foreground: 'hsl(var(--primary-foreground))',
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: 'hsl(var(--secondary))',
|
||||
foreground: 'hsl(var(--secondary-foreground))',
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: 'hsl(var(--destructive))',
|
||||
foreground: 'hsl(var(--destructive-foreground))',
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: 'hsl(var(--muted))',
|
||||
foreground: 'hsl(var(--muted-foreground))',
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: 'hsl(var(--accent))',
|
||||
foreground: 'hsl(var(--accent-foreground))',
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: 'hsl(var(--popover))',
|
||||
foreground: 'hsl(var(--popover-foreground))',
|
||||
},
|
||||
card: {
|
||||
DEFAULT: 'hsl(var(--card))',
|
||||
foreground: 'hsl(var(--card-foreground))',
|
||||
},
|
||||
},
|
||||
borderRadius: {
|
||||
lg: 'var(--radius)',
|
||||
md: 'calc(var(--radius) - 2px)',
|
||||
sm: 'calc(var(--radius) - 4px)',
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['Figtree', ...defaultTheme.fontFamily.sans],
|
||||
},
|
||||
keyframes: {
|
||||
'accordion-down': {
|
||||
from: { height: 0 },
|
||||
to: { height: 'var(--radix-accordion-content-height)' },
|
||||
},
|
||||
'accordion-up': {
|
||||
from: { height: 'var(--radix-accordion-content-height)' },
|
||||
to: { height: 0 },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
'accordion-down': 'accordion-down 0.2s ease-out',
|
||||
'accordion-up': 'accordion-up 0.2s ease-out',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
plugins: [forms, require('tailwindcss-animate')],
|
||||
}
|
||||
```
|
||||
|
||||
### That's it
|
||||
|
||||
You can now start adding components to your project.
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add button
|
||||
```
|
||||
|
||||
The command above will add the `Button` component to your project. You can then import it like this:
|
||||
|
||||
```vue {2,7}
|
||||
<script setup lang="ts">
|
||||
import { Button } from '@/Components/ui/button'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Button>Click me</Button>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
</Steps>
|
||||
124
apps/www/src/content/docs/installation/nuxt.md
Normal file
124
apps/www/src/content/docs/installation/nuxt.md
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
---
|
||||
title: Nuxt
|
||||
description: Install and configure Nuxt.
|
||||
---
|
||||
|
||||
<Steps>
|
||||
|
||||
### Create project
|
||||
|
||||
Start by creating a new Nuxt project using `create-next-app`:
|
||||
|
||||
```bash
|
||||
npx nuxi@latest init my-app
|
||||
```
|
||||
|
||||
### Install TailwindCSS module
|
||||
|
||||
```bash
|
||||
npm install -D @nuxtjs/tailwindcss
|
||||
```
|
||||
|
||||
### Configure `nuxt.config.ts`
|
||||
|
||||
```ts
|
||||
export default defineNuxtConfig({
|
||||
modules: ['@nuxtjs/tailwindcss'],
|
||||
components: [
|
||||
{
|
||||
path: '~/components/ui',
|
||||
// this is required else Nuxt will autoImport `.ts` file
|
||||
extensions: ['.vue'],
|
||||
// prefix for your components, eg: UiButton
|
||||
prefix: 'Ui'
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Run the CLI
|
||||
|
||||
Run the `shadcn-vue` init command to setup your project:
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest init
|
||||
```
|
||||
|
||||
### Configure components.json
|
||||
|
||||
You will be asked a few questions to configure `components.json`:
|
||||
|
||||
```txt showLineNumbers
|
||||
Would you like to use TypeScript (recommended)? no / yes
|
||||
Which framework are you using? Vite / Nuxt / Laravel
|
||||
Which style would you like to use? › Default
|
||||
Which color would you like to use as base color? › Slate
|
||||
Where is your global CSS file? › › src/index.css
|
||||
Do you want to use CSS variables for colors? › no / yes
|
||||
Where is your tailwind.config.js located? › tailwind.config.js
|
||||
Configure the import alias for components: › @/components
|
||||
Configure the import alias for utils: › @/lib/utils
|
||||
```
|
||||
|
||||
### App structure
|
||||
|
||||
Here's the default structure of Nuxt app. You can use this as a reference:
|
||||
|
||||
```txt {6-16,20-21}
|
||||
.
|
||||
├── pages
|
||||
│ ├── index.vue
|
||||
│ └── dashboard.vue
|
||||
├── components
|
||||
│ ├── ui
|
||||
│ │ ├── alert-dialog
|
||||
│ │ │ ├── AlertDialog.vue
|
||||
│ │ │ └── ...
|
||||
│ │ ├── button
|
||||
│ │ │ ├── Button.vue
|
||||
│ │ │ └── ...
|
||||
│ │ ├── dropdown-menu
|
||||
│ │ │ ├── Dropdown.vue
|
||||
│ │ │ └── ...
|
||||
│ │ └── ...
|
||||
│ ├── MainNav.vue
|
||||
│ ├── PageHeader.vue
|
||||
│ └── ...
|
||||
├── lib
|
||||
│ └── utils.ts
|
||||
├── assets
|
||||
│ ├── css
|
||||
│ │ └── tailwind.css
|
||||
├── app.vue
|
||||
├── nuxt.config.ts
|
||||
├── package.json
|
||||
├── tailwind.config.js
|
||||
└── tsconfig.json
|
||||
```
|
||||
|
||||
- I place the UI components in the `components/ui` folder.
|
||||
- The rest of the components such as `<PageHeader />` and `<MainNav />` are placed in the `components` folder.
|
||||
- The `lib` folder contains all the utility functions. I have a `utils.ts` where I define the `cn` helper.
|
||||
- The `assets/css` folder contains the global CSS.
|
||||
|
||||
### That's it
|
||||
|
||||
You can now start adding components to your project.
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add button
|
||||
```
|
||||
|
||||
The command above will add the `Button` component to your project. Nuxt autoImport will handle importing the components, you can just use it as such:
|
||||
|
||||
```vue {3}
|
||||
<template>
|
||||
<div>
|
||||
<UiButton>Click me</UiButton>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
</Steps>
|
||||
106
apps/www/src/content/docs/installation/vite.md
Normal file
106
apps/www/src/content/docs/installation/vite.md
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
---
|
||||
title: Vite
|
||||
description: Install and configure Vite.
|
||||
---
|
||||
|
||||
<Steps>
|
||||
|
||||
### Create project
|
||||
|
||||
Start by creating a new Vue project using `vite`:
|
||||
|
||||
```bash
|
||||
# npm 6.x
|
||||
npm create vite@latest my-vue-app --template vue
|
||||
|
||||
# npm 7+, extra double-dash is needed:
|
||||
npm create vite@latest my-vue-app -- --template vue
|
||||
```
|
||||
|
||||
### Add Tailwind and its configuration
|
||||
|
||||
Install `tailwindcss` and its peer dependencies, then generate your `tailwind.config.js` and `postcss.config.js` files:
|
||||
|
||||
```bash
|
||||
npm install -D tailwindcss postcss autoprefixer
|
||||
|
||||
npx tailwindcss init -p
|
||||
```
|
||||
|
||||
### Edit tsconfig.json
|
||||
|
||||
Add the code below to the compilerOptions of your tsconfig.json so your app can resolve paths without error
|
||||
|
||||
```typescript
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
```
|
||||
|
||||
### Update vite.config.ts
|
||||
|
||||
Add the code below to the vite.config.ts so your app can resolve paths without error
|
||||
|
||||
```typescript
|
||||
import path from "path"
|
||||
import vue from "@vitejs/plugin-vue"
|
||||
import { defineConfig } from "vite"
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### Run the CLI
|
||||
|
||||
Run the `shadcn-vue` init command to setup your project:
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest init
|
||||
```
|
||||
|
||||
### Configure components.json
|
||||
|
||||
You will be asked a few questions to configure `components.json`:
|
||||
|
||||
```txt showLineNumbers
|
||||
Would you like to use TypeScript (recommended)? no / yes
|
||||
Which framework are you using? Vite / Nuxt / Laravel
|
||||
Which style would you like to use? › Default
|
||||
Which color would you like to use as base color? › Slate
|
||||
Where is your global CSS file? › › src/index.css
|
||||
Do you want to use CSS variables for colors? › no / yes
|
||||
Where is your tailwind.config.js located? › tailwind.config.js
|
||||
Configure the import alias for components: › @/components
|
||||
Configure the import alias for utils: › @/lib/utils
|
||||
```
|
||||
|
||||
### That's it
|
||||
|
||||
You can now start adding components to your project.
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add button
|
||||
```
|
||||
|
||||
The command above will add the `Button` component to your project. You can then import it like this:
|
||||
|
||||
```vue {2,7}
|
||||
<script setup lang="ts">
|
||||
import { Button } from '@/components/ui/button'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Button>Click me</Button>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
</Steps>
|
||||
|
|
@ -17,7 +17,6 @@ To use utility classes for theming set `tailwind.cssVariables` to `false` in you
|
|||
```json {8} title="components.json"
|
||||
{
|
||||
"style": "default",
|
||||
"rsc": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "app/globals.css",
|
||||
|
|
@ -43,7 +42,6 @@ To use CSS variables for theming set `tailwind.cssVariables` to `true` in your `
|
|||
```json {8} title="components.json"
|
||||
{
|
||||
"style": "default",
|
||||
"rsc": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "app/globals.css",
|
||||
|
|
|
|||
|
|
@ -4,112 +4,56 @@ description: Styles for headings, paragraphs, lists...etc
|
|||
component: true
|
||||
---
|
||||
|
||||
<ComponentPreview name="TypographyDemo">
|
||||
|
||||
<div/>
|
||||
|
||||
</ComponentPreview>
|
||||
<ComponentPreview name="TypographyDemo" />
|
||||
|
||||
## h1
|
||||
|
||||
<ComponentPreview name="TypographyH1">
|
||||
|
||||
<div/>
|
||||
|
||||
</ComponentPreview>
|
||||
<ComponentPreview name="TypographyH1" />
|
||||
|
||||
## h2
|
||||
|
||||
<ComponentPreview name="TypographyH2">
|
||||
|
||||
<div/>
|
||||
|
||||
</ComponentPreview>
|
||||
<ComponentPreview name="TypographyH2" />
|
||||
|
||||
## h3
|
||||
|
||||
<ComponentPreview name="TypographyH3">
|
||||
|
||||
<div/>
|
||||
|
||||
</ComponentPreview>
|
||||
<ComponentPreview name="TypographyH3" />
|
||||
|
||||
## h4
|
||||
|
||||
<ComponentPreview name="TypographyH4">
|
||||
|
||||
<div/>
|
||||
|
||||
</ComponentPreview>
|
||||
<ComponentPreview name="TypographyH4" />
|
||||
|
||||
## p
|
||||
|
||||
<ComponentPreview name="TypographyP">
|
||||
|
||||
<div/>
|
||||
|
||||
</ComponentPreview>
|
||||
<ComponentPreview name="TypographyP" />
|
||||
|
||||
## blockquote
|
||||
|
||||
<ComponentPreview name="TypographyBlockquote">
|
||||
|
||||
<div/>
|
||||
|
||||
</ComponentPreview>
|
||||
<ComponentPreview name="TypographyBlockquote" />
|
||||
|
||||
## table
|
||||
|
||||
<ComponentPreview name="TypographyTable">
|
||||
|
||||
<div/>
|
||||
|
||||
</ComponentPreview>
|
||||
<ComponentPreview name="TypographyTable" />
|
||||
|
||||
## list
|
||||
|
||||
<ComponentPreview name="TypographyList">
|
||||
|
||||
<div/>
|
||||
|
||||
</ComponentPreview>
|
||||
<ComponentPreview name="TypographyList" />
|
||||
|
||||
## Inline code
|
||||
|
||||
<ComponentPreview name="TypographyInlineCode">
|
||||
|
||||
<div/>
|
||||
|
||||
</ComponentPreview>
|
||||
<ComponentPreview name="TypographyInlineCode" />
|
||||
|
||||
## Lead
|
||||
|
||||
<ComponentPreview name="TypographyLead">
|
||||
|
||||
<div/>
|
||||
|
||||
</ComponentPreview>
|
||||
<ComponentPreview name="TypographyLead" />
|
||||
|
||||
## Large
|
||||
|
||||
<ComponentPreview name="TypographyLarge">
|
||||
|
||||
<div/>
|
||||
|
||||
</ComponentPreview>
|
||||
<ComponentPreview name="TypographyLarge" />
|
||||
|
||||
## Small
|
||||
|
||||
<ComponentPreview name="TypographySmall">
|
||||
|
||||
<div/>
|
||||
|
||||
</ComponentPreview>
|
||||
<ComponentPreview name="TypographySmall" />
|
||||
|
||||
## Muted
|
||||
|
||||
<ComponentPreview name="TypographyMuted">
|
||||
|
||||
<div/>
|
||||
|
||||
</ComponentPreview>
|
||||
<ComponentPreview name="TypographyMuted" />
|
||||
5
apps/www/src/content/examples/forms/account.md
Normal file
5
apps/www/src/content/examples/forms/account.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<script setup>
|
||||
import AccountExample from "@/examples/forms/Account.vue"
|
||||
</script>
|
||||
|
||||
<AccountExample />
|
||||
5
apps/www/src/content/examples/forms/appearance.md
Normal file
5
apps/www/src/content/examples/forms/appearance.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<script setup>
|
||||
import AppearanceExample from "@/examples/forms/Appearance.vue"
|
||||
</script>
|
||||
|
||||
<AppearanceExample />
|
||||
5
apps/www/src/content/examples/forms/display.md
Normal file
5
apps/www/src/content/examples/forms/display.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<script setup>
|
||||
import DisplayExample from "@/examples/forms/Display.vue"
|
||||
</script>
|
||||
|
||||
<DisplayExample />
|
||||
5
apps/www/src/content/examples/forms/forms.md
Normal file
5
apps/www/src/content/examples/forms/forms.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<script setup>
|
||||
import FormsExample from "@/examples/forms/Example.vue"
|
||||
</script>
|
||||
|
||||
<FormsExample />
|
||||
5
apps/www/src/content/examples/forms/notifications.md
Normal file
5
apps/www/src/content/examples/forms/notifications.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<script setup>
|
||||
import NotificationsExample from "@/examples/forms/Notifications.vue"
|
||||
</script>
|
||||
|
||||
<NotificationsExample />
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import ChevronDownIcon from '~icons/radix-icons/chevron-down'
|
||||
|
||||
import {
|
||||
|
|
@ -14,12 +15,16 @@ import {
|
|||
CardHeader,
|
||||
CardTitle,
|
||||
} from '@/lib/registry/new-york/ui/card'
|
||||
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '@/lib/registry/new-york/ui/command'
|
||||
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/lib/registry/new-york/ui/popover'
|
||||
|
||||
const sofiaRole = ref('Owner')
|
||||
const jacksonRole = ref('Member')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -49,43 +54,43 @@ import {
|
|||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="outline" class="ml-auto">
|
||||
Owner
|
||||
{{ sofiaRole }}
|
||||
<ChevronDownIcon class="ml-2 h-4 w-4 text-muted-foreground" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="p-0" align="end">
|
||||
<!-- <Command>
|
||||
<CommandInput placeholder="Select new role..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No roles found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
<CommandItem class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Viewer</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Can view and comment.
|
||||
</p>
|
||||
</CommandItem>
|
||||
<CommandItem class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Developer</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Can view, comment and edit.
|
||||
</p>
|
||||
</CommandItem>
|
||||
<CommandItem class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Billing</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Can view, comment and manage billing.
|
||||
</p>
|
||||
</CommandItem>
|
||||
<CommandItem class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Owner</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Admin-level access to all resources.
|
||||
</p>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command> -->
|
||||
<Command v-model="sofiaRole">
|
||||
<CommandInput placeholder="Select new role..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No roles found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
<CommandItem value="Viewer" class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Viewer</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Can view and comment.
|
||||
</p>
|
||||
</CommandItem>
|
||||
<CommandItem value="Developer" class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Developer</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Can view, comment and edit.
|
||||
</p>
|
||||
</CommandItem>
|
||||
<CommandItem value="Billing" class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Billing</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Can view, comment and manage billing.
|
||||
</p>
|
||||
</CommandItem>
|
||||
<CommandItem value="Owner" class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Owner</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Admin-level access to all resources.
|
||||
</p>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
|
|
@ -107,43 +112,43 @@ import {
|
|||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="outline" class="ml-auto">
|
||||
Member
|
||||
{{ jacksonRole }}
|
||||
<ChevronDownIcon class="ml-2 h-4 w-4 text-muted-foreground" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="p-0" align="end">
|
||||
<!-- <Command>
|
||||
<CommandInput placeholder="Select new role..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No roles found.</CommandEmpty>
|
||||
<CommandGroup class="p-1.5">
|
||||
<CommandItem class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Viewer</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Can view and comment.
|
||||
</p>
|
||||
</CommandItem>
|
||||
<CommandItem class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Developer</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Can view, comment and edit.
|
||||
</p>
|
||||
</CommandItem>
|
||||
<CommandItem class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Billing</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Can view, comment and manage billing.
|
||||
</p>
|
||||
</CommandItem>
|
||||
<CommandItem class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Owner</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Admin-level access to all resources.
|
||||
</p>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command> -->
|
||||
<Command v-model="jacksonRole">
|
||||
<CommandInput placeholder="Select new role..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No roles found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
<CommandItem value="Viewer" class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Viewer</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Can view and comment.
|
||||
</p>
|
||||
</CommandItem>
|
||||
<CommandItem value="Developer" class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Developer</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Can view, comment and edit.
|
||||
</p>
|
||||
</CommandItem>
|
||||
<CommandItem value="Billing" class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Billing</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Can view, comment and manage billing.
|
||||
</p>
|
||||
</CommandItem>
|
||||
<CommandItem value="Owner" class="teamaspace-y-1 flex flex-col items-start px-4 py-2">
|
||||
<p>Owner</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Admin-level access to all resources.
|
||||
</p>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import CaretSortIcon from '~icons/radix-icons/caret-sort'
|
||||
import CheckIcon from '~icons/radix-icons/check'
|
||||
import PlusCircledIcon from '~icons/radix-icons/plus-circled'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import {
|
||||
|
|
@ -17,7 +19,9 @@ import {
|
|||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@/lib/registry/new-york/ui/dialog'
|
||||
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator } from '@/lib/registry/new-york/ui/command'
|
||||
import { Input } from '@/lib/registry/new-york/ui/input'
|
||||
import { Label } from '@/lib/registry/new-york/ui/label'
|
||||
import {
|
||||
|
|
@ -88,60 +92,58 @@ const selectedTeam = ref<Team>(groups[0].teams[0])
|
|||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-[200px] p-0">
|
||||
<!-- <Command>
|
||||
<CommandList>
|
||||
<CommandInput placeholder="Search team..." />
|
||||
<CommandEmpty>No team found.</CommandEmpty>
|
||||
{groups.map((group) => (
|
||||
<CommandGroup key={group.label} heading={group.label}>
|
||||
{group.teams.map((team) => (
|
||||
<CommandItem
|
||||
key={team.value}
|
||||
onSelect={() => {
|
||||
setSelectedTeam(team)
|
||||
setOpen(false)
|
||||
}}
|
||||
class="text-sm"
|
||||
>
|
||||
<Avatar class="mr-2 h-5 w-5">
|
||||
<AvatarImage
|
||||
src={`https://avatar.vercel.sh/${team.value}.png`}
|
||||
alt={team.label}
|
||||
class="grayscale"
|
||||
/>
|
||||
<AvatarFallback>SC</AvatarFallback>
|
||||
</Avatar>
|
||||
{team.label}
|
||||
<CheckIcon
|
||||
class={cn(
|
||||
"ml-auto h-4 w-4",
|
||||
selectedTeam.value === team.value
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
)}
|
||||
/>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
))}
|
||||
</CommandList>
|
||||
<CommandSeparator />
|
||||
<CommandList>
|
||||
<CommandGroup>
|
||||
<DialogTrigger asChild>
|
||||
<CommandItem
|
||||
onSelect={() => {
|
||||
setOpen(false)
|
||||
setShowNewTeamDialog(true)
|
||||
}}
|
||||
>
|
||||
<PlusCircledIcon class="mr-2 h-5 w-5" />
|
||||
Create Team
|
||||
</CommandItem>
|
||||
</DialogTrigger>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command> -->
|
||||
<Command :filter-function="(list, term) => list.filter(i => i.label?.toLowerCase()?.includes(term)) ">
|
||||
<CommandList>
|
||||
<CommandInput placeholder="Search team..." />
|
||||
<CommandEmpty>No team found.</CommandEmpty>
|
||||
<CommandGroup v-for="group in groups" :key="group.label" :heading="group.label">
|
||||
<CommandItem
|
||||
v-for="team in group.teams"
|
||||
:key="team.value"
|
||||
:value="team"
|
||||
class="text-sm"
|
||||
@select="() => {
|
||||
selectedTeam = team
|
||||
open = false
|
||||
}"
|
||||
>
|
||||
<Avatar class="mr-2 h-5 w-5">
|
||||
<AvatarImage
|
||||
:src="`https://avatar.vercel.sh/${team.value}.png`"
|
||||
:alt="team.label"
|
||||
class="grayscale"
|
||||
/>
|
||||
<AvatarFallback>SC</AvatarFallback>
|
||||
</Avatar>
|
||||
{{ team.label }}
|
||||
<CheckIcon
|
||||
:class="cn('ml-auto h-4 w-4',
|
||||
selectedTeam.value === team.value
|
||||
? 'opacity-100'
|
||||
: 'opacity-0',
|
||||
)"
|
||||
/>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
<CommandSeparator />
|
||||
<CommandList>
|
||||
<CommandGroup>
|
||||
<DialogTrigger as-child>
|
||||
<CommandItem
|
||||
:value="{ label: 'Create Team' }"
|
||||
@select="() => {
|
||||
open = false
|
||||
showNewTeamDialog = true
|
||||
}"
|
||||
>
|
||||
<PlusCircledIcon class="mr-2 h-5 w-5" />
|
||||
Create Team
|
||||
</CommandItem>
|
||||
</DialogTrigger>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<DialogContent>
|
||||
|
|
|
|||
10
apps/www/src/examples/forms/Account.vue
Normal file
10
apps/www/src/examples/forms/Account.vue
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import FormsLayout from './layouts/FormsLayout.vue'
|
||||
import AccountForm from './components/AccountForm.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FormsLayout>
|
||||
<AccountForm />
|
||||
</FormsLayout>
|
||||
</template>
|
||||
10
apps/www/src/examples/forms/Appearance.vue
Normal file
10
apps/www/src/examples/forms/Appearance.vue
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import FormsLayout from './layouts/FormsLayout.vue'
|
||||
import AppearanceForm from './components/AppearanceForm.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FormsLayout>
|
||||
<AppearanceForm />
|
||||
</FormsLayout>
|
||||
</template>
|
||||
10
apps/www/src/examples/forms/Display.vue
Normal file
10
apps/www/src/examples/forms/Display.vue
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import FormsLayout from './layouts/FormsLayout.vue'
|
||||
import DisplayForm from './components/DisplayForm.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FormsLayout>
|
||||
<DisplayForm />
|
||||
</FormsLayout>
|
||||
</template>
|
||||
10
apps/www/src/examples/forms/Example.vue
Normal file
10
apps/www/src/examples/forms/Example.vue
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import FormsLayout from './layouts/FormsLayout.vue'
|
||||
import ProfileForm from './components/ProfileForm.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FormsLayout>
|
||||
<ProfileForm />
|
||||
</FormsLayout>
|
||||
</template>
|
||||
10
apps/www/src/examples/forms/Notifications.vue
Normal file
10
apps/www/src/examples/forms/Notifications.vue
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import FormsLayout from './layouts/FormsLayout.vue'
|
||||
import NotificationsForm from './components/NotificationsForm.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FormsLayout>
|
||||
<NotificationsForm />
|
||||
</FormsLayout>
|
||||
</template>
|
||||
158
apps/www/src/examples/forms/components/AccountForm.vue
Normal file
158
apps/www/src/examples/forms/components/AccountForm.vue
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import * as z from 'zod'
|
||||
import { format } from 'date-fns'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
import RadixIconsCalendar from '~icons/radix-icons/calendar'
|
||||
|
||||
import { Input } from '@/lib/registry/new-york/ui/input'
|
||||
import { Label } from '@/lib/registry/new-york/ui/label'
|
||||
import { Separator } from '@/lib/registry/new-york/ui/separator'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/lib/registry/new-york/ui/select'
|
||||
import { Button } from '@/lib/registry/new-york/ui/button'
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/lib/registry/default/ui/popover'
|
||||
import { Calendar } from '@/lib/registry/new-york/ui/calendar'
|
||||
|
||||
const accountForm = ref({
|
||||
name: '',
|
||||
dob: null,
|
||||
language: '',
|
||||
})
|
||||
|
||||
const languages = [
|
||||
{ label: 'English', value: 'en' },
|
||||
{ label: 'French', value: 'fr' },
|
||||
{ label: 'German', value: 'de' },
|
||||
{ label: 'Spanish', value: 'es' },
|
||||
{ label: 'Portuguese', value: 'pt' },
|
||||
{ label: 'Russian', value: 'ru' },
|
||||
{ label: 'Japanese', value: 'ja' },
|
||||
{ label: 'Korean', value: 'ko' },
|
||||
{ label: 'Chinese', value: 'zh' },
|
||||
] as const
|
||||
|
||||
const accountFormSchema = z.object({
|
||||
name: z
|
||||
.string()
|
||||
.min(2, {
|
||||
message: 'Name must be at least 2 characters.',
|
||||
})
|
||||
.max(30, {
|
||||
message: 'Name must not be longer than 30 characters.',
|
||||
}),
|
||||
dob: z.date({
|
||||
required_error: 'A date of birth is required.',
|
||||
}),
|
||||
language: z.string().nonempty({
|
||||
message: 'Please select a language.',
|
||||
}),
|
||||
})
|
||||
|
||||
type AccountFormValues = z.infer<typeof accountFormSchema>
|
||||
const errors = ref<z.ZodFormattedError<AccountFormValues> | null>(null)
|
||||
|
||||
async function handleSubmit() {
|
||||
const result = accountFormSchema.safeParse(accountForm.value)
|
||||
if (!result.success) {
|
||||
errors.value = result.error.format()
|
||||
console.log(errors.value)
|
||||
return
|
||||
}
|
||||
|
||||
console.log('Form submitted!', accountForm.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h3 class="text-lg font-medium">
|
||||
Account
|
||||
</h3>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Update your account settings. Set your preferred language and timezone.
|
||||
</p>
|
||||
</div>
|
||||
<Separator />
|
||||
<form class="space-y-8" @submit.prevent="handleSubmit">
|
||||
<div class="grid gap-2">
|
||||
<Label for="name" :class="cn('text-sm', errors?.name && 'text-destructive')">
|
||||
Name
|
||||
</Label>
|
||||
<Input id="name" v-model="accountForm.name" placeholder="Your name" />
|
||||
<span class="text-muted-foreground text-sm">
|
||||
This is the name that will be displayed on your profile and in emails.
|
||||
</span>
|
||||
<div v-if="errors?.name" class="text-sm text-destructive">
|
||||
<span v-for="error in errors.name._errors" :key="error">{{ error }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="dob" :class="cn('text-sm', errors?.dob && 'text-destructive')">
|
||||
Date of Birth
|
||||
</Label>
|
||||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
<Button
|
||||
variant="outline"
|
||||
:class="cn(
|
||||
'w-[280px] pl-3 text-left font-normal',
|
||||
!accountForm.dob && 'text-muted-foreground',
|
||||
)"
|
||||
>
|
||||
<span>{{ accountForm.dob ? format(accountForm.dob, "PPP") : "Pick a date" }}</span>
|
||||
<RadixIconsCalendar class="ml-auto h-4 w-4 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="p-0">
|
||||
<Calendar v-model="accountForm.dob" />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<span class="text-muted-foreground text-sm">
|
||||
Your date of birth is used to calculate your age.
|
||||
</span>
|
||||
<div v-if="errors?.dob" class="text-sm text-destructive">
|
||||
<span v-for="error in errors.dob._errors" :key="error">{{ error }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="language" :class="cn('text-sm', errors?.language && 'text-destructive')">
|
||||
Language
|
||||
</Label>
|
||||
<Select id="language" v-model="accountForm.language">
|
||||
<SelectTrigger class="w-[200px]">
|
||||
<SelectValue placeholder="Select a language" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem v-for="language in languages" :key="language.value" :value="language.value">
|
||||
{{ language.label }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span class="text-muted-foreground text-sm">
|
||||
This is the language that will be used in the dashboard.
|
||||
</span>
|
||||
<div v-if="errors?.language" class="text-sm text-destructive">
|
||||
<span v-for="error in errors.language._errors" :key="error">{{ error }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-start">
|
||||
<Button type="submit">
|
||||
Update account
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
169
apps/www/src/examples/forms/components/AppearanceForm.vue
Normal file
169
apps/www/src/examples/forms/components/AppearanceForm.vue
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import * as z from 'zod'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
import { Label } from '@/lib/registry/new-york/ui/label'
|
||||
import { Separator } from '@/lib/registry/new-york/ui/separator'
|
||||
import { RadioGroup, RadioGroupItem } from '@/lib/registry/default/ui/radio-group'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/lib/registry/new-york/ui/select'
|
||||
import { Button } from '@/lib/registry/new-york/ui/button'
|
||||
|
||||
const appearenceForm = ref({
|
||||
theme: 'light',
|
||||
font: '',
|
||||
})
|
||||
|
||||
const appearanceFormSchema = z.object({
|
||||
theme: z.enum(['light', 'dark'], {
|
||||
required_error: 'Please select a theme.',
|
||||
}),
|
||||
font: z.enum(['inter', 'manrope', 'system'], {
|
||||
invalid_type_error: 'Select a font',
|
||||
required_error: 'Please select a font.',
|
||||
}),
|
||||
})
|
||||
|
||||
type AppearanceFormValues = z.infer<typeof appearanceFormSchema>
|
||||
const errors = ref<z.ZodFormattedError<AppearanceFormValues> | null>(null)
|
||||
|
||||
async function handleSubmit() {
|
||||
const result = appearanceFormSchema.safeParse(appearenceForm.value)
|
||||
if (!result.success) {
|
||||
errors.value = result.error.format()
|
||||
console.log(errors.value)
|
||||
return
|
||||
}
|
||||
|
||||
console.log('Form submitted!', appearenceForm.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h3 class="text-lg font-medium">
|
||||
Appearence
|
||||
</h3>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Customize the appearance of the app. Automatically switch between day and night themes.
|
||||
</p>
|
||||
</div>
|
||||
<Separator />
|
||||
<form class="space-y-8" @submit.prevent="handleSubmit">
|
||||
<div class="grid gap-2">
|
||||
<Label for="font" :class="cn('text-sm', errors?.font && 'text-destructive')">
|
||||
Font
|
||||
</Label>
|
||||
<Select id="font" v-model="appearenceForm.font">
|
||||
<SelectTrigger class="w-[200px]">
|
||||
<SelectValue placeholder="Select a font" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="inter">
|
||||
Inter
|
||||
</SelectItem>
|
||||
<SelectItem value="manrope">
|
||||
Manrope
|
||||
</SelectItem>
|
||||
<SelectItem value="system">
|
||||
System
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span class="text-muted-foreground text-xs">
|
||||
Set the font you want to use in the dashboard.
|
||||
</span>
|
||||
<div v-if="errors?.font" class="text-sm text-destructive">
|
||||
<span v-for="error in errors.font._errors" :key="error">{{ error }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="theme" :class="cn('text-sm', errors?.theme && 'text-destructive')">
|
||||
Theme
|
||||
</Label>
|
||||
<span class="text-muted-foreground text-xs">
|
||||
Select the theme for the dashboard.
|
||||
</span>
|
||||
<RadioGroup
|
||||
v-model="appearenceForm.theme"
|
||||
default-value="light"
|
||||
class="grid max-w-md grid-cols-2 gap-8 pt-2"
|
||||
>
|
||||
<div class="grid gap-2">
|
||||
<Label class="[&:has([data-state=checked])>div]:border-primary">
|
||||
<div>
|
||||
<RadioGroupItem value="light" class="sr-only" />
|
||||
</div>
|
||||
<div class="items-center rounded-md border-2 border-muted p-1 hover:border-accent">
|
||||
<div class="space-y-2 rounded-sm bg-[#ecedef] p-2">
|
||||
<div class="space-y-2 rounded-md bg-white p-2 shadow-sm">
|
||||
<div class="h-2 w-[80px] rounded-lg bg-[#ecedef]" />
|
||||
<div class="h-2 w-[100px] rounded-lg bg-[#ecedef]" />
|
||||
</div>
|
||||
<div class="flex items-center space-x-2 rounded-md bg-white p-2 shadow-sm">
|
||||
<div class="h-4 w-4 rounded-full bg-[#ecedef]" />
|
||||
<div class="h-2 w-[100px] rounded-lg bg-[#ecedef]" />
|
||||
</div>
|
||||
<div class="flex items-center space-x-2 rounded-md bg-white p-2 shadow-sm">
|
||||
<div class="h-4 w-4 rounded-full bg-[#ecedef]" />
|
||||
<div class="h-2 w-[100px] rounded-lg bg-[#ecedef]" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="block w-full p-2 text-center font-normal">
|
||||
Light
|
||||
</span>
|
||||
</Label>
|
||||
</div>
|
||||
<div>
|
||||
<Label class="[&:has([data-state=checked])>div]:border-primary">
|
||||
<div>
|
||||
<RadioGroupItem value="dark" class="sr-only" />
|
||||
</div>
|
||||
<div class="items-center rounded-md border-2 border-muted bg-popover p-1 hover:bg-accent hover:text-accent-foreground">
|
||||
<div class="space-y-2 rounded-sm bg-slate-950 p-2">
|
||||
<div class="space-y-2 rounded-md bg-slate-800 p-2 shadow-sm">
|
||||
<div class="h-2 w-[80px] rounded-lg bg-slate-400" />
|
||||
<div class="h-2 w-[100px] rounded-lg bg-slate-400" />
|
||||
</div>
|
||||
<div class="flex items-center space-x-2 rounded-md bg-slate-800 p-2 shadow-sm">
|
||||
<div class="h-4 w-4 rounded-full bg-slate-400" />
|
||||
<div class="h-2 w-[100px] rounded-lg bg-slate-400" />
|
||||
</div>
|
||||
<div class="flex items-center space-x-2 rounded-md bg-slate-800 p-2 shadow-sm">
|
||||
<div class="h-4 w-4 rounded-full bg-slate-400" />
|
||||
<div class="h-2 w-[100px] rounded-lg bg-slate-400" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="block w-full p-2 text-center font-normal">
|
||||
Dark
|
||||
</span>
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2">
|
||||
<span v-if="errors?.theme" class="text-sm text-destructive">
|
||||
<span v-for="error in errors.theme._errors" :key="error">{{ error }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-start">
|
||||
<Button type="submit">
|
||||
Update preferences
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
98
apps/www/src/examples/forms/components/DisplayForm.vue
Normal file
98
apps/www/src/examples/forms/components/DisplayForm.vue
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import * as z from 'zod'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
import { Label } from '@/lib/registry/new-york/ui/label'
|
||||
import { Separator } from '@/lib/registry/new-york/ui/separator'
|
||||
import { Checkbox } from '@/lib/registry/new-york/ui/checkbox'
|
||||
import { Button } from '@/lib/registry/new-york/ui/button'
|
||||
|
||||
const displayForm = ref({
|
||||
items: ['recents', 'home'],
|
||||
})
|
||||
|
||||
const items = [
|
||||
{
|
||||
id: 'recents',
|
||||
label: 'Recents',
|
||||
},
|
||||
{
|
||||
id: 'home',
|
||||
label: 'Home',
|
||||
},
|
||||
{
|
||||
id: 'applications',
|
||||
label: 'Applications',
|
||||
|
||||
},
|
||||
{
|
||||
id: 'desktop',
|
||||
label: 'Desktop',
|
||||
|
||||
},
|
||||
{
|
||||
id: 'downloads',
|
||||
label: 'Downloads',
|
||||
|
||||
},
|
||||
{
|
||||
id: 'documents',
|
||||
label: 'Documents',
|
||||
|
||||
},
|
||||
] as const
|
||||
|
||||
const displayFormSchema = z.object({
|
||||
items: z.array(z.string()).refine(value => value.some(item => item), {
|
||||
message: 'You have to select at least one item.',
|
||||
}),
|
||||
})
|
||||
|
||||
type DisplayFormValues = z.infer<typeof displayFormSchema>
|
||||
const errors = ref<z.ZodFormattedError<DisplayFormValues> | null>(null)
|
||||
|
||||
async function handleSubmit() {
|
||||
const result = displayFormSchema.safeParse(displayForm.value)
|
||||
if (!result.success) {
|
||||
errors.value = result.error.format()
|
||||
console.log(errors.value)
|
||||
return
|
||||
}
|
||||
|
||||
console.log('Form submitted!', displayForm.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h3 class="text-lg font-medium">
|
||||
Display
|
||||
</h3>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Turn items on or off to control what's displayed in the app.
|
||||
</p>
|
||||
</div>
|
||||
<Separator />
|
||||
<form @submit.prevent="handleSubmit">
|
||||
<div class="mb-4">
|
||||
<Label for="sidebar" :class="cn('text-md', errors?.items && 'text-destructive')">
|
||||
Sidebar
|
||||
</Label>
|
||||
<span class="text-xs text-muted-foreground">
|
||||
Select the items you want to display in the sidebar.
|
||||
</span>
|
||||
</div>
|
||||
<div v-for="item in items" :key="item.id" class="pb-1">
|
||||
<div class="flex flex-row items-center space-x-3 space-y-0">
|
||||
<Checkbox :id="item.id" :checked="displayForm.items.includes(item.id)" @change="displayForm.items.includes(item.id) ? displayForm.items.splice(displayForm.items.indexOf(item.id), 1) : displayForm.items.push(item.id)" />
|
||||
<Label :for="item.id">{{ item.label }}</Label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-start mt-4">
|
||||
<Button type="submit">
|
||||
Update display
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
176
apps/www/src/examples/forms/components/NotificationsForm.vue
Normal file
176
apps/www/src/examples/forms/components/NotificationsForm.vue
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import * as z from 'zod'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
import { Label } from '@/lib/registry/new-york/ui/label'
|
||||
import { Separator } from '@/lib/registry/new-york/ui/separator'
|
||||
import { RadioGroup, RadioGroupItem } from '@/lib/registry/new-york/ui/radio-group'
|
||||
import { Switch } from '@/lib/registry/new-york/ui/switch'
|
||||
import { Checkbox } from '@/lib/registry/new-york/ui/checkbox'
|
||||
import { Button } from '@/lib/registry/new-york/ui/button'
|
||||
|
||||
const notificationsForm = ref({
|
||||
type: '',
|
||||
mobile: false,
|
||||
communication_emails: false,
|
||||
social_emails: true,
|
||||
marketing_emails: false,
|
||||
security_emails: true,
|
||||
})
|
||||
|
||||
const notificationsFormSchema = z.object({
|
||||
type: z.enum(['all', 'mentions', 'none'], {
|
||||
required_error: 'You need to select a notification type.',
|
||||
}),
|
||||
mobile: z.boolean().default(false).optional(),
|
||||
communication_emails: z.boolean().default(false).optional(),
|
||||
social_emails: z.boolean().default(false).optional(),
|
||||
marketing_emails: z.boolean().default(false).optional(),
|
||||
security_emails: z.boolean(),
|
||||
})
|
||||
|
||||
type notificationsFormValues = z.infer<typeof notificationsFormSchema>
|
||||
const errors = ref<z.ZodFormattedError<notificationsFormValues> | null>(null)
|
||||
|
||||
async function handleSubmit() {
|
||||
const result = notificationsFormSchema.safeParse(notificationsForm.value)
|
||||
if (!result.success) {
|
||||
errors.value = result.error.format()
|
||||
console.log(errors.value)
|
||||
return
|
||||
}
|
||||
|
||||
console.log('Form submitted!', notificationsForm.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h3 class="text-lg font-medium">
|
||||
Notifications
|
||||
</h3>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Configure how you receive notifications.
|
||||
</p>
|
||||
</div>
|
||||
<Separator />
|
||||
<form class="space-y-8" @submit.prevent="handleSubmit">
|
||||
<div class="grid gap-2">
|
||||
<Label for="font" :class="cn('text-sm', errors?.type && 'text-destructive')">
|
||||
Notify me about...
|
||||
</Label>
|
||||
<RadioGroup
|
||||
v-model="notificationsForm.type"
|
||||
default-value="all"
|
||||
class="flex flex-col space-y-1"
|
||||
>
|
||||
<div class="flex items-center space-x-3 space-y-0">
|
||||
<RadioGroupItem id="all" value="all" />
|
||||
<Label for="all">All new messages</Label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-3 space-y-0">
|
||||
<RadioGroupItem id="mentions" value="mentions" />
|
||||
<Label for="mentions">Direct messages and mentions</Label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-3 space-y-0">
|
||||
<RadioGroupItem id="none" value="none" />
|
||||
<Label for="none">Nothing</Label>
|
||||
</div>
|
||||
<div v-if="errors?.type" class="text-sm text-destructive">
|
||||
<span v-for="error in errors.type._errors" :key="error">{{ error }}</span>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<h3 class="mb-4 text-lg font-medium">
|
||||
Email Notifications
|
||||
</h3>
|
||||
<div class="space-y-4">
|
||||
<div class="flex flex-row items-center justify-between rounded-lg border p-4">
|
||||
<div class="space-y-0.5">
|
||||
<Label class="text-base" for="communication_emails">
|
||||
Communication emails
|
||||
</Label>
|
||||
<span class="text-xs text-muted-foreground">
|
||||
Receive emails about your account activity.
|
||||
</span>
|
||||
</div>
|
||||
<Switch
|
||||
id="communication_emails"
|
||||
v-model:checked="notificationsForm.communication_emails"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row items-center justify-between rounded-lg border p-4">
|
||||
<div class="space-y-0.5">
|
||||
<Label class="text-base" for="marketing_emails">
|
||||
Marketing emails
|
||||
</Label>
|
||||
<span class="text-xs text-muted-foreground">
|
||||
Receive emails about new products, features, and more.
|
||||
</span>
|
||||
</div>
|
||||
<Switch
|
||||
id="marketing_emails"
|
||||
v-model:checked="notificationsForm.marketing_emails"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-row items-center justify-between rounded-lg border p-4">
|
||||
<div class="space-y-0.5">
|
||||
<Label class="text-base" for="social_emails">
|
||||
Social emails
|
||||
</Label>
|
||||
<span class="text-xs text-muted-foreground">
|
||||
Receive emails for friend requests, follows, and more.
|
||||
</span>
|
||||
</div>
|
||||
<Switch
|
||||
id="social_emails"
|
||||
v-model:checked="notificationsForm.social_emails"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row items-center justify-between rounded-lg border p-4">
|
||||
<div class="space-y-0.5">
|
||||
<Label class="text-base" for="security_emails">
|
||||
Security emails
|
||||
</Label>
|
||||
<span class="text-xs text-muted-foreground">
|
||||
Receive emails about your account activity and security.
|
||||
</span>
|
||||
</div>
|
||||
<Switch
|
||||
id="security_emails"
|
||||
v-model:checked="notificationsForm.security_emails"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<div class="flex flex-row items-start space-x-3 space-y-0">
|
||||
<Checkbox
|
||||
id="mobile"
|
||||
v-model:checked="notificationsForm.mobile"
|
||||
/>
|
||||
<div>
|
||||
<Label for="mobile">
|
||||
Use different settings for my mobile devices
|
||||
</Label>
|
||||
<span class="text-xs text-muted-foreground">
|
||||
You can manage your mobile notifications in the {{ " " }}
|
||||
<a href="/examples/forms">mobile settings</a> page.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-start">
|
||||
<Button type="submit">
|
||||
Update notifications
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
152
apps/www/src/examples/forms/components/ProfileForm.vue
Normal file
152
apps/www/src/examples/forms/components/ProfileForm.vue
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import * as z from 'zod'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
import { Input } from '@/lib/registry/new-york/ui/input'
|
||||
import { Label } from '@/lib/registry/new-york/ui/label'
|
||||
import { Separator } from '@/lib/registry/new-york/ui/separator'
|
||||
import { Textarea } from '@/lib/registry/new-york/ui/textarea'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/lib/registry/new-york/ui/select'
|
||||
import { Button } from '@/lib/registry/new-york/ui/button'
|
||||
|
||||
const verifiedEmails = ref(['m@example.com', 'm@google.com', 'm@support.com'])
|
||||
|
||||
const profileForm = ref({
|
||||
username: '',
|
||||
email: '',
|
||||
bio: 'I own a computer.',
|
||||
urls: [
|
||||
{ value: 'https://shadcn.com' },
|
||||
{ value: 'http://twitter.com/shadcn' },
|
||||
],
|
||||
})
|
||||
|
||||
const profileFormSchema = z.object({
|
||||
username: z
|
||||
.string()
|
||||
.min(2, {
|
||||
message: 'Username must be at least 2 characters.',
|
||||
})
|
||||
.max(30, {
|
||||
message: 'Username must not be longer than 30 characters.',
|
||||
}),
|
||||
email: z
|
||||
.string({
|
||||
required_error: 'Please select an email to display.',
|
||||
})
|
||||
.email(),
|
||||
bio: z.string().max(160, { message: 'Bio must not be longer than 160 characters.' }).min(4, { message: 'Bio must be at least 2 characters.' }),
|
||||
urls: z
|
||||
.array(
|
||||
z.object({
|
||||
value: z.string().url({ message: 'Please enter a valid URL.' }),
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
})
|
||||
|
||||
type ProfileFormValues = z.infer<typeof profileFormSchema>
|
||||
const errors = ref<z.ZodFormattedError<ProfileFormValues> | null>(null)
|
||||
|
||||
async function handleSubmit() {
|
||||
const result = profileFormSchema.safeParse(profileForm.value)
|
||||
if (!result.success) {
|
||||
errors.value = result.error.format()
|
||||
return
|
||||
}
|
||||
errors.value = null
|
||||
console.log('Form submitted!')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h3 class="text-lg font-medium">
|
||||
Profile
|
||||
</h3>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
This is how others will see you on the site.
|
||||
</p>
|
||||
</div>
|
||||
<Separator />
|
||||
<form class="space-y-8" @submit.prevent="handleSubmit">
|
||||
<div class="grid gap-2">
|
||||
<Label for="username" :class="cn('text-sm', errors?.username && 'text-destructive')">
|
||||
Username
|
||||
</Label>
|
||||
<Input id="username" v-model="profileForm.username" placeholder="shadcn" />
|
||||
<span class="text-muted-foreground text-sm">
|
||||
This is your public display name. It can be your real name or a pseudonym. You can only change this once every 30 days.
|
||||
</span>
|
||||
<div v-if="errors?.username" class="text-sm text-destructive">
|
||||
<span v-for="error in errors.username._errors" :key="error">{{ error }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="email" :class="cn('text-sm', errors?.email && 'text-destructive')">
|
||||
Email
|
||||
</Label>
|
||||
<Select id="email" v-model="profileForm.email">
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select an email" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem v-for="email in verifiedEmails" :key="email" :value="email">
|
||||
{{ email }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span class="text-muted-foreground text-sm">
|
||||
You can manage verified email addresses in your email settings.
|
||||
</span>
|
||||
<div v-if="errors?.email" class="text-sm text-destructive">
|
||||
<span v-for="error in errors.email._errors" :key="error">{{ error }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="bio" :class="cn('text-sm', errors?.bio && 'text-destructive')">
|
||||
Bio
|
||||
</Label>
|
||||
<Textarea id="bio" v-model="profileForm.bio" placeholder="Tell us about yourself." />
|
||||
<span class="text-muted-foreground text-sm">
|
||||
You can @mention other users and organizations to link to them.
|
||||
</span>
|
||||
<div v-if="errors?.bio" class="text-sm text-destructive">
|
||||
<span v-for="error in errors.bio._errors" :key="error">{{ error }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="urls" :class="cn('text-sm', errors?.urls && 'text-destructive')">
|
||||
URLs
|
||||
</Label>
|
||||
<Input v-for="(url, index) in profileForm.urls" id="urls" :key="index" v-model="url.value" />
|
||||
<div v-if="errors?.urls" class="text-sm text-destructive">
|
||||
<span v-for="error in errors.urls._errors" :key="error">{{ error }}</span>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="text-xs w-20 mt-2"
|
||||
@click="profileForm.urls?.push({ value: '' })"
|
||||
>
|
||||
Add URL
|
||||
</Button>
|
||||
</div>
|
||||
<div class="flex justify-start">
|
||||
<Button type="submit">
|
||||
Update profile
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
53
apps/www/src/examples/forms/components/SidebarNav.vue
Normal file
53
apps/www/src/examples/forms/components/SidebarNav.vue
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<script setup lang="ts">
|
||||
import { useRoute } from 'vitepress'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Button } from '@/lib/registry/new-york/ui/button'
|
||||
|
||||
interface Item {
|
||||
title: string
|
||||
href: string
|
||||
}
|
||||
|
||||
const $route = useRoute()
|
||||
|
||||
const sidebarNavItems: Item[] = [
|
||||
{
|
||||
title: 'Profile',
|
||||
href: '/examples/forms/forms',
|
||||
},
|
||||
{
|
||||
title: 'Account',
|
||||
href: '/examples/forms/account',
|
||||
},
|
||||
{
|
||||
title: 'Appearance',
|
||||
href: '/examples/forms/appearance',
|
||||
},
|
||||
{
|
||||
title: 'Notifications',
|
||||
href: '/examples/forms/notifications',
|
||||
},
|
||||
{
|
||||
title: 'Display',
|
||||
href: '/examples/forms/display',
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="flex space-x-2 lg:flex-col lg:space-x-0 lg:space-y-1">
|
||||
<Button
|
||||
v-for="item in sidebarNavItems"
|
||||
:key="item.title"
|
||||
as="a"
|
||||
:href="item.href"
|
||||
variant="ghost"
|
||||
:class="cn(
|
||||
'w-full text-left justify-start',
|
||||
$route.path === `${item.href}.html` && 'bg-muted hover:bg-muted',
|
||||
)"
|
||||
>
|
||||
{{ item.title }}
|
||||
</Button>
|
||||
</nav>
|
||||
</template>
|
||||
38
apps/www/src/examples/forms/layouts/FormsLayout.vue
Normal file
38
apps/www/src/examples/forms/layouts/FormsLayout.vue
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<script setup lang="ts">
|
||||
import SidebarNav from '../components/SidebarNav.vue'
|
||||
import { Separator } from '@/lib/registry/new-york/ui/separator'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="md:hidden">
|
||||
<VPImage
|
||||
alt="Forms"
|
||||
width="1280"
|
||||
height="1214" class="block" :image="{
|
||||
dark: '/examples/forms-dark.png',
|
||||
light: '/examples/forms-light.png',
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
<div class="hidden space-y-6 p-10 pb-16 md:block">
|
||||
<div class="space-y-0.5">
|
||||
<h2 class="text-2xl font-bold tracking-tight">
|
||||
Settings
|
||||
</h2>
|
||||
<p class="text-muted-foreground">
|
||||
Manage your account settings and set e-mail preferences.
|
||||
</p>
|
||||
</div>
|
||||
<Separator class="my-6" />
|
||||
<div class="flex flex-col space-y-8 lg:flex-row lg:space-x-12 lg:space-y-0">
|
||||
<aside class="-mx-4 lg:w-1/5">
|
||||
<SidebarNav />
|
||||
</aside>
|
||||
<div class="flex-1 lg:max-w-2xl">
|
||||
<div class="space-y-6">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -1,12 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import type { Column } from '@tanstack/vue-table'
|
||||
import type { Component } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { type Task } from '../data/schema'
|
||||
import PlusCircledIcon from '~icons/radix-icons/plus-circled'
|
||||
import CheckIcon from '~icons/radix-icons/check'
|
||||
|
||||
import { Badge } from '@/lib/registry/new-york/ui/badge'
|
||||
import { Button } from '@/lib/registry/new-york/ui/button'
|
||||
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator } from '@/lib/registry/new-york/ui/command'
|
||||
|
||||
import {
|
||||
Popover,
|
||||
|
|
@ -14,6 +16,7 @@ import {
|
|||
PopoverTrigger,
|
||||
} from '@/lib/registry/new-york/ui/popover'
|
||||
import { Separator } from '@/lib/registry/new-york/ui/separator'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface DataTableFacetedFilter {
|
||||
column?: Column<Task, any>
|
||||
|
|
@ -70,66 +73,63 @@ const selectedValues = computed(() => new Set(props.column?.getFilterValue() as
|
|||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-[200px] p-0" align="start">
|
||||
<!-- <Command>
|
||||
<CommandInput placeholder={title} />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{options.map((option) => {
|
||||
<Command
|
||||
:filter-function="(list: DataTableFacetedFilter['options'], term) => list.filter(i => i.label.toLowerCase()?.includes(term)) "
|
||||
>
|
||||
<CommandInput :placeholder="title" />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
v-for="option in options"
|
||||
:key="option.value"
|
||||
:value="option"
|
||||
@select="() => {
|
||||
const isSelected = selectedValues.has(option.value)
|
||||
return (
|
||||
<CommandItem
|
||||
key={option.value}
|
||||
onSelect={() => {
|
||||
if (isSelected) {
|
||||
selectedValues.delete(option.value)
|
||||
} else {
|
||||
selectedValues.add(option.value)
|
||||
}
|
||||
const filterValues = Array.from(selectedValues)
|
||||
column?.setFilterValue(
|
||||
filterValues.length ? filterValues : undefined
|
||||
)
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class={cn(
|
||||
"mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",
|
||||
isSelected
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "opacity-50 [&_svg]:invisible"
|
||||
)}
|
||||
>
|
||||
<CheckIcon class={cn("h-4 w-4")} />
|
||||
</div>
|
||||
{option.icon && (
|
||||
<option.icon class="mr-2 h-4 w-4 text-muted-foreground" />
|
||||
)}
|
||||
<span>{option.label}</span>
|
||||
{facets?.get(option.value) && (
|
||||
<span class="ml-auto flex h-4 w-4 items-center justify-center font-mono text-xs">
|
||||
{facets.get(option.value)}
|
||||
</span>
|
||||
)}
|
||||
</CommandItem>
|
||||
if (isSelected) {
|
||||
selectedValues.delete(option.value)
|
||||
}
|
||||
else {
|
||||
selectedValues.add(option.value)
|
||||
}
|
||||
const filterValues = Array.from(selectedValues)
|
||||
column?.setFilterValue(
|
||||
filterValues.length ? filterValues : undefined,
|
||||
)
|
||||
})}
|
||||
}"
|
||||
>
|
||||
<div
|
||||
:class="cn(
|
||||
'mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary',
|
||||
selectedValues.has(option.value)
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'opacity-50 [&_svg]:invisible',
|
||||
)"
|
||||
>
|
||||
<CheckIcon :class="cn('h-4 w-4')" />
|
||||
</div>
|
||||
<option.icon v-if="option.icon" class="mr-2 h-4 w-4 text-muted-foreground" />
|
||||
<span>{{ option.label }}</span>
|
||||
<span v-if="facets?.get(option.value)" class="ml-auto flex h-4 w-4 items-center justify-center font-mono text-xs">
|
||||
{{ facets.get(option.value) }}
|
||||
</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
|
||||
<template v-if="selectedValues.size > 0">
|
||||
<CommandSeparator />
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
:value="{ label: 'Clear filters' }"
|
||||
class="justify-center text-center"
|
||||
@select="column?.setFilterValue(undefined)"
|
||||
>
|
||||
Clear filters
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
{selectedValues.size > 0 && (
|
||||
<>
|
||||
<CommandSeparator />
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
onSelect={() => column?.setFilterValue(undefined)}
|
||||
class="justify-center text-center"
|
||||
>
|
||||
Clear filters
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</>
|
||||
)}
|
||||
</CommandList>
|
||||
</Command> -->
|
||||
</template>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</template>
|
||||
|
|
|
|||
100
apps/www/src/lib/registry/default/example/Cards/ActivityGoal.vue
Normal file
100
apps/www/src/lib/registry/default/example/Cards/ActivityGoal.vue
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { Button } from '@/lib/registry/default/ui/button'
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from '@/lib/registry/default/ui/card'
|
||||
import { themes } from '@/lib/registry/themes'
|
||||
import { useConfigStore } from '@/stores/config'
|
||||
|
||||
const { theme, radius, setRadius, setTheme } = useConfigStore()
|
||||
|
||||
const goal = ref(350)
|
||||
|
||||
const data = [
|
||||
{ goal: 400 },
|
||||
{ goal: 300 },
|
||||
{ goal: 200 },
|
||||
{ goal: 300 },
|
||||
{ goal: 200 },
|
||||
{ goal: 278 },
|
||||
{ goal: 189 },
|
||||
{ goal: 239 },
|
||||
{ goal: 300 },
|
||||
{ goal: 200 },
|
||||
{ goal: 278 },
|
||||
{ goal: 189 },
|
||||
{ goal: 349 },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Card>
|
||||
<CardHeader class-name="pb-4">
|
||||
<CardTitle class-name="text-base">
|
||||
Move Goal
|
||||
</CardTitle>
|
||||
<CardDescription>Set your daily activity goal.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent class-name="pb-2">
|
||||
<div className="flex items-center justify-center space-x-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class-name="h-8 w-8 shrink-0 rounded-full"
|
||||
:disabled="goal <= 200"
|
||||
@click="goal -= 10"
|
||||
>
|
||||
<Minus class-name="h-4 w-4" />
|
||||
<span className="sr-only">Decrease</span>
|
||||
</Button>
|
||||
<div className="flex-1 text-center">
|
||||
<div className="text-5xl font-bold tracking-tighter">
|
||||
{{ goal }}
|
||||
</div>
|
||||
<div className="text-[0.70rem] uppercase text-muted-foreground">
|
||||
Calories/day
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
class-name="h-8 w-8 shrink-0 rounded-full"
|
||||
:disabled="goal >= 400"
|
||||
@click="goal += 10 "
|
||||
>
|
||||
<Plus class-name="h-4 w-4" />
|
||||
<span className="sr-only">Increase</span>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="my-3 h-[60px]">
|
||||
<!-- <ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart data="{data}">
|
||||
<Bar
|
||||
data-key="goal"
|
||||
style="{"
|
||||
{
|
||||
fill: "var(--theme-primary)",
|
||||
opacity: 0.2,
|
||||
"--theme-primary": `hsl(${
|
||||
theme?.cssVars[mode="==" "dark" ? "dark" : "light"].primary
|
||||
})`,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
/>
|
||||
</BarChart>
|
||||
</ResponsiveContainer> -->
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button class-name="w-full">
|
||||
Set Goal
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</template>
|
||||
125
apps/www/src/lib/registry/default/example/Cards/index.vue
Normal file
125
apps/www/src/lib/registry/default/example/Cards/index.vue
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ChevronDown, Minus, Plus, Send } from 'lucide-vue-next'
|
||||
import { addDays, startOfToday } from 'date-fns'
|
||||
import {
|
||||
months,
|
||||
payments,
|
||||
roles,
|
||||
teamMembers,
|
||||
years,
|
||||
} from './utils/data'
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from '@/lib/registry/default/ui/card'
|
||||
import {
|
||||
Avatar,
|
||||
AvatarFallback,
|
||||
AvatarImage,
|
||||
} from '@/lib/registry/default/ui/avatar'
|
||||
import { Button } from '@/lib/registry/default/ui/button'
|
||||
import { Textarea } from '@/lib/registry/default/ui/textarea'
|
||||
import { Calendar } from '@/lib/registry/default/ui/calendar'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/lib/registry/default/ui/dropdown-menu'
|
||||
import { Label } from '@/lib/registry/default/ui/label'
|
||||
import { Switch } from '@/lib/registry/default/ui/switch'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/lib/registry/default/ui/select'
|
||||
import { Input } from '@/lib/registry/default/ui/input'
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from '@/lib/registry/default/ui/tooltip'
|
||||
import { Separator } from '@/lib/registry/default/ui/separator'
|
||||
import RadixIconsGithubLogo from '~icons/radix-icons/github-logo'
|
||||
import RiGoogleLine from '~icons/ri/google-line'
|
||||
|
||||
const strictlyNecessarySwitch = ref<boolean>(true)
|
||||
const functionalCookiesSwitch = ref<boolean>(false)
|
||||
const performanceCookiesSwitch = ref<boolean>(false)
|
||||
const selectedArea = ref('Billing')
|
||||
const selectedSecurity = ref('Medium')
|
||||
const selectedMonth = ref<string>(months[0])
|
||||
const selectedYear = ref<string>(years[0])
|
||||
const selectedPayment = ref(payments[0])
|
||||
const goal = ref(350)
|
||||
|
||||
function switchPayment(payment: any) {
|
||||
selectedPayment.value = payment
|
||||
}
|
||||
|
||||
const range = ref({
|
||||
start: startOfToday(),
|
||||
end: addDays(startOfToday(), 8),
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div className="md:grids-col-2 grid md:gap-4 lg:grid-cols-10 xl:grid-cols-11 xl:gap-4">
|
||||
<div className="space-y-4 lg:col-span-4 xl:col-span-6 xl:space-y-4">
|
||||
<CardsStats />
|
||||
<div className="grid gap-1 sm:grid-cols-[280px_1fr] md:hidden">
|
||||
<CardsCalendar />
|
||||
<div className="pt-3 sm:pl-2 sm:pt-0 xl:pl-4">
|
||||
<CardsActivityGoal />
|
||||
</div>
|
||||
<div className="pt-3 sm:col-span-2 xl:pt-4">
|
||||
<CardsMetric />
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2">
|
||||
<div className="space-y-4 xl:space-y-4">
|
||||
<CardsTeamMembers />
|
||||
<CardsCookieSettings />
|
||||
<CardsPaymentMethod />
|
||||
</div>
|
||||
<div className="space-y-4 xl:space-y-4">
|
||||
<CardsChat />
|
||||
<CardsCreateAccount />
|
||||
<div className="hidden xl:block">
|
||||
<CardsReportIssue />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-4 lg:col-span-6 xl:col-span-5 xl:space-y-4">
|
||||
<div className="hidden gap-1 sm:grid-cols-[280px_1fr] md:grid">
|
||||
<CardsCalendar />
|
||||
<div className="pt-3 sm:pl-2 sm:pt-0 xl:pl-3">
|
||||
<CardsActivityGoal />
|
||||
</div>
|
||||
<div className="pt-3 sm:col-span-2 xl:pt-3">
|
||||
<CardsMetric />
|
||||
</div>
|
||||
</div>
|
||||
<div className="hidden md:block">
|
||||
<CardsDataTable />
|
||||
</div>
|
||||
<CardsShare />
|
||||
<div className="xl:hidden">
|
||||
<CardsReportIssue />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<script setup lang="ts">
|
||||
import { Checkbox } from '@/lib/registry/default/ui/checkbox'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div className="items-top flex space-x-2">
|
||||
<Checkbox id="terms1" disabled />
|
||||
<div className="grid gap-1.5 leading-none">
|
||||
<label
|
||||
htmlFor="terms1"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Accept terms and conditions
|
||||
</label>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
You agree to our Terms of Service and Privacy Policy.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
70
apps/www/src/lib/registry/default/example/ComboboxDemo.vue
Normal file
70
apps/www/src/lib/registry/default/example/ComboboxDemo.vue
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<script setup lang="ts">
|
||||
import { Check, ChevronsUpDown } from 'lucide-vue-next'
|
||||
|
||||
import { ref } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Button } from '@/lib/registry/default/ui/button'
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
} from '@/lib/registry/default/ui/command'
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/lib/registry/default/ui/popover'
|
||||
|
||||
const frameworks = [
|
||||
{ value: 'next.js', label: 'Next.js' },
|
||||
{ value: 'sveltekit', label: 'SvelteKit' },
|
||||
{ value: 'nuxt.js', label: 'Nuxt.js' },
|
||||
{ value: 'remix', label: 'Remix' },
|
||||
{ value: 'astro', label: 'Astro' },
|
||||
]
|
||||
|
||||
const open = ref(false)
|
||||
const value = ref<typeof frameworks[number]>()
|
||||
|
||||
const filterFunction = (list: typeof frameworks, search: string) => list.filter(i => i.value.toLowerCase().includes(search.toLowerCase()))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Popover v-model:open="open">
|
||||
<PopoverTrigger as-child>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
:aria-expanded="open"
|
||||
class="w-[200px] justify-between"
|
||||
>
|
||||
{{ value ? value.label : 'Select framework...' }}
|
||||
<ChevronsUpDown class="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-[200px] p-0">
|
||||
<Command v-model="value" :filter-function="filterFunction">
|
||||
<CommandInput placeholder="Search framework..." />
|
||||
<CommandEmpty>No framework found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
v-for="framework in frameworks"
|
||||
:key="framework.value"
|
||||
:value="framework"
|
||||
@select="open = false"
|
||||
>
|
||||
<Check
|
||||
:class="cn(
|
||||
'mr-2 h-4 w-4',
|
||||
value?.value === framework.value ? 'opacity-100' : 'opacity-0',
|
||||
)"
|
||||
/>
|
||||
{{ framework.label }}
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</template>
|
||||
62
apps/www/src/lib/registry/default/example/CommandDemo.vue
Normal file
62
apps/www/src/lib/registry/default/example/CommandDemo.vue
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<script setup lang="ts">
|
||||
import {
|
||||
Calculator,
|
||||
Calendar,
|
||||
CreditCard,
|
||||
Settings,
|
||||
Smile,
|
||||
User,
|
||||
} from 'lucide-vue-next'
|
||||
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
CommandShortcut,
|
||||
} from '@/lib/registry/default/ui/command'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Command class="rounded-lg border shadow-md max-w-[450px]">
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup heading="Suggestions">
|
||||
<CommandItem value="Calendar">
|
||||
<Calendar class="mr-2 h-4 w-4" />
|
||||
<span>Calendar</span>
|
||||
</CommandItem>
|
||||
<CommandItem value="Search Emoji">
|
||||
<Smile class="mr-2 h-4 w-4" />
|
||||
<span>Search Emoji</span>
|
||||
</CommandItem>
|
||||
<CommandItem value="Calculator">
|
||||
<Calculator class="mr-2 h-4 w-4" />
|
||||
<span>Calculator</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Settings">
|
||||
<CommandItem value="Profile">
|
||||
<User class="mr-2 h-4 w-4" />
|
||||
<span>Profile</span>
|
||||
<CommandShortcut>⌘P</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem value="Billing">
|
||||
<CreditCard class="mr-2 h-4 w-4" />
|
||||
<span>Billing</span>
|
||||
<CommandShortcut>⌘B</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem value="Settings">
|
||||
<Settings class="mr-2 h-4 w-4" />
|
||||
<span>Settings</span>
|
||||
<CommandShortcut>⌘S</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</template>
|
||||
|
|
@ -103,7 +103,7 @@ const columns: ColumnDef<Payment>[] = [
|
|||
return h(Button, {
|
||||
variant: 'ghost',
|
||||
onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'),
|
||||
}, ['Email', h(ArrowUpDown, { class: 'ml-2 h-4 w-4' })])
|
||||
}, () => ['Email', h(ArrowUpDown, { class: 'ml-2 h-4 w-4' })])
|
||||
},
|
||||
cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email')),
|
||||
},
|
||||
|
|
@ -128,9 +128,9 @@ const columns: ColumnDef<Payment>[] = [
|
|||
cell: ({ row }) => {
|
||||
const payment = row.original
|
||||
|
||||
return h(DropdownAction, {
|
||||
return h('div', { class: 'relative' }, h(DropdownAction, {
|
||||
payment,
|
||||
})
|
||||
}))
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
@ -162,7 +162,7 @@ const table = useVueTable({
|
|||
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<div class="flex items-center py-4">
|
||||
<div class="flex gap-2 items-center py-4">
|
||||
<Input
|
||||
class="max-w-sm"
|
||||
placeholder="Filter emails..."
|
||||
|
|
@ -244,7 +244,6 @@ const table = useVueTable({
|
|||
:disabled="!table.getCanNextPage()"
|
||||
@click="table.nextPage()"
|
||||
>
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Slider } from '@/lib/registry/default/ui/slider'
|
||||
|
||||
const modelValue = [50]
|
||||
const modelValue = ref([50])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
21
apps/www/src/lib/registry/default/ui/command/Command.vue
Normal file
21
apps/www/src/lib/registry/default/ui/command/Command.vue
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<script setup lang="ts">
|
||||
import type { ComboboxRootEmits, ComboboxRootProps } from 'radix-vue'
|
||||
import { ComboboxRoot } from 'radix-vue'
|
||||
import { cn, useEmitAsProps } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<ComboboxRootProps>()
|
||||
const emits = defineEmits<ComboboxRootEmits>()
|
||||
|
||||
const emitsAsProps = useEmitAsProps(emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ComboboxRoot
|
||||
v-bind="{ ...props, ...emitsAsProps }"
|
||||
:open="true"
|
||||
:model-value="''"
|
||||
:class="cn('flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground', $attrs.class ?? '')"
|
||||
>
|
||||
<slot />
|
||||
</ComboboxRoot>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<script setup lang="ts">
|
||||
import type { DialogRootEmits, DialogRootProps } from 'radix-vue'
|
||||
import Command from './Command.vue'
|
||||
import { Dialog, DialogContent } from '@/lib/registry/default/ui/dialog'
|
||||
import { useEmitAsProps } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<DialogRootProps>()
|
||||
const emits = defineEmits<DialogRootEmits>()
|
||||
|
||||
const emitsAsProps = useEmitAsProps(emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-bind="{ ...props, ...emitsAsProps }">
|
||||
<DialogContent class="overflow-hidden p-0 shadow-lg">
|
||||
<Command class="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
||||
<slot />
|
||||
</Command>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user