refactor(stage-web): providers ui

Co-authored-by: Rizumu Ayaka <19204772+LittleSound@users.noreply.github.com>
This commit is contained in:
Neko Ayaka
2025-02-22 21:43:42 +08:00
co-authored by Rizumu Ayaka
parent 9889767d22
commit e993849a5f
3 changed files with 58 additions and 61 deletions
@@ -1,7 +1,6 @@
<script setup lang="ts">
import { TransitionVertical } from '@proj-airi/stage-ui/components'
import { CollapsibleContent, CollapsibleRoot, CollapsibleTrigger } from 'radix-vue'
import { reactive, ref } from 'vue'
import { Collapsable } from '@proj-airi/stage-ui/components'
import { ref } from 'vue'
interface ModelProvider {
id: string
@@ -35,54 +34,50 @@ const providers = ref<ModelProvider[]>([
],
},
])
const openedProviders = reactive<Record<string, boolean>>(Object.fromEntries(providers.value.map(provider => [provider.id, false])))
</script>
<template>
<div class="space-y-2">
<div v-for="(provider) in providers" :key="provider.id">
<CollapsibleRoot :default-open="false" w-full>
<CollapsibleTrigger
bg="zinc-100 dark:zinc-800"
hover="bg-zinc-200 dark:bg-zinc-700"
transition="all ease-in-out duration-250"
w-full flex items-center gap-1.5 rounded-lg px-4 py-3
@click="openedProviders[provider.id] = !openedProviders[provider.id]"
>
<div flex="~ row 1" items-center gap-1.5>
<div :class="provider.icon" class="size-6" />
<div class="font-medium">
{{ provider.name }} {{ openedProviders[provider.id] }}
</div>
</div>
<div transform transition="transform duration-250" :class="{ 'rotate-180': openedProviders[provider.id] }">
<div i-solar:alt-arrow-down-bold-duotone />
</div>
</CollapsibleTrigger>
<CollapsibleContent>
<TransitionVertical>
<div v-if="openedProviders[provider.id]" p-4>
<div class="space-y-4">
<div class="flex items-center justify-between">
<div class="text-sm font-medium">
API Key
</div>
<input
class="rounded bg-zinc-200 px-2 py-1 text-sm dark:bg-zinc-800"
placeholder="Enter API key"
>
</div>
<div class="space-y-2">
<div class="text-sm font-medium">
Available Models
</div>
</div>
<Collapsable w-full>
<template #trigger="slotProps">
<button
bg="zinc-100 dark:zinc-800"
hover="bg-zinc-200 dark:bg-zinc-700"
transition="all ease-in-out duration-250"
w-full flex items-center gap-1.5 rounded-lg px-4 py-3
@click="slotProps.setVisible(!slotProps.visible)"
>
<div flex="~ row 1" items-center gap-1.5>
<div :class="provider.icon" class="size-6" />
<div class="font-medium">
{{ provider.name }}
</div>
</div>
</TransitionVertical>
</CollapsibleContent>
</CollapsibleRoot>
<div transform transition="transform duration-250" :class="{ 'rotate-180': slotProps.visible }">
<div i-solar:alt-arrow-down-bold-duotone />
</div>
</button>
</template>
<div p-4>
<div class="space-y-4">
<div class="flex items-center justify-between">
<div class="text-sm font-medium">
API Key
</div>
<input
class="rounded bg-zinc-200 px-2 py-1 text-sm dark:bg-zinc-800"
placeholder="Enter API key"
>
</div>
<div class="space-y-2">
<div class="text-sm font-medium">
Available Models
</div>
</div>
</div>
</div>
</Collapsable>
</div>
</div>
</template>
@@ -7,30 +7,32 @@ const props = defineProps<{
default?: boolean
label?: string
}>()
const isVisible = defineModel<boolean>({ default: false })
const visible = defineModel<boolean>({ default: false })
watchEffect(() => {
if (props.default != null) {
isVisible.value = !!props.default
visible.value = !!props.default
}
})
function setVisible(value: boolean) {
visible.value = value
}
</script>
<template>
<div flex="~ col" border="~ gray/25 rounded-lg" divide="y dashed gray/25" of-clip shadow-sm>
<button
sticky top-0 z-10 flex items-center justify-between px2 py1 text-sm backdrop-blur-xl
@click="isVisible = !isVisible"
>
<span>
<slot name="label">
<div>
<slot name="trigger" v-bind="{ visible, setVisible }">
<button
sticky top-0 z-10 flex items-center justify-between px2 py1 text-sm backdrop-blur-xl
@click="visible = !visible"
>
<span>
{{ props.label ?? 'Collapsable' }}
</slot>
</span> <span op50>{{ isVisible ? '▲' : '▼' }}</span>
</button>
</span> <span op50>{{ visible ? '▲' : '▼' }}</span>
</button>
</slot>
<TransitionVertical>
<div v-if="isVisible" w-full>
<slot />
</div>
<slot v-if="visible" />
</TransitionVertical>
</div>
</template>
@@ -82,7 +82,7 @@ defineExpose({
<div font-mono>
<span>{{ $t('stage.viewers.debug-menu.vrm.model.title') }}</span>
</div>
<Collapsable h-fit w-full>
<Collapsable h-fit w-full flex="~ col" border="~ gray/25 rounded-lg" divide="y dashed gray/25" of-clip shadow-sm>
<template #label>
<span font-mono>{{ $t('stage.viewers.debug-menu.vrm.camera') }}</span>
</template>
@@ -118,7 +118,7 @@ defineExpose({
</div>
</div>
</Collapsable>
<Collapsable h-fit w-full>
<Collapsable h-fit w-full flex="~ col" border="~ gray/25 rounded-lg" divide="y dashed gray/25" of-clip shadow-sm>
<template #label>
<span font-mono>{{ $t('stage.viewers.debug-menu.vrm.model.title') }}</span>
</template>