feat(Button): add match and invert color mode

refactor(docs): update docs
This commit is contained in:
Timothy Yin 2024-11-23 17:58:06 +08:00
parent 15aa2315ae
commit 0e070c8909
13 changed files with 272 additions and 82 deletions

View File

@ -1,6 +1,7 @@
<script lang="ts" setup>
import { camelCase, upperFirst } from 'scule'
import * as config from '#rayui/ui.config'
import json5 from 'json5'
const route = useRoute()
@ -16,18 +17,23 @@ const componentCamelName = camelCase(slug)
const componentName = `Ray${upperFirst(componentCamelName)}`
const defaults = config[componentCamelName as keyof typeof config]
console.log(componentCamelName, JSON.stringify(defaults));
const { data: defaultsRender } = await useAsyncData(`${componentName}-defaults`, () => parseMarkdown(`
\`\`\`json
${JSON.stringify(defaults, null, 2)}
const { data: defaultsRender } = await useAsyncData(`${componentName}-defaults`, () => {
return parseMarkdown(`
\`\`\`yaml
${json5.stringify(defaults, null, 2).replace(/,(\s+[}\]\|])/g, '$1') }
\`\`\`
`, {}))
`)
})
</script>
<template>
<ContentRenderer v-if="defaultsRender?.body" :value="defaultsRender" />
<ContentRenderer :value="defaultsRender!" />
</template>
<style scoped>
<style>
pre.shiki > code > span {
@apply text-wrap break-words;
}
</style>

View File

@ -127,7 +127,7 @@ const code = computed(() => {
return code
})
const { data: codeRender, error: codeRenderError } = await useAsyncData(`${componentName}-renderer-${JSON.stringify({ props: componentProps, slots: props.slots, code: code.value })}`, async () => {
const { data: codeRender, error: codeRenderError } = await useAsyncData(`${componentName}-code-renderer-${JSON.stringify({ props: componentProps, slots: props.slots, code: code.value })}`, async () => {
return parseMarkdown(code.value, {})
}, {
watch: [code],
@ -150,40 +150,22 @@ const { data: codeRender, error: codeRenderError } = await useAsyncData(`${compo
</div>
<div v-if="customizableProps.length > 0" class="border-b border-neutral-200 dark:border-neutral-700 flex">
<div
v-for="(prop, k) in customizableProps"
:key="k"
class="px-2 py-0.5 flex flex-col gap-0.5 border-r dark:border-neutral-700"
>
<div v-for="(prop, k) in customizableProps" :key="k"
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')"
:id="`${prop.name}-prop`"
v-model="componentProps[prop.name]"
type="checkbox"
class="mt-1 mb-2"
>
<input v-if="prop.type.startsWith('boolean')" :id="`${prop.name}-prop`" v-model="componentProps[prop.name]"
type="checkbox" class="mt-1 mb-2">
<select v-else-if="prop.options.length" :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
:id="`${prop.name}-prop`"
v-model="componentProps[prop.name]"
type="text"
placeholder="type something..."
>
<input v-else :id="`${prop.name}-prop`" v-model="componentProps[prop.name]" type="text"
placeholder="type something...">
</div>
</div>
<template v-if="codeRender || codeRenderError">
<div class="overflow-auto 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>
</div>
</template>
<ContentRenderer v-if="codeRender" :value="codeRender" class="overflow-auto [&_.pre]:rounded-none [&_.pre]:border-none" />
</div>
</template>

View File

@ -0,0 +1,46 @@
<template>
<div class="bg-neutral-50 dark:bg-neutral-800/50 not-prose text-sm" data-prose-code>
<slot />
</div>
</template>
<script setup lang="ts">
defineProps({
code: {
type: String,
default: ''
},
language: {
type: String,
default: null
},
filename: {
type: String,
default: null
},
highlights: {
type: Array as () => number[],
default: () => []
},
meta: {
type: String,
default: null
}
})
</script>
<style>
pre {
@apply p-0 py-2;
}
pre code .line {
@apply block min-h-4 px-4;
}
pre code .line.highlight {
@apply !bg-gray-200/50 dark:!bg-gray-800;
}
</style>

View File

@ -0,0 +1,87 @@
<script setup lang="ts">
import FileTypeVue from '../../icon/VscodeIconsFileTypeVue.vue'
import FileTypeTypescript from '../../icon/VscodeIconsFileTypeTypescriptOfficial.vue'
import FileTypeJavascript from '../../icon/VscodeIconsFileTypeJsOfficial.vue'
import TablerTerminal from '../../icon/TablerTerminal.vue'
import TablerFile from '~/components/icon/TablerFile.vue';
import VscodeIconsFileTypeJson from '~/components/icon/VscodeIconsFileTypeJson.vue';
import VscodeIconsFileTypeNuxt from '~/components/icon/VscodeIconsFileTypeNuxt.vue';
const props = defineProps({
code: {
type: String,
default: ''
},
language: {
type: String,
default: null
},
filename: {
type: String,
default: null
},
highlights: {
type: Array as () => number[],
default: () => []
},
meta: {
type: String,
default: null
},
class: {
type: String,
default: null
},
style: {
type: [String, Object],
default: null
}
})
const mapIconLanguage = {
'default': TablerFile,
'vue': FileTypeVue,
'vue-html': FileTypeVue,
'bash': TablerTerminal,
'sh': TablerTerminal,
'ts': FileTypeTypescript,
'js': FileTypeJavascript,
'json': VscodeIconsFileTypeJson
}
const mapIconFilename = {
'nuxt.config.ts': VscodeIconsFileTypeNuxt
}
const resolveIcon = computed(() => {
if (props.filename) {
if (props.filename.endsWith('.vue')) return FileTypeVue
const icon = mapIconFilename[props.filename as keyof typeof mapIconFilename]
if (icon) return icon
}
return mapIconLanguage[props.language as keyof typeof mapIconLanguage]
})
</script>
<template>
<div data-prose-pre class="pre rounded-lg overflow-hidden border border-gray-200 dark:border-gray-700">
<div v-if="filename" class="p-4 py-2 border-b border-neutral-200 dark:border-neutral-700">
<span class="flex items-center gap-1">
<component :is="resolveIcon" v-if="language" class="inline" />
<span class="text-sm text-neutral-500 dark:text-neutral-400">{{ filename }}</span>
</span>
</div>
<ProseCode data-prose-precode :code="code" :language="language" :filename="filename" :highlights="highlights"
:meta="meta">
<pre data-prose-pre-inner-pre :class="$props.class" :style="style"><slot></slot></pre>
</ProseCode>
</div>
</template>
<style>
pre code .line {
display: block;
min-height: 1rem
}
</style>

View File

@ -0,0 +1,10 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M14 3v4a1 1 0 0 0 1 1h4"></path><path d="M17 21H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7l5 5v11a2 2 0 0 1-2 2"></path></g></svg>
</template>
<script>
export default {
name: 'TablerFile'
}
</script>

View File

@ -0,0 +1,10 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 32 32"><path fill="#f5de19" d="M4.014 14.976a2.5 2.5 0 0 0 1.567-.518a2.38 2.38 0 0 0 .805-1.358a15.3 15.3 0 0 0 .214-2.944q.012-2.085.075-2.747a5.2 5.2 0 0 1 .418-1.686a3 3 0 0 1 .755-1.018A3.05 3.05 0 0 1 9 4.125A6.8 6.8 0 0 1 10.544 4h.7v1.96h-.387a2.34 2.34 0 0 0-1.723.468a3.4 3.4 0 0 0-.425 2.092a36 36 0 0 1-.137 4.133a4.7 4.7 0 0 1-.768 2.06A4.6 4.6 0 0 1 6.1 16a3.8 3.8 0 0 1 1.992 1.754a8.9 8.9 0 0 1 .618 3.865q0 2.435.05 2.9a1.76 1.76 0 0 0 .504 1.181a2.64 2.64 0 0 0 1.592.337h.387V28h-.7a5.7 5.7 0 0 1-1.773-.2a2.97 2.97 0 0 1-1.324-.93a3.35 3.35 0 0 1-.681-1.63a24 24 0 0 1-.165-3.234a16.5 16.5 0 0 0-.214-3.106a2.4 2.4 0 0 0-.805-1.361a2.5 2.5 0 0 0-1.567-.524Zm23.972 2.035a2.5 2.5 0 0 0-1.567.524a2.4 2.4 0 0 0-.805 1.361a16.5 16.5 0 0 0-.212 3.109a24 24 0 0 1-.169 3.234a3.35 3.35 0 0 1-.681 1.63a2.97 2.97 0 0 1-1.324.93a5.7 5.7 0 0 1-1.773.2h-.7V26.04h.387a2.64 2.64 0 0 0 1.592-.337a1.76 1.76 0 0 0 .506-1.186q.05-.462.05-2.9a8.9 8.9 0 0 1 .618-3.865A3.8 3.8 0 0 1 25.9 16a4.6 4.6 0 0 1-1.7-1.286a4.7 4.7 0 0 1-.768-2.06a36 36 0 0 1-.137-4.133a3.4 3.4 0 0 0-.425-2.092a2.34 2.34 0 0 0-1.723-.468h-.387V4h.7a6.8 6.8 0 0 1 1.54.125a3.05 3.05 0 0 1 1.149.581a3 3 0 0 1 .755 1.018a5.2 5.2 0 0 1 .418 1.686q.062.662.075 2.747a15.3 15.3 0 0 0 .212 2.947a2.38 2.38 0 0 0 .805 1.355a2.5 2.5 0 0 0 1.567.518Z"></path></svg>
</template>
<script>
export default {
name: 'VscodeIconsFileTypeJson'
}
</script>

View File

@ -0,0 +1,10 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 32 32"><path fill="#00DC82" d="M17.708 25h10.409c.33 0 .655-.088.942-.254a1.9 1.9 0 0 0 .689-.696a1.91 1.91 0 0 0 0-1.9L22.756 9.936a1.87 1.87 0 0 0-3.261 0l-1.788 3.125l-3.494-6.111a1.871 1.871 0 0 0-3.262 0l-8.7 15.2a1.91 1.91 0 0 0 .69 2.595c.286.167.61.255.941.255h6.534c2.589 0 4.498-1.147 5.811-3.385l3.19-5.572l1.708-2.982l5.127 8.957h-6.835zm-7.398-2.985l-4.56-.001l6.836-11.942l3.41 5.97l-2.283 3.992c-.873 1.452-1.864 1.981-3.403 1.981"></path></svg>
</template>
<script>
export default {
name: 'VscodeIconsFileTypeNuxt'
}
</script>

View File

@ -2,19 +2,19 @@
1. Install rayine-ui via npm or other package manager.
```bash
```bash [Terminal]
npm install rayine-ui
```
or...
```bash
```bash [Terminal]
npx nuxi@latest module add rayine-ui
```
2. Add to the modules in your project.
```ts
```ts [nuxt.config.ts]{2}
export default defineNuxtConfig({
modules: ['rayine-ui']
})

View File

@ -23,6 +23,34 @@ props:
Button
::
#### Match
The color of the buttons will match the color theme.
::ComponentPreview
---
props:
color: match
excludedProps:
- color
---
Button
::
#### Invert
The color of the buttons will be the opposite of the color theme.
::ComponentPreview
---
props:
color: invert
excludedProps:
- color
---
Button
::
### Sizes
::ComponentPreview
@ -58,6 +86,7 @@ props:
---
props:
disabled: true
variant: solid
---
Button
::
@ -68,6 +97,7 @@ Button
---
props:
loading: true
variant: solid
---
Button
::

View File

@ -6,7 +6,7 @@ description: The message component is used to display a message to the user
First add the `<RayMessages>` component to your `app.vue`.
```js
```js [app.vue]{6}
<template>
<NuxtLayout>
<NuxtPage />
@ -18,7 +18,7 @@ First add the `<RayMessages>` component to your `app.vue`.
Then, use the `useMessage` composable to add messages to your app anywhere you want.
```vue
```vue [pages/index.vue]{2,5-8}
<script lang="ts" setup>
const message = useMessage()

View File

@ -41,7 +41,7 @@ export default defineNuxtConfig({
},
},
routeRules: {
'/components': { redirect: '/components/button' },
'/components': { redirect: '/components/button', prerender: false },
},
compatibilityDate: '2024-04-03',
typescript: {

View File

@ -41,7 +41,7 @@ const { data: surround } = await useAsyncData(`${route.path}-surround`, () => {
<NuxtLink
:to="child._path"
class="text-sm text-neutral-500 dark:text-neutral-400"
active-class="text-primary font-medium"
active-class="text-primary dark:text-primary font-medium"
>
{{ child.title }}
</NuxtLink>

View File

@ -1,60 +1,69 @@
export default {
base: 'focus:outline-none focus-visible:outline-0 disabled:cursor-not-allowed disabled:opacity-75 aria-disabled:cursor-not-allowed aria-disabled:opacity-75 flex-shrink-0 transition',
rounded: 'rounded-lg',
font: 'font-medium',
block: 'w-full flex justify-center items-center',
inline: 'inline-flex items-center',
base: "focus:outline-none focus-visible:outline-0 disabled:cursor-not-allowed disabled:opacity-70 aria-disabled:cursor-not-allowed aria-disabled:opacity-70 flex-shrink-0 transition",
rounded: "rounded-lg",
font: "font-medium",
block: "w-full flex justify-center items-center",
inline: "inline-flex items-center",
size: {
'2xs': 'text-xs',
'xs': 'text-xs',
'sm': 'text-sm',
'md': 'text-sm',
'lg': 'text-sm',
'xl': 'text-base',
"2xs": "text-xs",
xs: "text-xs",
sm: "text-sm",
md: "text-sm",
lg: "text-sm",
xl: "text-base",
},
padding: {
'2xs': 'px-2 py-1',
'xs': 'px-2.5 py-1.5',
'sm': 'px-2.5 py-1.5',
'md': 'px-3 py-2',
'lg': 'px-3.5 py-2.5',
'xl': 'px-3.5 py-2.5',
"2xs": "px-2 py-1",
xs: "px-2.5 py-1.5",
sm: "px-2.5 py-1.5",
md: "px-3 py-2",
lg: "px-3.5 py-2.5",
xl: "px-3.5 py-2.5",
},
square: {
'2xs': 'p-1',
'xs': 'p-1.5',
'sm': 'p-1.5',
'md': 'p-2',
'lg': 'p-2.5',
'xl': 'p-2.5',
"2xs": "p-1",
xs: "p-1.5",
sm: "p-1.5",
md: "p-2",
lg: "p-2.5",
xl: "p-2.5",
},
icon: {
base: 'flex-shrink-0',
loading: 'animate-spin',
base: "flex-shrink-0",
loading: "animate-spin",
size: {
'2xs': 'h-4 w-4',
'xs': 'h-4 w-4',
'sm': 'h-5 w-5',
'md': 'h-5 w-5',
'lg': 'h-5 w-5',
'xl': 'h-6 w-6',
"2xs": "h-4 w-4",
xs: "h-4 w-4",
sm: "h-5 w-5",
md: "h-5 w-5",
lg: "h-5 w-5",
xl: "h-6 w-6",
},
},
color: {
match: {
solid:
"shadow-sm active:shadow-none bg-white dark:bg-gray-900 hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-900 dark:text-white ring-1 ring-inset ring-gray-300 dark:ring-gray-700 disabled:bg-white disabled:active:shadow-sm focus-visible:ring-2 focus-visible:ring-primary-500 dark:focus-visible:ring-primary-400",
},
invert: {
solid:
"shadow-sm active:shadow-none bg-gray-900 dark:bg-white hover:bg-gray-800 dark:hover:bg-gray-100 text-white dark:text-gray-900 ring-1 ring-inset ring-gray-900 dark:ring-white disabled:bg-white disabled:active:shadow-sm focus-visible:ring-2 focus-visible:ring-primary-500 dark:focus-visible:ring-primary-400",
},
},
color: {},
variant: {
solid:
'shadow-sm hover:shadow-md disabled:hover:shadow-sm active:shadow-none bg-{color}-500 disabled:bg-{color}-500 aria-disabled:bg-{color}-500 hover:bg-{color}-600 text-white active:bg-{color}-700 dark:active:bg-{color}-500 focus:ring focus:ring-{color}-300 focus:ring-opacity-50 dark:focus:ring-opacity-20',
"shadow-sm hover:shadow-md disabled:hover:shadow-sm active:shadow-none bg-{color}-500 disabled:bg-{color}-500 aria-disabled:bg-{color}-500 hover:bg-{color}-600 text-white active:bg-{color}-700 dark:active:bg-{color}-500 focus:ring focus:ring-{color}-300 focus:ring-opacity-50 dark:focus:ring-opacity-20",
outline:
'ring-1 ring-inset ring-current ring-{color}-500 text-{color}-500 dark:hover:text-{color}-400 dark:hover:text-{color}-500 hover:bg-{color}-100 dark:hover:bg-{color}-900 disabled:bg-transparent disabled:hover:bg-transparent aria-disabled:bg-transparent focus-visible:ring-2 focus-visible:ring-{color}-500 dark:focus-visible:ring-{color}-400',
soft: 'text-{color}-500 dark:text-{color}-400 bg-{color}-50 hover:bg-{color}-100 disabled:bg-{color}-50 aria-disabled:bg-{color}-50 dark:bg-{color}-950 dark:hover:bg-{color}-900 dark:disabled:bg-{color}-950 dark:aria-disabled:bg-{color}-950 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-{color}-500 dark:focus-visible:ring-{color}-400 transition-none',
"ring-1 ring-inset ring-current ring-{color}-500 text-{color}-500 dark:hover:text-{color}-400 dark:hover:text-{color}-500 hover:bg-{color}-100 dark:hover:bg-{color}-900 disabled:bg-transparent disabled:hover:bg-transparent aria-disabled:bg-transparent focus-visible:ring-2 focus-visible:ring-{color}-500 dark:focus-visible:ring-{color}-400",
soft: "text-{color}-500 dark:text-{color}-400 bg-{color}-50 hover:bg-{color}-100 disabled:bg-{color}-50 aria-disabled:bg-{color}-50 dark:bg-{color}-950 dark:hover:bg-{color}-900 dark:disabled:bg-{color}-950 dark:aria-disabled:bg-{color}-950 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-{color}-500 dark:focus-visible:ring-{color}-400 transition-none",
ghost:
'text-{color}-500 dark:text-{color}-400 hover:bg-{color}-50 disabled:bg-transparent aria-disabled:bg-transparent dark:hover:bg-{color}-950 dark:disabled:bg-transparent dark:aria-disabled:bg-transparent focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-{color}-500 dark:focus-visible:ring-{color}-400',
link: 'text-{color}-500 hover:text-{color}-600 disabled:text-{color}-500 aria-disabled:text-{color}-500 dark:text-{color}-400 dark:hover:text-{color}-500 dark:disabled:text-{color}-400 dark:aria-disabled:text-{color}-400 underline-offset-4 hover:underline focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-{color}-500 dark:focus-visible:ring-{color}-400',
"text-{color}-500 dark:text-{color}-400 hover:bg-{color}-50 disabled:bg-transparent aria-disabled:bg-transparent dark:hover:bg-{color}-950 dark:disabled:bg-transparent dark:aria-disabled:bg-transparent focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-{color}-500 dark:focus-visible:ring-{color}-400",
link: "text-{color}-500 hover:text-{color}-600 disabled:text-{color}-500 aria-disabled:text-{color}-500 dark:text-{color}-400 dark:hover:text-{color}-500 dark:disabled:text-{color}-400 dark:aria-disabled:text-{color}-400 underline-offset-4 hover:underline focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-{color}-500 dark:focus-visible:ring-{color}-400",
},
default: {
size: 'sm',
color: 'primary',
variant: 'solid',
loadingIcon: 'loading',
size: "sm",
color: "primary",
variant: "solid",
loadingIcon: "loading",
},
}
};