feat: improve component preview components

This commit is contained in:
zernonia 2023-09-04 22:36:40 +08:00
parent a0f2f0a37f
commit 77b96ccbd7
45 changed files with 238 additions and 213 deletions

View File

@ -1,6 +1,7 @@
import path from 'node:path' import path from 'node:path'
import { defineConfig } from 'vitepress' import { defineConfig } from 'vitepress'
import Icons from 'unplugin-icons/vite' import Icons from 'unplugin-icons/vite'
import ComponentPreviewPlugin from './theme/plugins/previewer'
// https://vitepress.dev/reference/site-config // https://vitepress.dev/reference/site-config
export default defineConfig({ export default defineConfig({
@ -9,6 +10,9 @@ export default defineConfig({
srcDir: path.resolve(__dirname, '../src/content'), srcDir: path.resolve(__dirname, '../src/content'),
markdown: { markdown: {
theme: 'css-variables', theme: 'css-variables',
config(md) {
md.use(ComponentPreviewPlugin)
},
}, },
vite: { vite: {
plugins: [ plugins: [

View File

@ -7,6 +7,8 @@ import { cn } from '@/lib/utils'
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
name: string name: string
align?: 'center' | 'start' | 'end' align?: 'center' | 'start' | 'end'
sfcTsCode?: string
sfcTsHtml?: string
}>(), { align: 'center' }) }>(), { align: 'center' })
const Component = defineAsyncComponent({ const Component = defineAsyncComponent({
@ -17,7 +19,9 @@ const Component = defineAsyncComponent({
</script> </script>
<template> <template>
<div class="not-docs group relative my-4 flex flex-col space-y-2"> <div
class="not-docs group relative my-4 flex flex-col space-y-2"
>
<Tabs default-value="preview" class="relative mr-auto w-full"> <Tabs default-value="preview" class="relative mr-auto w-full">
<div class="flex items-center justify-between pb-3"> <div class="flex items-center justify-between pb-3">
<TabsList class="w-full justify-start rounded-none border-b bg-transparent p-0"> <TabsList class="w-full justify-start rounded-none border-b bg-transparent p-0">
@ -47,7 +51,8 @@ const Component = defineAsyncComponent({
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="code"> <TabsContent value="code">
<slot /> <div v-if="sfcTsHtml" class="language-vue" style="flex: 1;" v-html="decodeURIComponent(sfcTsHtml)" />
<slot v-else />
</TabsContent> </TabsContent>
</Tabs> </Tabs>
</div> </div>

View File

@ -0,0 +1,39 @@
import { dirname, resolve } from 'node:path'
import fs from 'node:fs'
import type { MarkdownEnv, MarkdownRenderer } from 'vitepress'
import { generateDemoComponent, parseProps } from './utils'
export default function (md: MarkdownRenderer) {
function addRenderRule(type: string) {
const defaultRender = md.renderer.rules[type]
md.renderer.rules[type] = (tokens, idx, options, env, self) => {
const token = tokens[idx]
const content = token.content.trim()
if (!content.match(/^<ComponentPreview\s/) || !content.endsWith('/>'))
return defaultRender!(tokens, idx, options, env, self)
const { path } = env as MarkdownEnv
const props = parseProps(content)
const { name, attrs } = props
const pluginPath = dirname(__dirname)
const srcPath = resolve(pluginPath, '../../src/lib/registry/default/examples/', `${name}.vue`).replace(/\\/g, '/')
if (!fs.existsSync(srcPath)) {
console.error(`rendering ${path}: ${srcPath} does not exist`)
return defaultRender!(tokens, idx, options, env, self)
}
const demoScripts = generateDemoComponent(md, env, {
attrs,
props,
code: fs.readFileSync(srcPath, 'utf-8'),
path: srcPath,
})
return demoScripts
}
}
addRenderRule('html_block')
addRenderRule('html_inline')
}

View File

@ -0,0 +1,71 @@
// Credit to @hairyf https://github.com/hairyf/markdown-it-vitepress-demo
import type { MarkdownEnv, MarkdownRenderer } from 'vitepress'
import { baseParse } from '@vue/compiler-core'
import type { AttributeNode, ElementNode } from '@vue/compiler-core'
export interface GenerateOptions {
attrs?: string
props: Record<string, any>
path: string
code: string
}
export function parse(
md: MarkdownRenderer,
env: MarkdownEnv,
{ code, attrs: _attrs, props }: GenerateOptions,
) {
const highlightedHtml = md.options.highlight!(code, 'vue', _attrs || '')
const sfcTsHtml = highlightedHtml
const attrs
= `sfcTsCode="${encodeURIComponent(code)}"\n`
+ `sfcTsHtml="${encodeURIComponent(sfcTsHtml)}"\n`
+ `v-bind='${JSON.stringify(props)}'\n`
return {
attrs,
highlightedHtml,
sfcTsCode: code,
sfcTsHtml,
}
}
export function generateDemoComponent(
md: MarkdownRenderer,
env: MarkdownEnv,
options: GenerateOptions,
) {
const { attrs } = parse(md, env, options)
return `<ComponentPreview \n${attrs}></ComponentPreview>`.trim()
}
export function isUndefined(v: any): v is undefined {
return v === undefined || v === null
}
function getPropsMap(attrs: any[]) {
const map: Record<string, any> = {}
for (const { name, value, exp, arg } of attrs) {
if (name === 'bind') {
if (!isUndefined(arg?.content))
map[arg.content] = JSON.parse(exp.content)
continue
}
if (isUndefined(value?.content) || value?.content === '')
map[name] = true
else if (['true', 'false'].includes(value?.content || ''))
map[name] = value?.content === 'true'
else
map[name] = value?.content
}
return map
}
export function parseProps(content: string) {
const ast = baseParse(content)
const demoElement = ast.children[0] as ElementNode
return getPropsMap(demoElement.props as AttributeNode[])
}

View File

@ -30,6 +30,7 @@
"@iconify/vue": "^4.1.1", "@iconify/vue": "^4.1.1",
"@types/node": "^20.5.7", "@types/node": "^20.5.7",
"@vitejs/plugin-vue": "^4.1.0", "@vitejs/plugin-vue": "^4.1.0",
"@vue/compiler-core": "^3.3.4",
"autoprefixer": "^10.4.14", "autoprefixer": "^10.4.14",
"postcss": "^8.4.24", "postcss": "^8.4.24",
"radix-vue": "^0.1.29", "radix-vue": "^0.1.29",

View File

@ -42,11 +42,7 @@ The style for your components. **This cannot be changed after initialization.**
} }
``` ```
<ComponentPreview name="card-with-form"> <ComponentPreview name="CardWithForm" />
<div />
</ComponentPreview>
## tailwind ## tailwind

View File

@ -6,11 +6,7 @@ primitive: https://www.radix-vue.com/components/accordion.html
--- ---
<ComponentPreview name="AccordionDemo" class="[&_.accordion]:sm:max-w-[70%]"> <ComponentPreview name="AccordionDemo" class="[&_.accordion]:sm:max-w-[70%]" />
<<< ../../../lib/registry/default/examples/AccordionDemo.vue
</ComponentPreview>

View File

@ -4,22 +4,19 @@ description: A modal dialog that interrupts the user with important content and
source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/registry/default/ui/alert-dialog source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/registry/default/ui/alert-dialog
primitive: https://www.radix-vue.com/components/alert-dialog.html primitive: https://www.radix-vue.com/components/alert-dialog.html
--- ---
<ComponentPreview name="AlertDialogDemo" > <ComponentPreview name="AlertDialogDemo" />
<<< ../../../lib/registry/default/examples/AlertDialogDemo.vue
</ComponentPreview>
## Installation ## Installation
```bash ```bash
npx shadcn-vue@latest add alert-dialog npx shadcn-vue@latest add alert-dialog
``` ```
<ManualInstall> <ManualInstall>
1. Install `radix-vue`: 1. Install `radix-vue`:

View File

@ -4,11 +4,7 @@ description: Displays a callout for user attention.
--- ---
<ComponentPreview name="AlertDemo" > <ComponentPreview name="AlertDemo" />
<<< ../../../lib/registry/default/examples/AlertDemo.vue
</ComponentPreview>

View File

@ -6,13 +6,7 @@ primitive: https://www.radix-vue.com/components/aspect-ratio.html
--- ---
<ComponentPreview name="AspectRatioDemo" > <ComponentPreview name="AspectRatioDemo" />
<<< ../../../lib/registry/default/examples/AspectRatioDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -6,12 +6,7 @@ primitive: https://www.radix-vue.com/components/avatar.html
--- ---
<ComponentPreview name="AvatarDemo" > <ComponentPreview name="AvatarDemo" />
<<< ../../../lib/registry/default/examples/AvatarDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -4,12 +4,7 @@ description: Displays a badge or a component that looks like a badge.
--- ---
<ComponentPreview name="BadgeDemo" > <ComponentPreview name="BadgeDemo" />
<<< ../../../lib/registry/default/examples/BadgeDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -4,13 +4,7 @@ description: Displays a button or a component that looks like a button.
--- ---
<ComponentPreview name="ButtonDemo" > <ComponentPreview name="ButtonDemo" />
<<< ../../../lib/registry/default/examples/ButtonDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -4,11 +4,7 @@ description: A date field component that allows users to enter and edit date.
--- ---
<ComponentPreview name="CalendarDemo" > <ComponentPreview name="CalendarDemo" />
<<< ../../../lib/registry/default/examples/CalendarDemo.vue
</ComponentPreview>
## About ## About

View File

@ -4,12 +4,7 @@ description: Displays a card with header, content, and footer.
--- ---
<ComponentPreview name="CardDemo" > <ComponentPreview name="CardDemo" />
<<< ../../../lib/registry/default/examples/CardDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -6,12 +6,7 @@ primitive: https://www.radix-vue.com/components/checkbox.html
--- ---
<ComponentPreview name="CheckboxDemo" > <ComponentPreview name="CheckboxDemo" />
<<< ../../../lib/registry/default/examples/CheckboxDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -6,11 +6,7 @@ primitive: https://www.radix-vue.com/components/collapsible.html
--- ---
<ComponentPreview name="CollapsibleDemo" > <ComponentPreview name="CollapsibleDemo" />
<<< ../../../lib/registry/default/examples/CollapsibleDemo.vue
</ComponentPreview>

View File

@ -6,11 +6,7 @@ primitive: https://www.radix-vue.com/components/context-menu.html
--- ---
<ComponentPreview name="ContextMenuDemo" > <ComponentPreview name="ContextMenuDemo" />
<<< ../../../lib/registry/default/examples/ContextMenuDemo.vue
</ComponentPreview>

View File

@ -4,11 +4,7 @@ description: A date picker component with range and presets.
--- ---
<ComponentPreview name="DatePickerDemo" > <ComponentPreview name="DatePickerDemo" />
<<< ../../../lib/registry/default/examples/DatePickerDemo.vue
</ComponentPreview>
## Installation ## Installation
@ -62,18 +58,10 @@ const date = ref<Date>()
### Date Range Picker ### Date Range Picker
<ComponentPreview name="DatePickerWithRange" > <ComponentPreview name="DatePickerWithRange" />
<<< ../../../lib/registry/default/examples/DatePickerWithRange.vue
</ComponentPreview>
### Date Picker ### Date Picker
<ComponentPreview name="DatePickerDemo" > <ComponentPreview name="DatePickerDemo" />
<<< ../../../lib/registry/default/examples/DatePickerDemo.vue
</ComponentPreview>

View File

@ -6,12 +6,7 @@ primitive: https://www.radix-vue.com/components/dialog.html
--- ---
<ComponentPreview name="DialogDemo" > <ComponentPreview name="DialogDemo" />
<<< ../../../lib/registry/default/examples/DialogDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -6,12 +6,7 @@ primitive: https://www.radix-vue.com/components/hover-card.html
--- ---
<ComponentPreview name="HoverCardDemo" > <ComponentPreview name="HoverCardDemo" />
<<< ../../../lib/registry/default/examples/HoverCardDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -4,11 +4,7 @@ description: Displays a form input field or a component that looks like an input
--- ---
<ComponentPreview name="InputDemo" class="[&_input]:max-w-xs" > <ComponentPreview name="InputDemo" class="[&_input]:max-w-xs" />
<<< ../../../lib/registry/default/examples/InputDemo.vue
</ComponentPreview>

View File

@ -5,12 +5,7 @@ source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/regis
primitive: https://www.radix-vue.com/components/label.html primitive: https://www.radix-vue.com/components/label.html
--- ---
<ComponentPreview name="LabelDemo" > <ComponentPreview name="LabelDemo" />
<<< ../../../lib/registry/default/examples/LabelDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -5,11 +5,7 @@ source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/regis
primitive: https://www.radix-vue.com/components/menubar.html primitive: https://www.radix-vue.com/components/menubar.html
--- ---
<ComponentPreview name="MenubarDemo" > <ComponentPreview name="MenubarDemo" />
<<< ../../../lib/registry/default/examples/MenubarDemo.vue
</ComponentPreview>

View File

@ -5,12 +5,7 @@ source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/regis
primitive: https://www.radix-vue.com/components/navigation-menu.html primitive: https://www.radix-vue.com/components/navigation-menu.html
--- ---
<ComponentPreview name="NavigationMenuDemo" > <ComponentPreview name="NavigationMenuDemo" />
<<< ../../../lib/registry/default/examples/NavigationMenuDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -6,11 +6,7 @@ primitive: https://www.radix-vue.com/components/popover.html
--- ---
<ComponentPreview name="PopoverDemo" > <ComponentPreview name="PopoverDemo" />
<<< ../../../lib/registry/default/examples/PopoverDemo.vue
</ComponentPreview>

View File

@ -5,11 +5,7 @@ source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/regis
primitive: https://www.radix-vue.com/components/progress.html primitive: https://www.radix-vue.com/components/progress.html
--- ---
<ComponentPreview name="ProgressDemo" > <ComponentPreview name="ProgressDemo" />
<<< ../../../lib/registry/default/examples/ProgressDemo.vue
</ComponentPreview>

View File

@ -5,11 +5,7 @@ source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/regis
primitive: https://www.radix-vue.com/components/radio-group.html primitive: https://www.radix-vue.com/components/radio-group.html
--- ---
<ComponentPreview name="RadioGroupDemo" > <ComponentPreview name="RadioGroupDemo" />
<<< ../../../lib/registry/default/examples/RadioGroupDemo.vue
</ComponentPreview>

View File

@ -5,11 +5,7 @@ source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/regis
primitive: https://www.radix-vue.com/components/scroll-area.html primitive: https://www.radix-vue.com/components/scroll-area.html
--- ---
<ComponentPreview name="ScrollAreaDemo" > <ComponentPreview name="ScrollAreaDemo" />
<<< ../../../lib/registry/default/examples/ScrollAreaDemo.vue
</ComponentPreview>

View File

@ -6,11 +6,7 @@ primitive: https://www.radix-vue.com/components/popover.html
--- ---
<ComponentPreview name="SelectDemo" > <ComponentPreview name="SelectDemo" />
<<< ../../../lib/registry/default/examples/SelectDemo.vue
</ComponentPreview>

View File

@ -5,11 +5,7 @@ source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/regis
primitive: https://www.radix-vue.com/components/separator.html primitive: https://www.radix-vue.com/components/separator.html
--- ---
<ComponentPreview name="SeparatorDemo" > <ComponentPreview name="SeparatorDemo" />
<<< ../../../lib/registry/default/examples/SeparatorDemo.vue
</ComponentPreview>

View File

@ -5,12 +5,7 @@ source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/regis
primitive: https://www.radix-vue.com/components/dialog.html primitive: https://www.radix-vue.com/components/dialog.html
--- ---
<ComponentPreview name="SheetDemo" > <ComponentPreview name="SheetDemo" />
<<< ../../../lib/registry/default/examples/SheetDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -3,12 +3,7 @@ title: Skeleton
description: Use to show a placeholder while content is loading. description: Use to show a placeholder while content is loading.
--- ---
<ComponentPreview name="SkeletonDemo" > <ComponentPreview name="SkeletonDemo" />
<<< ../../../lib/registry/default/examples/SkeletonDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -5,11 +5,7 @@ source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/regis
primitive: https://www.radix-vue.com/components/slider.html primitive: https://www.radix-vue.com/components/slider.html
--- ---
<ComponentPreview name="SliderDemo" > <ComponentPreview name="SliderDemo" />
<<< ../../../lib/registry/default/examples/SliderDemo.vue
</ComponentPreview>

View File

@ -5,12 +5,7 @@ source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/regis
primitive: https://www.radix-vue.com/components/switch.html primitive: https://www.radix-vue.com/components/switch.html
--- ---
<ComponentPreview name="SwitchDemo" > <ComponentPreview name="SwitchDemo" />
<<< ../../../lib/registry/default/examples/SwitchDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -3,12 +3,7 @@ title: Table
description: A responsive table component. description: A responsive table component.
--- ---
<ComponentPreview name="TableDemo" > <ComponentPreview name="TableDemo" />
<<< ../../../lib/registry/default/examples/TableDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -5,12 +5,7 @@ source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/regis
primitive: https://www.radix-vue.com/components/tabs.html primitive: https://www.radix-vue.com/components/tabs.html
--- ---
<ComponentPreview name="TabsDemo" > <ComponentPreview name="TabsDemo" />
<<< ../../../lib/registry/default/examples/TabsDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -3,12 +3,7 @@ title: Textarea
description: Displays a form textarea or a component that looks like a textarea. description: Displays a form textarea or a component that looks like a textarea.
--- ---
<ComponentPreview name="TextareaDemo" > <ComponentPreview name="TextareaDemo" />
<<< ../../../lib/registry/default/examples/TextareaDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -5,11 +5,7 @@ source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/regis
primitive: https://www.radix-vue.com/components/toggle.html primitive: https://www.radix-vue.com/components/toggle.html
--- ---
<ComponentPreview name="ToggleDemo" > <ComponentPreview name="ToggleDemo" />
<<< ../../../lib/registry/default/examples/ToggleDemo.vue
</ComponentPreview>

View File

@ -5,12 +5,7 @@ source: https://github.com/radix-vue/shadcn-vue/tree/main/apps/www/src/lib/regis
primitive: https://www.radix-vue.com/components/tooltip.html primitive: https://www.radix-vue.com/components/tooltip.html
--- ---
<ComponentPreview name="TooltipDemo" > <ComponentPreview name="TooltipDemo" />
<<< ../../../lib/registry/default/examples/TooltipDemo.vue
</ComponentPreview>
## Installation ## Installation

View File

@ -4,7 +4,7 @@ import { Avatar, AvatarFallback, AvatarImage } from '@/lib/registry/default/ui/a
<template> <template>
<Avatar> <Avatar>
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" /> <AvatarImage src="https://github.com/radix-vue.png" alt="@radix-vue" />
<AvatarFallback>CN</AvatarFallback> <AvatarFallback>CN</AvatarFallback>
</Avatar> </Avatar>
</template> </template>

View File

@ -0,0 +1,67 @@
<script setup lang="ts">
import { Button } from '@/lib/registry/default/ui/button'
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from '@/lib/registry/default/ui/card'
import { Input } from '@/lib/registry/default/ui/input'
import { Label } from '@/lib/registry/default/ui/label'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/lib/registry/default/ui/select'
</script>
<template>
<Card class="w-[350px]">
<CardHeader>
<CardTitle>Create project</CardTitle>
<CardDescription>Deploy your new project in one-click.</CardDescription>
</CardHeader>
<CardContent>
<form>
<div class="grid w-full items-center gap-4">
<div class="flex flex-col space-y-1.5">
<Label html-for="name">Name</Label>
<Input id="name" placeholder="Name of your project" />
</div>
<div class="flex flex-col space-y-1.5">
<Label html-for="framework">Framework</Label>
<Select>
<SelectTrigger id="framework">
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent position="popper">
<SelectItem value="next">
Next.js
</SelectItem>
<SelectItem value="sveltekit">
SvelteKit
</SelectItem>
<SelectItem value="astro">
Astro
</SelectItem>
<SelectItem value="nuxt">
Nuxt.js
</SelectItem>
</SelectContent>
</Select>
</div>
</div>
</form>
</CardContent>
<CardFooter class="flex justify-between">
<Button variant="outline">
Cancel
</Button>
<Button>Deploy</Button>
</CardFooter>
</Card>
</template>

View File

@ -11,7 +11,7 @@ const emits = defineEmits<AccordionRootEmits>()
</script> </script>
<template> <template>
<AccordionRoot v-bind="{ ...props, ...useEmitAsProps(emits) }"> <AccordionRoot v-bind="{ ...props, ...useEmitAsProps(emits) }" class="accordion">
<slot /> <slot />
</AccordionRoot> </AccordionRoot>
</template> </template>

View File

@ -10,6 +10,7 @@
"scripts": { "scripts": {
"dev": "pnpm --filter www dev", "dev": "pnpm --filter www dev",
"build": "pnpm --filter www build", "build": "pnpm --filter www build",
"preview": "pnpm --filter www preview",
"prepare": "pnpm simple-git-hooks", "prepare": "pnpm simple-git-hooks",
"lint": "eslint . --ignore-path .gitignore", "lint": "eslint . --ignore-path .gitignore",
"lint:fix": "eslint . --fix --ignore-path .gitignore" "lint:fix": "eslint . --fix --ignore-path .gitignore"

View File

@ -93,6 +93,9 @@ importers:
'@vitejs/plugin-vue': '@vitejs/plugin-vue':
specifier: ^4.1.0 specifier: ^4.1.0
version: 4.1.0(vite@4.3.9)(vue@3.3.4) version: 4.1.0(vite@4.3.9)(vue@3.3.4)
'@vue/compiler-core':
specifier: ^3.3.4
version: 3.3.4
autoprefixer: autoprefixer:
specifier: ^10.4.14 specifier: ^10.4.14
version: 10.4.14(postcss@8.4.24) version: 10.4.14(postcss@8.4.24)