mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-23 00:15:05 +01:00
feat(module): generate tailwindcss theme colors (#2967)
Co-authored-by: HugoRCD <hugo.richard@epitech.eu> Co-authored-by: Sébastien Chopin <seb@nuxt.com>
This commit is contained in:
@@ -5,7 +5,8 @@ export default defineAppConfig({
|
||||
duration: 5000
|
||||
},
|
||||
theme: {
|
||||
radius: 0.25
|
||||
radius: 0.25,
|
||||
blackAsPrimary: false
|
||||
},
|
||||
ui: {
|
||||
colors: {
|
||||
|
||||
@@ -50,6 +50,7 @@ const links = computed(() => [{
|
||||
|
||||
const color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white')
|
||||
const radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
|
||||
const blackAsPrimary = computed(() => appConfig.theme.blackAsPrimary ? `:root { --ui-primary: black; } .dark { --ui-primary: white; }` : ':root {}')
|
||||
|
||||
useHead({
|
||||
meta: [
|
||||
@@ -61,7 +62,8 @@ useHead({
|
||||
{ rel: 'canonical', href: `https://ui.nuxt.com${withoutTrailingSlash(route.path)}` }
|
||||
],
|
||||
style: [
|
||||
{ innerHTML: radius, id: 'nuxt-ui-radius', tagPriority: -2 }
|
||||
{ innerHTML: radius, id: 'nuxt-ui-radius', tagPriority: -2 },
|
||||
{ innerHTML: blackAsPrimary, id: 'nuxt-ui-black-as-primary', tagPriority: -2 }
|
||||
],
|
||||
htmlAttrs: {
|
||||
lang: 'en'
|
||||
|
||||
@@ -1,3 +1,64 @@
|
||||
<script setup lang="ts">
|
||||
import colors from 'tailwindcss/colors'
|
||||
import { omit } from '#ui/utils'
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
const colorMode = useColorMode()
|
||||
|
||||
const neutralColors = ['slate', 'gray', 'zinc', 'neutral', 'stone']
|
||||
const neutral = computed({
|
||||
get() {
|
||||
return appConfig.ui.colors.neutral
|
||||
},
|
||||
set(option) {
|
||||
appConfig.ui.colors.neutral = option
|
||||
window.localStorage.setItem('nuxt-ui-neutral', appConfig.ui.colors.neutral)
|
||||
}
|
||||
})
|
||||
|
||||
const colorsToOmit = ['inherit', 'current', 'transparent', 'black', 'white', ...neutralColors]
|
||||
const primaryColors = Object.keys(omit(colors, colorsToOmit as any))
|
||||
const primary = computed({
|
||||
get() {
|
||||
return appConfig.ui.colors.primary
|
||||
},
|
||||
set(option) {
|
||||
appConfig.ui.colors.primary = option
|
||||
window.localStorage.setItem('nuxt-ui-primary', appConfig.ui.colors.primary)
|
||||
setBlackAsPrimary(false)
|
||||
}
|
||||
})
|
||||
|
||||
const radiuses = [0, 0.125, 0.25, 0.375, 0.5]
|
||||
const radius = computed({
|
||||
get() {
|
||||
return appConfig.theme.radius
|
||||
},
|
||||
set(option) {
|
||||
appConfig.theme.radius = option
|
||||
window.localStorage.setItem('nuxt-ui-radius', String(appConfig.theme.radius))
|
||||
}
|
||||
})
|
||||
|
||||
const modes = [
|
||||
{ label: 'light', icon: appConfig.ui.icons.light },
|
||||
{ label: 'dark', icon: appConfig.ui.icons.dark }
|
||||
]
|
||||
const mode = computed({
|
||||
get() {
|
||||
return colorMode.value
|
||||
},
|
||||
set(option) {
|
||||
colorMode.preference = option
|
||||
}
|
||||
})
|
||||
|
||||
function setBlackAsPrimary(value: boolean) {
|
||||
appConfig.theme.blackAsPrimary = value
|
||||
window.localStorage.setItem('nuxt-ui-black-as-primary', String(value))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UPopover :ui="{ content: 'w-72 px-6 py-4 flex flex-col gap-4' }">
|
||||
<template #default="{ open }">
|
||||
@@ -18,12 +79,22 @@
|
||||
</legend>
|
||||
|
||||
<div class="grid grid-cols-3 gap-1 -mx-2">
|
||||
<ThemePickerButton
|
||||
chip="primary"
|
||||
label="Black"
|
||||
:selected="appConfig.theme.blackAsPrimary"
|
||||
@click="setBlackAsPrimary(true)"
|
||||
>
|
||||
<template #leading>
|
||||
<span class="inline-block w-2 h-2 rounded-full bg-black dark:bg-white" />
|
||||
</template>
|
||||
</ThemePickerButton>
|
||||
<ThemePickerButton
|
||||
v-for="color in primaryColors"
|
||||
:key="color"
|
||||
:label="color"
|
||||
:chip="color"
|
||||
:selected="primary === color"
|
||||
:selected="!appConfig.theme.blackAsPrimary && primary === color"
|
||||
@click="primary = color"
|
||||
/>
|
||||
</div>
|
||||
@@ -81,60 +152,3 @@
|
||||
</template>
|
||||
</UPopover>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import colors from 'tailwindcss/colors'
|
||||
import { omit } from '#ui/utils'
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
const colorMode = useColorMode()
|
||||
|
||||
// Computed
|
||||
|
||||
const neutralColors = ['slate', 'gray', 'zinc', 'neutral', 'stone']
|
||||
const neutral = computed({
|
||||
get() {
|
||||
return appConfig.ui.colors.neutral
|
||||
},
|
||||
set(option) {
|
||||
appConfig.ui.colors.neutral = option
|
||||
window.localStorage.setItem('nuxt-ui-neutral', appConfig.ui.colors.neutral)
|
||||
}
|
||||
})
|
||||
|
||||
const colorsToOmit = ['inherit', 'current', 'transparent', 'black', 'white', ...neutralColors]
|
||||
const primaryColors = Object.keys(omit(colors, colorsToOmit as any))
|
||||
const primary = computed({
|
||||
get() {
|
||||
return appConfig.ui.colors.primary
|
||||
},
|
||||
set(option) {
|
||||
appConfig.ui.colors.primary = option
|
||||
window.localStorage.setItem('nuxt-ui-primary', appConfig.ui.colors.primary)
|
||||
}
|
||||
})
|
||||
|
||||
const radiuses = [0, 0.125, 0.25, 0.375, 0.5]
|
||||
const radius = computed({
|
||||
get() {
|
||||
return appConfig.theme.radius
|
||||
},
|
||||
set(option) {
|
||||
appConfig.theme.radius = option
|
||||
window.localStorage.setItem('nuxt-ui-radius', String(appConfig.theme.radius))
|
||||
}
|
||||
})
|
||||
|
||||
const modes = [
|
||||
{ label: 'light', icon: appConfig.ui.icons.light },
|
||||
{ label: 'dark', icon: appConfig.ui.icons.dark }
|
||||
]
|
||||
const mode = computed({
|
||||
get() {
|
||||
return colorMode.value
|
||||
},
|
||||
set(option) {
|
||||
colorMode.preference = option
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
label: string
|
||||
icon?: string
|
||||
chip?: string
|
||||
selected?: boolean
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UButton
|
||||
size="sm"
|
||||
@@ -8,23 +17,16 @@
|
||||
class="capitalize ring-[var(--ui-border)] rounded-[var(--ui-radius)] text-[11px]"
|
||||
>
|
||||
<template v-if="chip" #leading>
|
||||
<span
|
||||
class="inline-block w-2 h-2 rounded-full"
|
||||
:class="`bg-[var(--color-light)] dark:bg-[var(--color-dark)]`"
|
||||
:style="{
|
||||
'--color-light': `var(--color-${chip}-500)`,
|
||||
'--color-dark': `var(--color-${chip}-400)`
|
||||
}"
|
||||
/>
|
||||
<slot name="leading">
|
||||
<span
|
||||
class="inline-block w-2 h-2 rounded-full"
|
||||
:class="`bg-[var(--color-light)] dark:bg-[var(--color-dark)]`"
|
||||
:style="{
|
||||
'--color-light': `var(--color-${chip}-500)`,
|
||||
'--color-dark': `var(--color-${chip}-400)`
|
||||
}"
|
||||
/>
|
||||
</slot>
|
||||
</template>
|
||||
</UButton>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
label: string
|
||||
icon?: string
|
||||
chip?: string
|
||||
selected?: boolean
|
||||
}>()
|
||||
</script>
|
||||
|
||||
@@ -18,9 +18,17 @@ export default defineNuxtPlugin({
|
||||
}
|
||||
}
|
||||
|
||||
function updateBlackAsPrimary() {
|
||||
const blackAsPrimary = localStorage.getItem('nuxt-ui-black-as-primary')
|
||||
if (blackAsPrimary) {
|
||||
appConfig.theme.blackAsPrimary = blackAsPrimary === 'true'
|
||||
}
|
||||
}
|
||||
|
||||
updateColor('primary')
|
||||
updateColor('neutral')
|
||||
updateRadius()
|
||||
updateBlackAsPrimary()
|
||||
}
|
||||
|
||||
if (import.meta.server) {
|
||||
@@ -31,10 +39,12 @@ export default defineNuxtPlugin({
|
||||
|
||||
if (localStorage.getItem('nuxt-ui-primary')) {
|
||||
const primaryColor = localStorage.getItem('nuxt-ui-primary');
|
||||
html = html.replace(
|
||||
/(--ui-color-primary-\\d{2,3}:\\s*var\\()--color-${appConfig.ui.colors.primary}-(\\d{2,3}\\))/g,
|
||||
\`$1--color-\${primaryColor}-$2\`
|
||||
);
|
||||
if (primaryColor !== 'black') {
|
||||
html = html.replace(
|
||||
/(--ui-color-primary-\\d{2,3}:\\s*var\\()--color-${appConfig.ui.colors.primary}-(\\d{2,3}\\))/g,
|
||||
\`$1--color-\${primaryColor}-$2\`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (localStorage.getItem('nuxt-ui-neutral')) {
|
||||
const neutralColor = localStorage.getItem('nuxt-ui-neutral');
|
||||
@@ -56,6 +66,14 @@ export default defineNuxtPlugin({
|
||||
`.replace(/\s+/g, ' '),
|
||||
type: 'text/javascript',
|
||||
tagPriority: -1
|
||||
}, {
|
||||
innerHTML: `
|
||||
if (localStorage.getItem('nuxt-ui-black-as-primary') === 'true') {
|
||||
document.querySelector('style#nuxt-ui-black-as-primary').innerHTML = ':root { --ui-primary: black; } .dark { --ui-primary: white; }';
|
||||
} else {
|
||||
document.querySelector('style#nuxt-ui-black-as-primary').innerHTML = '';
|
||||
}
|
||||
`.replace(/\s+/g, ' ')
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user