chore(stage-ui|stage-tamagotchi): icon
This commit is contained in:
@@ -330,6 +330,9 @@ settings:
|
||||
description: x.ai
|
||||
title: xAI
|
||||
title: Providers
|
||||
scene:
|
||||
description: Configure the environment where the character lives
|
||||
title: Scene
|
||||
themes:
|
||||
description: Customize your stage!
|
||||
sections:
|
||||
|
||||
@@ -317,6 +317,9 @@ settings:
|
||||
description: X.AI
|
||||
title: xAI
|
||||
title: 提供商
|
||||
scene:
|
||||
description: 配置角色所在环境
|
||||
title: 场景
|
||||
themes:
|
||||
description: 自定义你的舞台外观!
|
||||
sections:
|
||||
|
||||
@@ -31,6 +31,15 @@ const sortOption = ref('nameAsc')
|
||||
|
||||
const inputFiles = ref<File[]>([])
|
||||
|
||||
// Card list data structure
|
||||
interface CardItem {
|
||||
id: string
|
||||
name: string
|
||||
description?: string
|
||||
deprecated?: boolean
|
||||
customizable?: boolean
|
||||
}
|
||||
|
||||
watch(inputFiles, async (newFiles) => {
|
||||
const file = newFiles[0]
|
||||
if (!file)
|
||||
@@ -49,15 +58,6 @@ watch(inputFiles, async (newFiles) => {
|
||||
}
|
||||
})
|
||||
|
||||
// Card list data structure
|
||||
interface CardItem {
|
||||
id: string
|
||||
name: string
|
||||
description?: string
|
||||
deprecated?: boolean
|
||||
customizable?: boolean
|
||||
}
|
||||
|
||||
// Transform cards Map to array for display
|
||||
const cardsArray = computed<CardItem[]>(() =>
|
||||
Array.from(cards.value.entries()).map(([id, card]) => ({
|
||||
@@ -221,16 +221,18 @@ function getModuleShortName(id: string, module: 'consciousness' | 'voice') {
|
||||
<InputFile v-model="inputFiles" accept="*.json">
|
||||
<template #default="{ isDragging }">
|
||||
<template v-if="!isDragging">
|
||||
<div i-solar:upload-square-line-duotone mb-4 text-5xl text="neutral-400 dark:neutral-500" />
|
||||
<p font-medium text="center neutral-600 dark:neutral-300">
|
||||
{{ t('settings.pages.card.upload') }}
|
||||
</p>
|
||||
<p text="center neutral-500 dark:neutral-400" mt-2 text-sm>
|
||||
{{ t('settings.pages.card.upload_desc') }}) }}
|
||||
</p>
|
||||
<div flex flex-col items-center>
|
||||
<div i-solar:upload-square-line-duotone mb-4 text-5xl text="neutral-400 dark:neutral-500" />
|
||||
<p font-medium text="neutral-600 dark:neutral-300">
|
||||
{{ t('settings.pages.card.upload') }}
|
||||
</p>
|
||||
<p text="neutral-500 dark:neutral-400" mt-2 text-sm>
|
||||
{{ t('settings.pages.card.upload_desc') }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="text-center">
|
||||
<div flex flex-col items-center>
|
||||
<div i-solar:upload-minimalistic-bold class="text-primary-500 dark:text-primary-400 mb-2 text-5xl" />
|
||||
<p font-medium text="primary-600 dark:primary-300">
|
||||
{{ t('settings.pages.card.drop_here') }}
|
||||
@@ -304,12 +306,14 @@ function getModuleShortName(id: string, module: 'consciousness' | 'voice') {
|
||||
<div
|
||||
v-motion
|
||||
text="neutral-200/50 dark:neutral-600/20" pointer-events-none
|
||||
fixed top="[72dvh]" right--15 z--1
|
||||
fixed top="[calc(100dvh-15rem)]" bottom-0 right--5 z--1
|
||||
:initial="{ scale: 0.9, opacity: 0, x: 20 }"
|
||||
:enter="{ scale: 1, opacity: 1, x: 0 }"
|
||||
:duration="250"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-lucide:id-card />
|
||||
<div text="60" i-solar:emoji-funny-square-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -269,8 +269,9 @@ watch(() => [settings.usePageSpecificTransitions, settings.disableTransitions],
|
||||
:initial="{ scale: 0.9, opacity: 0, rotate: 30 }"
|
||||
:enter="{ scale: 1, opacity: 1, rotate: 0 }"
|
||||
:duration="250"
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-lucide:paintbrush />
|
||||
<div text="60" i-solar:filters-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -5,8 +5,11 @@ import { computed, nextTick, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import IconAnimation from '../../components/IconAnimation.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const iconAnimationStarted = ref(false)
|
||||
const iconAnimation = ref<InstanceType<typeof IconAnimation>>()
|
||||
const resolveAnimation = ref<() => void>()
|
||||
const { t } = useI18n()
|
||||
|
||||
@@ -15,6 +18,10 @@ const animationPosition = ref('')
|
||||
const showAnimationComponent = ref(false)
|
||||
const settingsStore = useSettings()
|
||||
|
||||
function handleAnimationEnded() {
|
||||
resolveAnimation.value?.()
|
||||
}
|
||||
|
||||
async function handleIconItemClick(event: MouseEvent, setting: typeof settings.value[0]) {
|
||||
const target = event.currentTarget as HTMLElement
|
||||
const iconElement = target.querySelector('.menu-icon-item-icon') as HTMLElement
|
||||
@@ -56,37 +63,43 @@ const settings = computed(() => [
|
||||
{
|
||||
title: t('settings.pages.card.title'),
|
||||
description: t('settings.pages.card.description'),
|
||||
icon: 'i-lucide:id-card',
|
||||
icon: 'i-solar:emoji-funny-square-bold-duotone',
|
||||
to: '/settings/airi-card',
|
||||
},
|
||||
{
|
||||
title: t('settings.pages.modules.title'),
|
||||
description: t('settings.pages.modules.description'),
|
||||
icon: 'i-lucide:blocks',
|
||||
icon: 'i-solar:layers-bold-duotone',
|
||||
to: '/settings/modules',
|
||||
},
|
||||
{
|
||||
title: t('settings.pages.scene.title'),
|
||||
description: t('settings.pages.scene.description'),
|
||||
icon: 'i-solar:armchair-2-bold-duotone',
|
||||
to: '/settings/scene',
|
||||
},
|
||||
{
|
||||
title: t('settings.pages.models.title'),
|
||||
description: t('settings.pages.models.description'),
|
||||
icon: 'i-lucide:person-standing',
|
||||
icon: 'i-solar:people-nearby-bold-duotone',
|
||||
to: '/settings/models',
|
||||
},
|
||||
{
|
||||
title: t('settings.pages.memory.title'),
|
||||
description: t('settings.pages.memory.description'),
|
||||
icon: 'i-lucide:sprout',
|
||||
icon: 'i-solar:leaf-bold-duotone',
|
||||
to: '/settings/memory',
|
||||
},
|
||||
{
|
||||
title: t('settings.pages.providers.title'),
|
||||
description: t('settings.pages.providers.description'),
|
||||
icon: 'i-lucide:brain',
|
||||
icon: 'i-solar:box-minimalistic-bold-duotone',
|
||||
to: '/settings/providers',
|
||||
},
|
||||
{
|
||||
title: t('settings.pages.themes.title'),
|
||||
description: t('settings.pages.themes.description'),
|
||||
icon: 'i-lucide:paintbrush',
|
||||
icon: 'i-solar:filters-bold-duotone',
|
||||
to: '/settings/appearance',
|
||||
},
|
||||
])
|
||||
@@ -126,15 +139,29 @@ const settings = computed(() => [
|
||||
@click="(e: MouseEvent) => handleIconItemClick(e, setting)"
|
||||
/>
|
||||
</div>
|
||||
<IconAnimation
|
||||
v-if="showAnimationComponent && !settingsStore.disableTransitions && settingsStore.usePageSpecificTransitions"
|
||||
ref="iconAnimation"
|
||||
:icon="animationIcon"
|
||||
:icon-size="6 * 1.2"
|
||||
:position="animationPosition"
|
||||
:duration="1000"
|
||||
text-color="text-neutral-400/50 dark:text-neutral-600/20"
|
||||
:started="iconAnimationStarted"
|
||||
@animation-ended.once="handleAnimationEnded"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
v-motion
|
||||
text="neutral-200/50 dark:neutral-600/20" pointer-events-none
|
||||
fixed top="[75dvh]" right--15 z--1
|
||||
:initial="{ scale: 0.9, opacity: 0, rotate: 45 }"
|
||||
fixed top="[calc(100dvh-12rem)]" bottom-0 right--10 z--1
|
||||
:initial="{ scale: 0.9, opacity: 0, rotate: 180 }"
|
||||
:enter="{ scale: 1, opacity: 1, rotate: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div v-motion text="60" i-lucide:cog />
|
||||
<div v-motion text="60" i-solar:settings-bold-duotone />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -38,12 +38,14 @@ const { t } = useI18n()
|
||||
<div
|
||||
v-motion
|
||||
text="neutral-200/50 dark:neutral-600/20" pointer-events-none
|
||||
fixed top="[65dvh]" right--15 z--1
|
||||
fixed top="[calc(100dvh-20rem)]" bottom-0 right--15 z--1
|
||||
:initial="{ scale: 0.9, opacity: 0, y: 40 }"
|
||||
:enter="{ scale: 1, opacity: 1, y: 0 }"
|
||||
:duration="250"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-lucide:sprout />
|
||||
<div text="60" i-solar:leaf-bold-duotone />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import Live2DCanvas from '@proj-airi/stage-ui/components/Live2D/Canvas.vue'
|
||||
import Live2DModel from '@proj-airi/stage-ui/components/Live2D/Model.vue'
|
||||
import { useSettings } from '@proj-airi/stage-ui/stores'
|
||||
import { useElementBounding } from '@vueuse/core'
|
||||
import { Vibrant } from 'node-vibrant/browser'
|
||||
import { ref } from 'vue'
|
||||
@@ -9,13 +8,13 @@ import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import Live2DSettings from '../../../components/Widgets/Live2DSettings.vue'
|
||||
import { useIconAnimation } from '../../../composables/useIconAnimation'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const live2dContainerRef = ref<HTMLDivElement>()
|
||||
const live2dCanvasRef = ref<InstanceType<typeof Live2DCanvas>>()
|
||||
const { width, height } = useElementBounding(live2dContainerRef)
|
||||
const settingsStore = useSettings()
|
||||
|
||||
const palette = ref<string[]>([])
|
||||
|
||||
@@ -40,6 +39,12 @@ async function extractColorsFromModel() {
|
||||
URL.revokeObjectURL(frameUrl)
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
iconAnimationStarted,
|
||||
showIconAnimation,
|
||||
animationIcon,
|
||||
} = useIconAnimation('i-solar:people-nearby-bold-duotone')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -70,8 +75,29 @@ async function extractColorsFromModel() {
|
||||
<Live2DSettings w="50%" h="80vh" :palette="palette" @extract-colors-from-model="extractColorsFromModel" />
|
||||
</div>
|
||||
|
||||
<div v-if="!settingsStore.usePageSpecificTransitions" text="neutral-200/50 dark:neutral-500/20" pointer-events-none fixed bottom-0 right-0 z--1 translate-x-10 translate-y-10>
|
||||
<div text="40" i-lucide:person-standing />
|
||||
<IconAnimation
|
||||
v-if="showIconAnimation"
|
||||
:z-index="-1"
|
||||
:icon="animationIcon"
|
||||
:icon-size="12"
|
||||
:duration="1000"
|
||||
:started="iconAnimationStarted"
|
||||
:is-reverse="true"
|
||||
position="calc(100dvw - 9.5rem), calc(100dvh - 9.5rem)"
|
||||
text-color="text-neutral-200/50 dark:text-neutral-600/20"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
v-motion
|
||||
text="neutral-200/50 dark:neutral-600/20" pointer-events-none
|
||||
fixed top="[calc(100dvh-15rem)]" bottom-0 right--5 z--1
|
||||
:initial="{ scale: 0.9, opacity: 0, y: 15 }"
|
||||
:enter="{ scale: 1, opacity: 1, y: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-solar:people-nearby-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -214,8 +214,17 @@ function updateCustomModelName(value: string) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div text="neutral-200/50 dark:neutral-600/20" pointer-events-none fixed bottom-0 right-0 z--1 translate-x-10 translate-y-10>
|
||||
<div text="40" i-lucide:ghost />
|
||||
<div
|
||||
v-motion
|
||||
text="neutral-200/50 dark:neutral-600/20" pointer-events-none
|
||||
fixed top="[calc(100dvh-15rem)]" bottom-0 right--5 z--1
|
||||
:initial="{ scale: 0.9, opacity: 0, x: 20 }"
|
||||
:enter="{ scale: 1, opacity: 1, x: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-solar:ghost-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@ import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import IconAnimation from '../../../components/IconAnimation.vue'
|
||||
import { useIconAnimation } from '../../../composables/useIconAnimation'
|
||||
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
|
||||
@@ -24,7 +27,7 @@ const modulesList = computed<Module[]>(() => [
|
||||
id: 'consciousness',
|
||||
name: t('settings.pages.modules.consciousness.title'),
|
||||
description: t('settings.pages.modules.consciousness.description'),
|
||||
icon: 'i-lucide:ghost',
|
||||
icon: 'i-solar:ghost-bold-duotone',
|
||||
to: '/settings/modules/consciousness',
|
||||
configured: false,
|
||||
},
|
||||
@@ -32,7 +35,7 @@ const modulesList = computed<Module[]>(() => [
|
||||
id: 'speech',
|
||||
name: t('settings.pages.modules.speech.title'),
|
||||
description: t('settings.pages.modules.speech.description'),
|
||||
icon: 'i-lucide:mic',
|
||||
icon: 'i-solar:user-speak-rounded-bold-duotone',
|
||||
to: '/settings/modules/speech',
|
||||
configured: false,
|
||||
},
|
||||
@@ -40,7 +43,7 @@ const modulesList = computed<Module[]>(() => [
|
||||
id: 'hearing',
|
||||
name: t('settings.pages.modules.hearing.title'),
|
||||
description: t('settings.pages.modules.hearing.description'),
|
||||
icon: 'i-lucide:ear',
|
||||
icon: 'i-solar:microphone-3-bold-duotone',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
@@ -48,7 +51,7 @@ const modulesList = computed<Module[]>(() => [
|
||||
id: 'vision',
|
||||
name: t('settings.pages.modules.vision.title'),
|
||||
description: t('settings.pages.modules.vision.description'),
|
||||
icon: 'i-lucide:eye',
|
||||
icon: 'i-solar:eye-closed-bold-duotone',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
@@ -56,7 +59,7 @@ const modulesList = computed<Module[]>(() => [
|
||||
id: 'memory-short-term',
|
||||
name: t('settings.pages.modules.memory-short-term.title'),
|
||||
description: t('settings.pages.modules.memory-short-term.description'),
|
||||
icon: 'i-lucide:book',
|
||||
icon: 'i-solar:bookmark-bold-duotone',
|
||||
to: '/settings/modules/memory-short-term',
|
||||
configured: false,
|
||||
},
|
||||
@@ -64,7 +67,7 @@ const modulesList = computed<Module[]>(() => [
|
||||
id: 'memory-long-term',
|
||||
name: t('settings.pages.modules.memory-long-term.title'),
|
||||
description: t('settings.pages.modules.memory-long-term.description'),
|
||||
icon: 'i-lucide:book-copy',
|
||||
icon: 'i-solar:book-bookmark-bold-duotone',
|
||||
to: '/settings/modules/memory-long-term',
|
||||
configured: false,
|
||||
},
|
||||
@@ -101,6 +104,12 @@ const modulesList = computed<Module[]>(() => [
|
||||
configured: false,
|
||||
},
|
||||
])
|
||||
|
||||
const {
|
||||
iconAnimationStarted,
|
||||
showIconAnimation,
|
||||
animationIcon,
|
||||
} = useIconAnimation('i-solar:layers-bold-duotone')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -142,15 +151,29 @@ const modulesList = computed<Module[]>(() => [
|
||||
:configured="module.configured"
|
||||
/>
|
||||
</div>
|
||||
<IconAnimation
|
||||
v-if="showIconAnimation"
|
||||
:icon="animationIcon"
|
||||
:icon-size="12"
|
||||
:duration="1000"
|
||||
:started="iconAnimationStarted"
|
||||
:is-reverse="true"
|
||||
:z-index="-1"
|
||||
text-color="text-neutral-200/50 dark:text-neutral-600/20"
|
||||
position="calc(100dvw - 9.5rem), calc(100dvh - 9.5rem)"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
v-motion
|
||||
text="neutral-200/50 dark:neutral-600/20" pointer-events-none
|
||||
fixed top="[72dvh]" right--15 z--1
|
||||
:initial="{ scale: 0.9, opacity: 0, y: 0 }"
|
||||
:enter="{ scale: 1, opacity: 1, y: 10 }"
|
||||
:duration="250"
|
||||
fixed top="[calc(100dvh-15rem)]" bottom-0 right--5 z--1
|
||||
:initial="{ scale: 0.9, opacity: 0, y: 20 }"
|
||||
:enter="{ scale: 1, opacity: 1, y: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-lucide:blocks />
|
||||
<div text="60" i-solar:layers-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -518,10 +518,16 @@ function updateCustomModelName(value: string) {
|
||||
</div>
|
||||
|
||||
<div
|
||||
text="neutral-200/50 dark:neutral-500/20" pointer-events-none fixed bottom-0 right-0 z--1 translate-x-10
|
||||
translate-y-10
|
||||
v-motion
|
||||
text="neutral-200/50 dark:neutral-600/20" pointer-events-none
|
||||
fixed top="[calc(100dvh-15rem)]" bottom-0 right--5 z--1
|
||||
:initial="{ scale: 0.9, opacity: 0, x: 20 }"
|
||||
:enter="{ scale: 1, opacity: 1, x: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="40" i-lucide:volume-2 />
|
||||
<div text="60" i-solar:user-speak-rounded-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -5,10 +5,18 @@ import { storeToRefs } from 'pinia'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { useIconAnimation } from '../../../composables/useIconAnimation'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const providersStore = useProvidersStore()
|
||||
const { allProvidersMetadata } = storeToRefs(providersStore)
|
||||
|
||||
const {
|
||||
iconAnimationStarted,
|
||||
showIconAnimation,
|
||||
animationIcon,
|
||||
} = useIconAnimation('i-solar:box-minimalistic-bold-duotone')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -50,15 +58,29 @@ const { allProvidersMetadata } = storeToRefs(providersStore)
|
||||
:configured="provider.configured"
|
||||
/>
|
||||
</div>
|
||||
<IconAnimation
|
||||
v-if="showIconAnimation"
|
||||
:z-index="-1"
|
||||
:icon="animationIcon"
|
||||
:icon-size="12"
|
||||
:duration="1000"
|
||||
:started="iconAnimationStarted"
|
||||
:is-reverse="true"
|
||||
position="calc(100dvw - 9.5rem), calc(100dvh - 9.5rem)"
|
||||
text-color="text-neutral-200/50 dark:text-neutral-600/20"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
v-motion
|
||||
text="neutral-200/50 dark:neutral-600/20" pointer-events-none
|
||||
fixed top="[70dvh]" right--15 z--1
|
||||
:initial="{ scale: 0.9, opacity: 0 }"
|
||||
:enter="{ scale: 1, opacity: 1 }"
|
||||
:duration="250"
|
||||
fixed top="[calc(100dvh-15rem)]" bottom-0 right--5 z--1
|
||||
:initial="{ scale: 0.9, opacity: 0, y: 20 }"
|
||||
:enter="{ scale: 1, opacity: 1, y: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-lucide:brain />
|
||||
<div text="60" i-solar:box-minimalistic-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { useIconAnimation } from '../../../composables/useIconAnimation'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
|
||||
const {
|
||||
iconAnimationStarted,
|
||||
showIconAnimation,
|
||||
animationIcon,
|
||||
} = useIconAnimation('i-solar:armchair-2-bold-duotone')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-motion
|
||||
flex="~ row" items-center gap-2
|
||||
:initial="{ opacity: 0, x: 10 }"
|
||||
:enter="{ opacity: 1, x: 0 }"
|
||||
:leave="{ opacity: 0, x: -10 }"
|
||||
:duration="250"
|
||||
>
|
||||
<button @click="router.back()">
|
||||
<div i-solar:alt-arrow-left-line-duotone text-2xl />
|
||||
</button>
|
||||
<h1 relative>
|
||||
<div absolute left-0 top-0 translate-y="[-80%]">
|
||||
<span text="neutral-300 dark:neutral-500" text-nowrap>{{ t('settings.title') }}</span>
|
||||
</div>
|
||||
<div text-nowrap text-3xl font-semibold>
|
||||
{{ t('settings.pages.scene.title') }}
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
<div>
|
||||
Scene
|
||||
</div>
|
||||
<IconAnimation
|
||||
v-if="showIconAnimation"
|
||||
:z-index="-1"
|
||||
:icon="animationIcon"
|
||||
:icon-size="12"
|
||||
:duration="1000"
|
||||
:started="iconAnimationStarted"
|
||||
:is-reverse="true"
|
||||
position="calc(100dvw - 9.5rem), calc(100dvh - 9.5rem)"
|
||||
text-color="text-neutral-200/50 dark:text-neutral-600/20"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
v-motion
|
||||
text="neutral-200/50 dark:neutral-600/20" pointer-events-none
|
||||
fixed top="[calc(100dvh-15rem)]" bottom-0 right--5 z--1
|
||||
:initial="{ scale: 0.9, opacity: 0, y: 20 }"
|
||||
:enter="{ scale: 1, opacity: 1, y: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-solar:armchair-2-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
stageTransition:
|
||||
name: slide
|
||||
pageSpecificAvailable: true
|
||||
</route>
|
||||
@@ -339,6 +339,9 @@ settings:
|
||||
description: x.ai
|
||||
title: xAI
|
||||
title: Providers
|
||||
scene:
|
||||
description: Configure the environment where the character lives
|
||||
title: Scene
|
||||
themes:
|
||||
description: Customize your stage!
|
||||
sections:
|
||||
|
||||
@@ -323,6 +323,9 @@ settings:
|
||||
description: X.AI
|
||||
title: xAI
|
||||
title: 提供商
|
||||
scene:
|
||||
description: 配置角色所在环境
|
||||
title: 场景
|
||||
themes:
|
||||
description: 自定义你的舞台外观!
|
||||
sections:
|
||||
|
||||
@@ -311,8 +311,9 @@ function getModuleShortName(id: string, module: 'consciousness' | 'voice') {
|
||||
:enter="{ scale: 1, opacity: 1, x: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-lucide:id-card />
|
||||
<div text="60" i-solar:emoji-funny-square-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -269,8 +269,9 @@ watch(() => [settings.usePageSpecificTransitions, settings.disableTransitions],
|
||||
:initial="{ scale: 0.9, opacity: 0, rotate: 30 }"
|
||||
:enter="{ scale: 1, opacity: 1, rotate: 0 }"
|
||||
:duration="250"
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-lucide:paintbrush />
|
||||
<div text="60" i-solar:filters-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -63,37 +63,43 @@ const settings = computed(() => [
|
||||
{
|
||||
title: t('settings.pages.card.title'),
|
||||
description: t('settings.pages.card.description'),
|
||||
icon: 'i-lucide:id-card',
|
||||
icon: 'i-solar:emoji-funny-square-bold-duotone',
|
||||
to: '/settings/airi-card',
|
||||
},
|
||||
{
|
||||
title: t('settings.pages.modules.title'),
|
||||
description: t('settings.pages.modules.description'),
|
||||
icon: 'i-lucide:blocks',
|
||||
icon: 'i-solar:layers-bold-duotone',
|
||||
to: '/settings/modules',
|
||||
},
|
||||
{
|
||||
title: t('settings.pages.scene.title'),
|
||||
description: t('settings.pages.scene.description'),
|
||||
icon: 'i-solar:armchair-2-bold-duotone',
|
||||
to: '/settings/scene',
|
||||
},
|
||||
{
|
||||
title: t('settings.pages.models.title'),
|
||||
description: t('settings.pages.models.description'),
|
||||
icon: 'i-lucide:person-standing',
|
||||
icon: 'i-solar:people-nearby-bold-duotone',
|
||||
to: '/settings/models',
|
||||
},
|
||||
{
|
||||
title: t('settings.pages.memory.title'),
|
||||
description: t('settings.pages.memory.description'),
|
||||
icon: 'i-lucide:sprout',
|
||||
icon: 'i-solar:leaf-bold-duotone',
|
||||
to: '/settings/memory',
|
||||
},
|
||||
{
|
||||
title: t('settings.pages.providers.title'),
|
||||
description: t('settings.pages.providers.description'),
|
||||
icon: 'i-lucide:brain',
|
||||
icon: 'i-solar:box-minimalistic-bold-duotone',
|
||||
to: '/settings/providers',
|
||||
},
|
||||
{
|
||||
title: t('settings.pages.themes.title'),
|
||||
description: t('settings.pages.themes.description'),
|
||||
icon: 'i-lucide:paintbrush',
|
||||
icon: 'i-solar:filters-bold-duotone',
|
||||
to: '/settings/appearance',
|
||||
},
|
||||
])
|
||||
@@ -149,12 +155,13 @@ const settings = computed(() => [
|
||||
v-motion
|
||||
text="neutral-200/50 dark:neutral-600/20" pointer-events-none
|
||||
fixed top="[calc(100dvh-12rem)]" bottom-0 right--10 z--1
|
||||
:initial="{ scale: 0.9, opacity: 0, rotate: 45 }"
|
||||
:initial="{ scale: 0.9, opacity: 0, rotate: 180 }"
|
||||
:enter="{ scale: 1, opacity: 1, rotate: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div v-motion text="60" i-lucide:cog />
|
||||
<div v-motion text="60" i-solar:settings-bold-duotone />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -43,8 +43,9 @@ const { t } = useI18n()
|
||||
:enter="{ scale: 1, opacity: 1, y: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-lucide:sprout />
|
||||
<div text="60" i-solar:leaf-bold-duotone />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -44,7 +44,7 @@ const {
|
||||
iconAnimationStarted,
|
||||
showIconAnimation,
|
||||
animationIcon,
|
||||
} = useIconAnimation('i-lucide:person-standing')
|
||||
} = useIconAnimation('i-solar:people-nearby-bold-duotone')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -95,8 +95,9 @@ const {
|
||||
:enter="{ scale: 1, opacity: 1, y: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-lucide:person-standing />
|
||||
<div text="60" i-solar:people-nearby-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -222,8 +222,9 @@ function updateCustomModelName(value: string) {
|
||||
:enter="{ scale: 1, opacity: 1, x: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-lucide:ghost />
|
||||
<div text="60" i-solar:ghost-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ const modulesList = computed<Module[]>(() => [
|
||||
id: 'consciousness',
|
||||
name: t('settings.pages.modules.consciousness.title'),
|
||||
description: t('settings.pages.modules.consciousness.description'),
|
||||
icon: 'i-lucide:ghost',
|
||||
icon: 'i-solar:ghost-bold-duotone',
|
||||
to: '/settings/modules/consciousness',
|
||||
configured: false,
|
||||
},
|
||||
@@ -35,7 +35,7 @@ const modulesList = computed<Module[]>(() => [
|
||||
id: 'speech',
|
||||
name: t('settings.pages.modules.speech.title'),
|
||||
description: t('settings.pages.modules.speech.description'),
|
||||
icon: 'i-lucide:mic',
|
||||
icon: 'i-solar:user-speak-rounded-bold-duotone',
|
||||
to: '/settings/modules/speech',
|
||||
configured: false,
|
||||
},
|
||||
@@ -43,7 +43,7 @@ const modulesList = computed<Module[]>(() => [
|
||||
id: 'hearing',
|
||||
name: t('settings.pages.modules.hearing.title'),
|
||||
description: t('settings.pages.modules.hearing.description'),
|
||||
icon: 'i-lucide:ear',
|
||||
icon: 'i-solar:microphone-3-bold-duotone',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
@@ -51,7 +51,7 @@ const modulesList = computed<Module[]>(() => [
|
||||
id: 'vision',
|
||||
name: t('settings.pages.modules.vision.title'),
|
||||
description: t('settings.pages.modules.vision.description'),
|
||||
icon: 'i-lucide:eye',
|
||||
icon: 'i-solar:eye-closed-bold-duotone',
|
||||
to: '',
|
||||
configured: false,
|
||||
},
|
||||
@@ -59,7 +59,7 @@ const modulesList = computed<Module[]>(() => [
|
||||
id: 'memory-short-term',
|
||||
name: t('settings.pages.modules.memory-short-term.title'),
|
||||
description: t('settings.pages.modules.memory-short-term.description'),
|
||||
icon: 'i-lucide:book',
|
||||
icon: 'i-solar:bookmark-bold-duotone',
|
||||
to: '/settings/modules/memory-short-term',
|
||||
configured: false,
|
||||
},
|
||||
@@ -67,7 +67,7 @@ const modulesList = computed<Module[]>(() => [
|
||||
id: 'memory-long-term',
|
||||
name: t('settings.pages.modules.memory-long-term.title'),
|
||||
description: t('settings.pages.modules.memory-long-term.description'),
|
||||
icon: 'i-lucide:book-copy',
|
||||
icon: 'i-solar:book-bookmark-bold-duotone',
|
||||
to: '/settings/modules/memory-long-term',
|
||||
configured: false,
|
||||
},
|
||||
@@ -109,7 +109,7 @@ const {
|
||||
iconAnimationStarted,
|
||||
showIconAnimation,
|
||||
animationIcon,
|
||||
} = useIconAnimation('i-lucide:blocks')
|
||||
} = useIconAnimation('i-solar:layers-bold-duotone')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -171,8 +171,9 @@ const {
|
||||
:enter="{ scale: 1, opacity: 1, y: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-lucide:blocks />
|
||||
<div text="60" i-solar:layers-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -525,8 +525,9 @@ function updateCustomModelName(value: string) {
|
||||
:enter="{ scale: 1, opacity: 1, x: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-lucide:mic />
|
||||
<div text="60" i-solar:user-speak-rounded-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ const {
|
||||
iconAnimationStarted,
|
||||
showIconAnimation,
|
||||
animationIcon,
|
||||
} = useIconAnimation('i-lucide:brain')
|
||||
} = useIconAnimation('i-solar:box-minimalistic-bold-duotone')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -78,8 +78,9 @@ const {
|
||||
:enter="{ scale: 1, opacity: 1, y: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-lucide:brain />
|
||||
<div text="60" i-solar:box-minimalistic-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { useIconAnimation } from '../../../composables/useIconAnimation'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
|
||||
const {
|
||||
iconAnimationStarted,
|
||||
showIconAnimation,
|
||||
animationIcon,
|
||||
} = useIconAnimation('i-solar:armchair-2-bold-duotone')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-motion
|
||||
flex="~ row" items-center gap-2
|
||||
:initial="{ opacity: 0, x: 10 }"
|
||||
:enter="{ opacity: 1, x: 0 }"
|
||||
:leave="{ opacity: 0, x: -10 }"
|
||||
:duration="250"
|
||||
>
|
||||
<button @click="router.back()">
|
||||
<div i-solar:alt-arrow-left-line-duotone text-2xl />
|
||||
</button>
|
||||
<h1 relative>
|
||||
<div absolute left-0 top-0 translate-y="[-80%]">
|
||||
<span text="neutral-300 dark:neutral-500" text-nowrap>{{ t('settings.title') }}</span>
|
||||
</div>
|
||||
<div text-nowrap text-3xl font-semibold>
|
||||
{{ t('settings.pages.scene.title') }}
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
<div>
|
||||
Scene
|
||||
</div>
|
||||
<IconAnimation
|
||||
v-if="showIconAnimation"
|
||||
:z-index="-1"
|
||||
:icon="animationIcon"
|
||||
:icon-size="12"
|
||||
:duration="1000"
|
||||
:started="iconAnimationStarted"
|
||||
:is-reverse="true"
|
||||
position="calc(100dvw - 9.5rem), calc(100dvh - 9.5rem)"
|
||||
text-color="text-neutral-200/50 dark:text-neutral-600/20"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
v-motion
|
||||
text="neutral-200/50 dark:neutral-600/20" pointer-events-none
|
||||
fixed top="[calc(100dvh-15rem)]" bottom-0 right--5 z--1
|
||||
:initial="{ scale: 0.9, opacity: 0, y: 20 }"
|
||||
:enter="{ scale: 1, opacity: 1, y: 0 }"
|
||||
:duration="500"
|
||||
size-60
|
||||
flex items-center justify-center
|
||||
>
|
||||
<div text="60" i-solar:armchair-2-bold-duotone />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
stageTransition:
|
||||
name: slide
|
||||
pageSpecificAvailable: true
|
||||
</route>
|
||||
Reference in New Issue
Block a user