ui
ui copied to clipboard
Sheet component with color prop
Would be great to have a basic "Sheet" component that "color" as prop. Here is some inspiration - https://vuetifyjs.com/en/components/sheets/#color
At the moment, there is no "sheet" component which can take a bg-color-pair that works for both light & dark modes, and accordingly set the content colors in contrast. Thank you!
Or, may be instead, you could add "color" prop to the container component, and re-purpose it? Thanks!
Another inspiration - https://flowbite-vue.com/components/flowbiteThemable/flowbiteThemable
I gave it a shot, and came up with this. Seem to work okay, this is just to explain the thought.
Here is a sample app using the below sheet component - https://github.com/TechAkayy/pg-nuxt-tailwindcss-nuxt-ui / https://stackblitz.com/github/TechAkayy/pg-nuxt-tailwindcss-nuxt-ui
USheet.vue
<script setup lang="ts">
import { computed } from 'vue'
import type { PropType } from 'vue'
import { defu } from 'defu'
// import { useAppConfig } from '#imports'
// TODO: Remove
// @ts-expect-error
import appConfig from '#build/app.config'
// TODO: Remove
// const appConfig = useAppConfig()
// eslint-disable-next-line vue/no-dupe-keys
const ui = computed<Partial<typeof appConfig.ui.sheet>>(() =>
defu({}, props.ui, appConfig.ui.sheet),
)
const props = defineProps({
ui: {
type: Object as PropType<Partial<typeof appConfig.ui.sheet>>,
default: () => appConfig.ui.sheet,
},
color: {
type: String,
default: () => appConfig.ui.sheet.default.color,
validator(value: string) {
return [
...appConfig.ui.colors,
...Object.keys(appConfig.ui.sheet.color),
appConfig.ui.sheet.default.color,
].includes(value)
},
},
variant: {
type: String,
default: () => appConfig.ui.sheet.default.variant,
validator(value: string) {
return [
...Object.keys(appConfig.ui.sheet.variant),
...Object.values(appConfig.ui.sheet.color).flatMap((value) =>
Object.keys(value),
),
].includes(value)
},
},
contrast: {
type: Boolean,
default: true,
},
tag: {
type: String,
default: 'div',
},
})
const classNames = (...classes) => {
return classes.filter(Boolean).join(' ')
}
const uiStyle = computed(() => {
const variant =
ui.value.color?.[props.color as string]?.[props.variant as string] ||
ui.value.variant[props.variant]
const variantClasses = variant?.replaceAll('{color}', props.color)
const variantClassesWithContrast = props.contrast
? variantClasses
: [
variantClasses
?.split(' ')
.filter((cls) => !cls.includes('text-'))
.join(' '),
ui.value.text,
]
return classNames(variantClassesWithContrast)
})
</script>
<template>
<component :is="tag" id="sheet" :class="[ui.shadow, uiStyle]">
<slot />
</component>
</template>
<style scoped></style>
app.config.ts
export default defineAppConfig({
ui: {
sheet: {
shadow: 'shadow-sm',
// Inspired by Material design guideline - https://m3.material.io/styles/color/the-color-system/tokens#e26e130c-fa67-48e1-81ca-d28f6e4ed398
text: 'text-gray-900 dark:text-white',
variant: {
solid:
'bg-{color}-600 dark:bg-{color}-200 text-white dark:text-{color}-800',
container:
'bg-{color}-100 dark:bg-{color}-700 text-{color}-900 dark:text-{color}-100',
},
color: {
gray: {
solid:
'bg-white dark:bg-{color}-950 text-{color}-900 dark:text-{color}-50',
container:
'bg-{color}-50 dark:bg-{color}-900 text-{color}-900 dark:text-{color}-100',
contained:
'bg-{color}-100 dark:bg-{color}-700 text-{color}-700 dark:text-{color}-200',
},
},
default: {
color: 'gray',
variant: 'solid',
},
},
},
})
tailwind.config.ts (safelist needs a little more work)
safelist: [
{
pattern:
/(bg|text)-(gray|primary)-(50|100|200|600|700|800|900|950)/,
},
{
pattern:
/(bg|text)-(gray|primary)-(50|100|200|600|700|800|900|950)/,
variants: ['dark'],
},
],
Why not use the UCard
component to achieve this? https://ui.nuxtlabs.com/layout/card
Thanks for the suggestion @benjamincanac :-) Looking at UCard preset, it sets only a background, and doesn't set color of any text or icons that goes on top of it. If we use the UCard and override with a "primary" bg, then we have to set the text color of the content to be at the right contrast, and these two bg & text combo needs an equivalent dark variant as well.
Overriding the bg, setting text color of the content, and removing the padding to use it as a layout "sheet", really means it's not really a card anymore, hence the idea to have a separate "Sheet" component.
My above sample works fine for me atm, and if you see this idea not fitting the library's goals, please feel free to close this request.
Meanwhile, the way you have architectured the library via presets & app.config.ts is amazing! Thanks!
You can use ui.card.body.background
, ui.card.header.background
and ui.card.footer.background
to achieve this I guess.