style(stage-ui,stage-tamagotchi): improved style

This commit is contained in:
Neko Ayaka
2025-07-03 13:25:09 +08:00
parent 5432106b6e
commit 7bda256ccf
4 changed files with 67 additions and 34 deletions
@@ -4,17 +4,17 @@ import { Select } from '@proj-airi/ui'
const props = defineProps<{
label: string
description?: string
options: { label: string, value: string | number }[]
options?: { label: string, value: string | number }[]
placeholder?: string
disabled?: boolean
}>()
const modelValue = defineModel<string>({ required: true })
const modelValue = defineModel<string>({ required: false })
</script>
<template>
<label flex="~ col gap-4">
<div flex="~ row col" justify-center gap-2>
<div flex="~ row" items-center gap-2>
<div flex="1">
<div class="flex items-center gap-1 text-sm font-medium">
{{ props.label }}
@@ -23,13 +23,15 @@ const modelValue = defineModel<string>({ required: true })
{{ props.description }}
</div>
</div>
<Select
v-model="modelValue"
:options="props.options"
:placeholder="props.placeholder"
:disabled="props.disabled"
:title="label"
/>
<slot>
<Select
v-model="modelValue"
:options="props.options"
:placeholder="props.placeholder"
:disabled="props.disabled"
:title="label"
/>
</slot>
</div>
</label>
</template>
@@ -0,0 +1,28 @@
<script setup lang="ts">
import { inject } from 'vue'
const props = defineProps<{
value: string | number
label?: string
active?: boolean
}>()
const selectOption = inject('selectOption') as (value: string | number) => void
const hide = inject('hide') as () => void
</script>
<template>
<div
v-bind="{ ...$attrs, class: null, style: null }"
class="cursor-pointer rounded px-2 py-1.5 text-sm text-neutral-700 hover:bg-neutral-100 dark:text-neutral-200 dark:hover:bg-neutral-800"
:class="{ 'bg-neutral-100 dark:bg-neutral-800': props.active }"
@click="() => {
selectOption(props.value)
hide()
}"
>
<slot>
{{ props.label }}
</slot>
</div>
</template>
@@ -1,24 +1,29 @@
<script setup lang="ts">
import { Dropdown as VDropdown } from 'floating-vue'
import { computed } from 'vue'
import { provide, ref } from 'vue'
import UIOption from './Option.vue'
const props = defineProps<{
options: { label: string, value: string | number }[]
options?: { label: string, value: string | number }[]
placeholder?: string
disabled?: boolean
title?: string
}>()
const modelValue = defineModel<string | number>({ required: true })
const selectedLabel = computed(() => {
const selected = props.options.find(opt => opt.value === modelValue.value)
return selected ? selected.label : props.placeholder
})
const show = ref(false)
const modelValue = defineModel<string | number>({ required: false })
function selectOption(value: string | number) {
modelValue.value = value
}
function handleHide() {
show.value = false
}
provide('selectOption', selectOption)
provide('hide', handleHide)
</script>
<template>
@@ -31,27 +36,24 @@ function selectOption(value: string | number) {
:class="{ 'pointer-events-none': props.disabled }"
>
<div class="flex-1 truncate">
<slot :label="selectedLabel">
{{ selectedLabel }}
</slot>
<slot :value="modelValue" />
</div>
<div i-solar:alt-arrow-down-bold-duotone class="h-3.5 w-3.5 text-neutral-500 dark:text-neutral-400" />
<div i-solar:alt-arrow-down-linear class="h-3.5 w-3.5 text-neutral-500 dark:text-neutral-400" />
</div>
<template #popper="{ hide }">
<div class="min-w-[160px] flex flex-col gap-0.5 border border-neutral-200 rounded-lg bg-white p-1 shadow-lg dark:border-neutral-800 dark:bg-neutral-900">
<div
v-for="option of props.options"
v-bind="{ ...$attrs, class: null, style: null }"
:key="option.value"
class="cursor-pointer rounded px-2 py-1.5 text-sm text-neutral-700 hover:bg-neutral-100 dark:text-neutral-200 dark:hover:bg-neutral-800"
:class="{
'bg-neutral-100 dark:bg-neutral-800': modelValue === option.value,
}"
@click="selectOption(option.value); hide()"
>
{{ option.label }}
</div>
<slot name="options" :hide="hide">
<template v-if="props.options && props.options.length">
<UIOption
v-for="option of props.options"
:key="option.value"
:value="option.value"
:label="option.label"
:active="modelValue === option.value"
/>
</template>
</slot>
</div>
</template>
</VDropdown>
@@ -1 +1,2 @@
export { default as Option } from './Option.vue'
export { default as Select } from './Select.vue'