前端代码
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div class="grid grid-cols-3 gap-3 px-1">
|
||||
<div
|
||||
v-for="item in tabModes"
|
||||
:key="item.value"
|
||||
class="relative flex flex-col items-center gap-1.5 p-1.5 bg-container border rounded-lg cursor-pointer transition-colors duration-150 ease-in-out hover:border-primary"
|
||||
:class="modelValue === item.value ? '' : 'border-border'"
|
||||
:style="
|
||||
modelValue === item.value
|
||||
? { borderColor: primaryColor, boxShadow: `0 0 0 1px ${primaryColor}` }
|
||||
: {}
|
||||
"
|
||||
:title="item.label"
|
||||
@click="handleChange(item.value)"
|
||||
>
|
||||
<!-- 默认风格:扁平药丸 + 短竖线分隔,选中项主色弱底 -->
|
||||
<div
|
||||
v-if="item.value === 'button'"
|
||||
class="flex h-9 w-full items-center gap-1 overflow-hidden rounded bg-white px-1.5 dark:bg-gray-800"
|
||||
>
|
||||
<span class="h-4 w-9 rounded" :style="{ backgroundColor: primarySoft }" />
|
||||
<span class="h-3 w-px bg-gray-200 dark:bg-gray-600" />
|
||||
<span class="h-4 w-9 rounded bg-gray-100 dark:bg-gray-700" />
|
||||
<span class="h-3 w-px bg-gray-200 dark:bg-gray-600" />
|
||||
<span class="h-4 w-7 rounded bg-gray-100 dark:bg-gray-700" />
|
||||
</div>
|
||||
|
||||
<!-- Chrome 风格:交叠标签,选中项抬升 + 主色弱底 -->
|
||||
<div
|
||||
v-else-if="item.value === 'chrome'"
|
||||
class="flex h-9 w-full items-end overflow-hidden rounded bg-gray-100 px-1 dark:bg-gray-800"
|
||||
>
|
||||
<span class="h-5 w-9 rounded-t bg-gray-200 dark:bg-gray-700" />
|
||||
<span
|
||||
class="-ml-1 h-6 w-9 rounded-t"
|
||||
:style="{ backgroundColor: primarySoft }"
|
||||
/>
|
||||
<span class="-ml-1 h-5 w-9 rounded-t bg-gray-200 dark:bg-gray-700" />
|
||||
</div>
|
||||
|
||||
<!-- Slider 风格:底部 2px 主色指示条 + 激活弱底 -->
|
||||
<div
|
||||
v-else-if="item.value === 'slider'"
|
||||
class="flex h-9 w-full items-end rounded bg-white px-1 dark:bg-gray-800"
|
||||
>
|
||||
<span class="mr-0.5 flex h-6 flex-1 items-center justify-center rounded-t-sm border-b-2 border-transparent bg-gray-50 dark:bg-gray-700">
|
||||
<span class="h-2 w-5 rounded-sm bg-gray-200 dark:bg-gray-600" />
|
||||
</span>
|
||||
<span
|
||||
class="mr-0.5 flex h-6 flex-1 items-center justify-center rounded-t-sm border-b-2"
|
||||
:style="{ borderColor: primaryColor, backgroundColor: primarySoft }"
|
||||
>
|
||||
<span class="h-2 w-5 rounded-sm" :style="{ backgroundColor: primaryColor }" />
|
||||
</span>
|
||||
<span class="flex h-6 flex-1 items-center justify-center rounded-t-sm border-b-2 border-transparent bg-gray-50 dark:bg-gray-700">
|
||||
<span class="h-2 w-4 rounded-sm bg-gray-200 dark:bg-gray-600" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span
|
||||
class="text-xs"
|
||||
:style="modelValue === item.value ? { color: primaryColor } : {}"
|
||||
>
|
||||
{{ item.label }}
|
||||
</span>
|
||||
|
||||
<svg-icon
|
||||
v-if="modelValue === item.value"
|
||||
icon="lucide:check"
|
||||
class="absolute top-1 right-1"
|
||||
:style="{ color: primaryColor }"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useThemeStore } from '@/pinia'
|
||||
|
||||
defineOptions({
|
||||
name: 'TabModeSelector'
|
||||
})
|
||||
|
||||
defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: 'button'
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const themeStore = useThemeStore()
|
||||
const { settings } = storeToRefs(themeStore)
|
||||
const primaryColor = computed(() => settings.value.themeColor)
|
||||
// 主色弱底(真实合成色,跟随换肤;预览只示意,不必严格等于实际标签底色)
|
||||
const primarySoft = 'rgb(var(--primary-color) / 0.15)'
|
||||
|
||||
const tabModes = [
|
||||
{ value: 'button', label: '默认' },
|
||||
{ value: 'chrome', label: 'Chrome' },
|
||||
{ value: 'slider', label: '指示条' }
|
||||
]
|
||||
|
||||
const handleChange = (value) => {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user