20260814173126

This commit is contained in:
oneao committed 2026-08-14 17:31:26 +08:00
1 parent 68de86aee9
commit b6f9a4c912
17 files changed
+1210 -544

No files matched your search

@@ -1,26 +0,0 @@
<script setup>
import { computed } from 'vue'
const props = defineProps({
variant: {
type: String,
default: 'default',
},
size: {
type: String,
default: 'default',
},
type: {
type: String,
default: 'button',
},
})
const classes = computed(() => ['button', `button-${props.variant}`, `button-size-${props.size}`])
</script>
<template>
<button :type="type" :class="classes">
<slot />
</button>
</template>
@@ -1,24 +1,133 @@
<script setup>
import { useTheme } from '../../composables/useTheme'
import { useTheme } from '@/theme/useTheme'
import { PRESETS } from '@/theme/color'
const { colorTheme, colorThemes, setColorTheme } = useTheme()
const { themeColor, setThemeColor } = useTheme()
function handleColorInput(event) {
setThemeColor(event.target.value)
}
</script>
<template>
<div class="color-theme-picker" role="group" aria-label="主题色">
<button
v-for="item in colorThemes"
:key="item.value"
class="color-swatch"
type="button"
:class="{ 'color-swatch-active': colorTheme === item.value }"
:style="{ '--swatch-color': item.color }"
:aria-label="`${item.label}主题色`"
:aria-pressed="colorTheme === item.value"
:title="item.label"
@click="setColorTheme(item.value)"
>
<span class="color-swatch-dot" aria-hidden="true" />
</button>
<div class="color-theme-picker">
<span class="color-theme-label">主题色</span>
<div class="theme-presets" aria-label="常用主题色">
<button
v-for="preset in PRESETS"
:key="preset.value"
class="theme-swatch"
:class="{ 'is-selected': themeColor === preset.value }"
type="button"
:style="{ '--swatch-color': preset.value }"
:aria-label="preset.name"
:aria-pressed="themeColor === preset.value"
:title="`${preset.name} ${preset.value}`"
@click="setThemeColor(preset.value)"
/>
</div>
<label class="custom-color" title="自定义主题色">
<input
class="color-theme-input"
type="color"
:value="themeColor"
aria-label="自定义主题色"
@input="handleColorInput"
/>
</label>
</div>
</template>
<style scoped>
.color-theme-picker {
display: inline-flex;
height: 2.5rem;
box-sizing: border-box;
align-items: center;
gap: 0.5rem;
padding: 0.25rem 0.375rem 0.25rem 0.75rem;
border: 1px solid var(--border);
border-radius: var(--radius);
background: var(--card);
color: var(--card-foreground);
}
.theme-presets {
display: inline-flex;
align-items: center;
gap: 0.25rem;
}
.theme-swatch {
width: 1.25rem;
height: 1.25rem;
flex: 0 0 auto;
padding: 0;
border: 1px solid color-mix(in srgb, var(--foreground) 18%, transparent);
border-radius: 50%;
background: var(--swatch-color);
cursor: pointer;
outline: none;
transition:
transform 120ms ease,
box-shadow 120ms ease;
}
.theme-swatch:hover {
transform: scale(1.12);
}
.theme-swatch.is-selected {
box-shadow:
0 0 0 2px var(--card),
0 0 0 4px var(--ring);
}
.theme-swatch:focus-visible {
box-shadow:
0 0 0 2px var(--card),
0 0 0 4px var(--ring);
}
.custom-color {
display: inline-flex;
align-items: center;
}
.color-theme-label {
font-size: 0.875rem;
font-weight: 500;
white-space: nowrap;
}
.color-theme-input {
width: 1.75rem;
height: 1.75rem;
padding: 0;
border: 1px solid var(--border);
border-radius: calc(var(--radius) - 0.25rem);
background: var(--background);
cursor: pointer;
outline: none;
}
.color-theme-input::-webkit-color-swatch-wrapper {
padding: 0.1875rem;
}
.color-theme-input::-webkit-color-swatch {
border: 0;
border-radius: calc(var(--radius) - 0.375rem);
}
.color-theme-input::-moz-color-swatch {
border: 0;
border-radius: calc(var(--radius) - 0.375rem);
}
.color-theme-input:focus-visible {
box-shadow:
0 0 0 2px var(--background),
0 0 0 4px color-mix(in srgb, var(--ring) 50%, transparent);
}
</style>
@@ -1,6 +1,6 @@
<script setup>
import Button from './Button.vue'
import { useTheme } from '../../composables/useTheme'
import Button from './button/button.vue'
import { useTheme } from '@/theme/useTheme'
const { theme, toggleTheme } = useTheme()
</script>
@@ -0,0 +1,22 @@
<script setup>
import { computed } from 'vue'
const props = defineProps({
type: {
type: String,
default: 'default',
},
})
const classes = computed(() => ['button', `button-${props.type}`])
</script>
<template>
<button :class="classes">
<slot />
</button>
</template>
<style lang="scss" scoped>
@use './index.scss';
</style>
@@ -0,0 +1,102 @@
.button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
white-space: nowrap;
border: 1px solid transparent;
border-radius: var(--radius);
font-weight: 500;
line-height: 1;
height: 2.5rem;
padding: 0 1rem;
font-size: 0.875rem;
outline: none;
transition:
color 120ms ease,
background-color 120ms ease,
border-color 120ms ease,
transform 80ms ease;
}
.button:active:not(:disabled) {
transform: scale(0.985);
}
.button-default {
color: var(--primary-foreground);
background: var(--primary);
}
.button-default:hover {
background: var(--primary-hover);
}
.button-default:active {
background: var(--primary-active);
}
.button-secondary {
color: var(--secondary-foreground);
background: var(--secondary);
}
.button-secondary:hover,
.button-ghost:hover {
background: var(--accent);
color: var(--accent-foreground);
}
.button-secondary:active,
.button-ghost:active {
background: color-mix(in srgb, var(--accent) 88%, var(--foreground));
color: var(--accent-foreground);
}
.button-outline {
color: var(--foreground);
border-color: var(--input);
background: var(--background);
}
.button-outline:hover {
color: var(--accent-foreground);
background: var(--accent);
}
.button-outline:active {
color: var(--accent-foreground);
background: color-mix(in srgb, var(--accent) 88%, var(--foreground));
}
.button-ghost {
color: var(--foreground);
background: transparent;
}
.button-destructive {
color: var(--destructive-foreground);
background: var(--destructive);
}
.button-destructive:hover {
background: color-mix(in srgb, var(--destructive) 90%, var(--background));
}
.button-destructive:active {
background: color-mix(in srgb, var(--destructive) 80%, var(--background));
}
.button-link {
color: var(--primary);
background: transparent;
text-underline-offset: 4px;
}
.button-link:hover {
text-decoration: underline;
}
.button-link:active {
color: var(--primary-active);
}