mirror of
https://github.com/HoshinoSuzumi/rayine-ui.git
synced 2025-04-10 04:58:51 +08:00
📝 docs(interactive): add interactive props
This commit is contained in:
parent
d3bd236e67
commit
355843b054
@ -6,6 +6,7 @@ import FileTypeJavascript from '../icon/VscodeIconsFileTypeJsOfficial.vue'
|
|||||||
import TablerTerminal from '../icon/TablerTerminal.vue'
|
import TablerTerminal from '../icon/TablerTerminal.vue'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
const appConfig = useAppConfig()
|
||||||
|
|
||||||
const IconComponents = {
|
const IconComponents = {
|
||||||
'vue': FileTypeVue,
|
'vue': FileTypeVue,
|
||||||
@ -38,9 +39,52 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const componentName = props.slug || `Ray${upperFirst(camelCase(route.params.slug[route.params.slug.length - 1]))}`
|
const componentName = props.slug || `Ray${upperFirst(camelCase(route.params.slug[route.params.slug.length - 1]))}`
|
||||||
|
const componentMeta = await fetchComponentMeta(componentName)
|
||||||
|
|
||||||
const componentProps = reactive({ ...props.props })
|
const componentProps = reactive({ ...props.props })
|
||||||
|
|
||||||
|
const customizableOptions = (key: string, schema: { kind: string, type: string, schema: [] }) => {
|
||||||
|
let options: string[] = [];
|
||||||
|
const invalidTypes = ['string', 'array', 'boolean', 'object', 'number', 'Function']
|
||||||
|
const hasInvalidType = schema?.type?.split('|')?.map(item => item.trim()?.replaceAll('"', ''))?.some(type => invalidTypes.includes(type))
|
||||||
|
const schemaOptions = Object.values(schema?.schema || {})
|
||||||
|
|
||||||
|
if (key.toLowerCase().endsWith('color')) {
|
||||||
|
options = [...appConfig.rayui.colors]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.toLowerCase() === 'size' && schemaOptions?.length) {
|
||||||
|
const baseSizeOrder = { xs: 1, sm: 2, md: 3, lg: 4, xl: 5 };
|
||||||
|
schemaOptions.sort((a: string, b: string) => {
|
||||||
|
const [aBase, aNum] = [(a.match(/[a-z]+/i)?.[0].toLowerCase() || 'xs') as keyof typeof baseSizeOrder, parseInt(a.match(/\d+/)?.[0] || '1')];
|
||||||
|
const [bBase, bNum] = [(b.match(/[a-z]+/i)?.[0].toLowerCase() || 'xs') as keyof typeof baseSizeOrder, parseInt(b.match(/\d+/)?.[0] || '1')];
|
||||||
|
return aBase === bBase
|
||||||
|
? (aBase === 'xs' ? bNum - aNum : aNum - bNum)
|
||||||
|
: baseSizeOrder[aBase] - baseSizeOrder[bBase];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (schemaOptions?.length > 0 && schema?.kind === 'enum' && !hasInvalidType) {
|
||||||
|
options = schemaOptions.filter(option => option !== 'undefined' && typeof option === 'string').map((option: string) => option.replaceAll('"', ''))
|
||||||
|
}
|
||||||
|
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
|
const customizableProps = computed(() => Object.keys(componentProps).map(k => {
|
||||||
|
const prop = componentMeta?.meta?.props?.find((prop: any) => prop.name === k)
|
||||||
|
const schema = prop?.schema || {}
|
||||||
|
const options = customizableOptions(k, schema)
|
||||||
|
return {
|
||||||
|
name: k,
|
||||||
|
type: prop?.type,
|
||||||
|
label: camelCase(k),
|
||||||
|
options,
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
const code = computed(() => {
|
const code = computed(() => {
|
||||||
let code = `\`\`\`html
|
let code = `\`\`\`html
|
||||||
<template>
|
<template>
|
||||||
@ -92,13 +136,31 @@ const { data: codeRender, error: codeRenderError } = await useAsyncData(`${compo
|
|||||||
</component>
|
</component>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="customizableProps.length > 0" class="border-b border-neutral-200 dark:border-neutral-700 flex">
|
||||||
|
<div v-for="prop in customizableProps" class="px-2 py-0.5 flex flex-col gap-0.5 border-r dark:border-neutral-700">
|
||||||
|
<label :for="`${prop.name}-prop`" class="text-sm text-neutral-400">{{ prop.name }}</label>
|
||||||
|
<input v-if="prop.type.startsWith('boolean')" type="checkbox" :id="`${prop.name}-prop`" class="mt-1 mb-2"
|
||||||
|
v-model="componentProps[prop.name]" />
|
||||||
|
<select v-else-if="prop.options.length > 0" :id="`${prop.name}-prop`" v-model="componentProps[prop.name]">
|
||||||
|
<option v-for="option in prop.options" :key="option" :value="option">{{ option }}</option>
|
||||||
|
</select>
|
||||||
|
<input v-else type="text" :id="`${prop.name}-prop`" v-model="componentProps[prop.name]"
|
||||||
|
placeholder="type something..." />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<template v-if="codeRender || codeRenderError">
|
<template v-if="codeRender || codeRenderError">
|
||||||
<div class="overflow-auto">
|
<div class="overflow-auto bg-neutral-50 dark:bg-neutral-800/50">
|
||||||
<ContentRenderer v-if="codeRender" :value="codeRender" class="p-4 bg-neutral-50 dark:bg-neutral-800/50" />
|
<ContentRenderer v-if="codeRender" :value="codeRender" class="p-4" />
|
||||||
<pre v-if="codeRenderError" class="p-4">{{ codeRenderError }}</pre>
|
<pre v-if="codeRenderError" class="p-4">{{ codeRenderError }}</pre>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped>
|
||||||
|
input,
|
||||||
|
select {
|
||||||
|
@apply text-sm outline-none border-none bg-transparent;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
39
docs/composables/useComponentMeta.ts
Normal file
39
docs/composables/useComponentMeta.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
interface ComponentMetaState {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const useComponentsMetaState = () =>
|
||||||
|
useState<ComponentMetaState>("components-meta", () => ({}));
|
||||||
|
|
||||||
|
export const fetchComponentMeta = async (name: string) => {
|
||||||
|
const state = useComponentsMetaState();
|
||||||
|
|
||||||
|
if (state.value[name]?.then) {
|
||||||
|
await state.value[name];
|
||||||
|
return state.value[name];
|
||||||
|
}
|
||||||
|
if (state.value[name]) {
|
||||||
|
return state.value[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (import.meta.server) {
|
||||||
|
const event = useRequestEvent();
|
||||||
|
if (event && event.node && event.node.res) {
|
||||||
|
event.node.res.setHeader(
|
||||||
|
"x-nitro-prerender",
|
||||||
|
[
|
||||||
|
event.node.res.getHeader("x-nitro-prerender"),
|
||||||
|
`/api/component-meta/${name}.json`,
|
||||||
|
].filter(Boolean) as string[]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.value[name] = $fetch(`/api/component-meta/${name}.json`).then(
|
||||||
|
(meta) => {
|
||||||
|
state.value[name] = meta;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await state.value[name];
|
||||||
|
return state.value[name];
|
||||||
|
};
|
@ -10,58 +10,39 @@ Default button style
|
|||||||
Button
|
Button
|
||||||
::
|
::
|
||||||
|
|
||||||
### Variants
|
### Styles
|
||||||
|
|
||||||
#### soft
|
Use the `variant` and `color` props to predefined styles and change the color of buttons.
|
||||||
|
|
||||||
::ComponentPreview
|
::ComponentPreview
|
||||||
---
|
---
|
||||||
props:
|
props:
|
||||||
variant: soft
|
variant: soft
|
||||||
---
|
|
||||||
Button
|
|
||||||
::
|
|
||||||
|
|
||||||
#### outline
|
|
||||||
|
|
||||||
::ComponentPreview
|
|
||||||
---
|
|
||||||
props:
|
|
||||||
variant: outline
|
|
||||||
---
|
|
||||||
Button
|
|
||||||
::
|
|
||||||
|
|
||||||
#### ghost
|
|
||||||
|
|
||||||
::ComponentPreview
|
|
||||||
---
|
|
||||||
props:
|
|
||||||
variant: ghost
|
|
||||||
---
|
|
||||||
Button
|
|
||||||
::
|
|
||||||
|
|
||||||
#### link
|
|
||||||
|
|
||||||
::ComponentPreview
|
|
||||||
---
|
|
||||||
props:
|
|
||||||
variant: link
|
|
||||||
---
|
|
||||||
Button
|
|
||||||
::
|
|
||||||
|
|
||||||
### Colors
|
|
||||||
|
|
||||||
::ComponentPreview
|
|
||||||
---
|
|
||||||
props:
|
|
||||||
color: violet
|
color: violet
|
||||||
---
|
---
|
||||||
Button
|
Button
|
||||||
::
|
::
|
||||||
|
|
||||||
|
### Sizes
|
||||||
|
|
||||||
|
::ComponentPreview
|
||||||
|
---
|
||||||
|
props:
|
||||||
|
size: sm
|
||||||
|
---
|
||||||
|
Button
|
||||||
|
::
|
||||||
|
|
||||||
|
### Block
|
||||||
|
|
||||||
|
::ComponentPreview
|
||||||
|
---
|
||||||
|
props:
|
||||||
|
block: true
|
||||||
|
---
|
||||||
|
Button
|
||||||
|
::
|
||||||
|
|
||||||
### Disabled
|
### Disabled
|
||||||
|
|
||||||
::ComponentPreview
|
::ComponentPreview
|
||||||
|
@ -1,48 +1,73 @@
|
|||||||
import defaultTheme from 'tailwindcss/defaultTheme'
|
import { createResolver } from "@nuxt/kit";
|
||||||
import module from '../src/module'
|
import defaultTheme from "tailwindcss/defaultTheme";
|
||||||
|
import module from "../src/module";
|
||||||
|
|
||||||
|
const { resolve } = createResolver(import.meta.url);
|
||||||
|
|
||||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
modules: ['@nuxt/content', '@nuxt/fonts', '@nuxtjs/color-mode', module],
|
modules: [
|
||||||
|
"@nuxt/content",
|
||||||
|
"@nuxt/fonts",
|
||||||
|
"@nuxtjs/color-mode",
|
||||||
|
module,
|
||||||
|
"nuxt-component-meta",
|
||||||
|
],
|
||||||
devtools: { enabled: true },
|
devtools: { enabled: true },
|
||||||
colorMode: {
|
colorMode: {
|
||||||
preference: 'system',
|
preference: "system",
|
||||||
classSuffix: '',
|
classSuffix: "",
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
highlight: {
|
highlight: {
|
||||||
langs: ['postcss', 'mdc', 'html', 'vue', 'ts', 'js', 'bash'],
|
langs: ["postcss", "mdc", "html", "vue", "ts", "js", "bash"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mdc: {
|
mdc: {
|
||||||
highlight: {
|
highlight: {
|
||||||
theme: {
|
theme: {
|
||||||
light: 'material-theme-lighter',
|
light: "material-theme-lighter",
|
||||||
dark: 'material-theme',
|
dark: "material-theme",
|
||||||
},
|
},
|
||||||
themes: ['material-theme-lighter', 'material-theme'],
|
themes: ["material-theme-lighter", "material-theme"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
routeRules: {
|
routeRules: {
|
||||||
'/components': { redirect: '/components/button' },
|
"/components": { redirect: "/components/button" },
|
||||||
},
|
},
|
||||||
compatibilityDate: '2024-04-03',
|
componentMeta: {
|
||||||
|
exclude: [
|
||||||
|
"@nuxt/content",
|
||||||
|
"@nuxtjs/color-mode",
|
||||||
|
"@nuxtjs/mdc",
|
||||||
|
"nuxt/dist",
|
||||||
|
resolve("./components"),
|
||||||
|
],
|
||||||
|
metaFields: {
|
||||||
|
type: false,
|
||||||
|
props: true,
|
||||||
|
slots: true,
|
||||||
|
events: false,
|
||||||
|
exposed: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
compatibilityDate: "2024-04-03",
|
||||||
typescript: {
|
typescript: {
|
||||||
includeWorkspace: true,
|
includeWorkspace: true,
|
||||||
},
|
},
|
||||||
rayui: {
|
rayui: {
|
||||||
globalComponents: true,
|
globalComponents: true,
|
||||||
safeColors: ['amber', 'emerald', 'red', 'sky', 'violet', 'cyan'],
|
safeColors: ["amber", "emerald", "red", "sky", "violet", "cyan"],
|
||||||
},
|
},
|
||||||
tailwindcss: {
|
tailwindcss: {
|
||||||
config: {
|
config: {
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
sans: ['Rubik', '"Noto Sans SC"', ...defaultTheme.fontFamily.sans],
|
sans: ["Rubik", '"Noto Sans SC"', ...defaultTheme.fontFamily.sans],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"@nuxtjs/color-mode": "^3.5.2",
|
"@nuxtjs/color-mode": "^3.5.2",
|
||||||
"@nuxtjs/mdc": "^0.9.2",
|
"@nuxtjs/mdc": "^0.9.2",
|
||||||
"nuxt": "^3.14.159",
|
"nuxt": "^3.14.159",
|
||||||
|
"nuxt-component-meta": "^0.9.0",
|
||||||
"nuxt-shiki": "^0.3.0",
|
"nuxt-shiki": "^0.3.0",
|
||||||
"rayine-ui": "workspace:rayine-ui",
|
"rayine-ui": "workspace:rayine-ui",
|
||||||
"ufo": "^1.5.4",
|
"ufo": "^1.5.4",
|
||||||
|
43
pnpm-lock.yaml
generated
43
pnpm-lock.yaml
generated
@ -87,6 +87,9 @@ importers:
|
|||||||
nuxt:
|
nuxt:
|
||||||
specifier: ^3.14.159
|
specifier: ^3.14.159
|
||||||
version: 3.14.159(@parcel/watcher@2.5.0)(@types/node@22.9.1)(eslint@9.15.0(jiti@2.4.0))(ioredis@5.4.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.27.2)(terser@5.36.0)(typescript@5.6.3)(vite@5.4.11(@types/node@22.9.1)(terser@5.36.0))(vue-tsc@2.1.10(typescript@5.6.3))
|
version: 3.14.159(@parcel/watcher@2.5.0)(@types/node@22.9.1)(eslint@9.15.0(jiti@2.4.0))(ioredis@5.4.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.27.2)(terser@5.36.0)(typescript@5.6.3)(vite@5.4.11(@types/node@22.9.1)(terser@5.36.0))(vue-tsc@2.1.10(typescript@5.6.3))
|
||||||
|
nuxt-component-meta:
|
||||||
|
specifier: ^0.9.0
|
||||||
|
version: 0.9.0(magicast@0.3.5)(rollup@4.27.2)
|
||||||
nuxt-shiki:
|
nuxt-shiki:
|
||||||
specifier: ^0.3.0
|
specifier: ^0.3.0
|
||||||
version: 0.3.0(magicast@0.3.5)(rollup@4.27.2)
|
version: 0.3.0(magicast@0.3.5)(rollup@4.27.2)
|
||||||
@ -3546,6 +3549,10 @@ packages:
|
|||||||
engines: {node: ^16.10.0 || >=18.0.0}
|
engines: {node: ^16.10.0 || >=18.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
nuxt-component-meta@0.9.0:
|
||||||
|
resolution: {integrity: sha512-Zmuw/PxAeJkIu7EPZEFg0lIwnfpeiDsHog9i1g5d4Z3O5+00R1Vbuk+NC6K7kgpdLsdU2/XBvzc7oQ6BsXuQPg==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
nuxt-shiki@0.3.0:
|
nuxt-shiki@0.3.0:
|
||||||
resolution: {integrity: sha512-edeP230QQmQ02PdquCjE0noM8+RNTrpjJk1pfR1tIJ5gBp1DegzTe4WdFUWXu7sjSiIndfDy2KbQ9SPscGROJw==}
|
resolution: {integrity: sha512-edeP230QQmQ02PdquCjE0noM8+RNTrpjJk1pfR1tIJ5gBp1DegzTe4WdFUWXu7sjSiIndfDy2KbQ9SPscGROJw==}
|
||||||
|
|
||||||
@ -4944,6 +4951,17 @@ packages:
|
|||||||
vue-bundle-renderer@2.1.1:
|
vue-bundle-renderer@2.1.1:
|
||||||
resolution: {integrity: sha512-+qALLI5cQncuetYOXp4yScwYvqh8c6SMXee3B+M7oTZxOgtESP0l4j/fXdEJoZ+EdMxkGWIj+aSEyjXkOdmd7g==}
|
resolution: {integrity: sha512-+qALLI5cQncuetYOXp4yScwYvqh8c6SMXee3B+M7oTZxOgtESP0l4j/fXdEJoZ+EdMxkGWIj+aSEyjXkOdmd7g==}
|
||||||
|
|
||||||
|
vue-component-meta@2.1.10:
|
||||||
|
resolution: {integrity: sha512-YEFSau36lLCJNvoM6eynAcq891Y6HKIEdEk3PCzCyNVySeYJAXgE/9iCYqQzLtBJlKg/bBpImz8VbUZsh4N/7Q==}
|
||||||
|
peerDependencies:
|
||||||
|
typescript: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
typescript:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
vue-component-type-helpers@2.1.10:
|
||||||
|
resolution: {integrity: sha512-lfgdSLQKrUmADiSV6PbBvYgQ33KF3Ztv6gP85MfGaGaSGMTXORVaHT1EHfsqCgzRNBstPKYDmvAV9Do5CmJ07A==}
|
||||||
|
|
||||||
vue-demi@0.14.10:
|
vue-demi@0.14.10:
|
||||||
resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
|
resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@ -9509,6 +9527,20 @@ snapshots:
|
|||||||
|
|
||||||
nuxi@3.15.0: {}
|
nuxi@3.15.0: {}
|
||||||
|
|
||||||
|
nuxt-component-meta@0.9.0(magicast@0.3.5)(rollup@4.27.2):
|
||||||
|
dependencies:
|
||||||
|
'@nuxt/kit': 3.14.159(magicast@0.3.5)(rollup@4.27.2)
|
||||||
|
citty: 0.1.6
|
||||||
|
mlly: 1.7.3
|
||||||
|
scule: 1.3.0
|
||||||
|
typescript: 5.6.3
|
||||||
|
ufo: 1.5.4
|
||||||
|
vue-component-meta: 2.1.10(typescript@5.6.3)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- magicast
|
||||||
|
- rollup
|
||||||
|
- supports-color
|
||||||
|
|
||||||
nuxt-shiki@0.3.0(magicast@0.3.5)(rollup@4.27.2):
|
nuxt-shiki@0.3.0(magicast@0.3.5)(rollup@4.27.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nuxt/kit': 3.14.159(magicast@0.3.5)(rollup@4.27.2)
|
'@nuxt/kit': 3.14.159(magicast@0.3.5)(rollup@4.27.2)
|
||||||
@ -11380,6 +11412,17 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ufo: 1.5.4
|
ufo: 1.5.4
|
||||||
|
|
||||||
|
vue-component-meta@2.1.10(typescript@5.6.3):
|
||||||
|
dependencies:
|
||||||
|
'@volar/typescript': 2.4.10
|
||||||
|
'@vue/language-core': 2.1.10(typescript@5.6.3)
|
||||||
|
path-browserify: 1.0.1
|
||||||
|
vue-component-type-helpers: 2.1.10
|
||||||
|
optionalDependencies:
|
||||||
|
typescript: 5.6.3
|
||||||
|
|
||||||
|
vue-component-type-helpers@2.1.10: {}
|
||||||
|
|
||||||
vue-demi@0.14.10(vue@3.5.13(typescript@5.6.3)):
|
vue-demi@0.14.10(vue@3.5.13(typescript@5.6.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
vue: 3.5.13(typescript@5.6.3)
|
vue: 3.5.13(typescript@5.6.3)
|
||||||
|
Loading…
Reference in New Issue
Block a user