feat(stage-web): impl settings

Signed-off-by: Neko Ayaka <neko@ayaka.moe>
This commit is contained in:
Neko Ayaka
2025-03-06 22:37:52 +08:00
parent d62bb4192c
commit 76b166e65b
11 changed files with 211 additions and 38 deletions
+2 -2
View File
@@ -17,9 +17,9 @@ watch(settings.language, () => {
<template>
<StageTransitionGroup
primary-color="#FF57C8"
secondary-color="#60C7FF"
secondary-color="#946BFF"
tertiary-color="#121212"
:colors="['#FF57C8', '#60C7FF', '#936AFF', '#121212']"
:colors="['#FF57C8', '#946BFF', '#64BCFF', '#121212']"
:z-index="100"
>
<RouterView />
@@ -1,29 +1,12 @@
<script setup lang="ts">
import { useDark } from '@vueuse/core'
import { RouterLink } from 'vue-router'
import LogoDark from '../../assets/logo-dark.svg'
import Logo from '../../assets/logo.svg'
const dark = useDark()
import HeaderLink from './HeaderLink.vue'
</script>
<template>
<header mb-1 w-full gap-2>
<a
href="https://github.com/moeru-ai/airi" rel="noreferrer noopener" target="_blank" flex="~ 1" w-full items-center
gap-2 px-2 text-nowrap text-2xl outline-none
>
<template v-if="dark">
<img :src="LogoDark" h-8 w-8>
</template>
<template v-else>
<img :src="Logo" h-8 w-8>
</template>
<div font-cute>
<span>アイリ</span>
</div>
</a>
<HeaderLink />
<RouterLink
class="m-1 block max-h-[10lh] min-h-[1lh] rounded-lg bg-zinc-100 p-2 text-lg text-zinc-500 outline-none dark:bg-zinc-800 dark:text-zinc-400"
to="/settings"
@@ -0,0 +1,26 @@
<script setup lang="ts">
import { useDark } from '@vueuse/core'
import { RouterLink } from 'vue-router'
import LogoDark from '../../assets/logo-dark.svg'
import Logo from '../../assets/logo.svg'
const dark = useDark()
</script>
<template>
<RouterLink
to="/" flex="~ 1" w-full items-center
gap-2 px-2 text-nowrap text-2xl outline-none
>
<template v-if="dark">
<img :src="LogoDark" h-8 w-8>
</template>
<template v-else>
<img :src="Logo" h-8 w-8>
</template>
<div font-cute>
<span>アイリ</span>
</div>
</RouterLink>
</template>
@@ -0,0 +1,33 @@
<script setup lang="ts">
defineProps<{
title: string
description: string
icon: string
to: string
}>()
</script>
<template>
<RouterLink
flex="~ row" bg="neutral-100 dark:neutral-800" hover="bg-neutral-200 dark:bg-neutral-700"
class="[&_.settings-section-icon]:hover:scale-120" transition="all ease-in-out duration-200" relative w-full
items-center overflow-hidden rounded-lg p-5 text-left
:to="to"
>
<div z-1 flex-1>
<div text-lg font-semibold>
{{ title }}
</div>
<div text="sm neutral-600 dark:neutral-400">
<span>{{ description }}</span>
</div>
</div>
<div
class="settings-section-icon"
transition="all ease-in-out duration-500"
absolute right-0 size-24 translate-y-4
text="neutral-400/50 dark:neutral-600/50"
:class="[icon]"
/>
</RouterLink>
</template>
+10 -13
View File
@@ -1,19 +1,16 @@
<script setup lang="ts">
import { useScreenSafeArea } from '@vueuse/core'
import { RouterView } from 'vue-router'
const { top, right, bottom, left } = useScreenSafeArea()
import HeaderLink from '../components/Layouts/HeaderLink.vue'
</script>
<template>
<main
text="gray-700 dark:gray-200" h-full font-cuteen
:style="{
paddingTop: `${top}px`,
paddingRight: `${right}px`,
paddingBottom: `${bottom}px`,
paddingLeft: `${left}px`,
}"
>
<RouterView />
</main>
<div p-2>
<div mb-1 w-full gap-2 p-2>
<HeaderLink />
</div>
<div p-5 flex="~ col gap-4">
<RouterView />
</div>
</div>
</template>
+19
View File
@@ -0,0 +1,19 @@
<script setup lang="ts">
import { useScreenSafeArea } from '@vueuse/core'
const { top, right, bottom, left } = useScreenSafeArea()
</script>
<template>
<main
text="gray-700 dark:gray-200" h-full font-cuteen
:style="{
paddingTop: `${top}px`,
paddingRight: `${right}px`,
paddingBottom: `${bottom}px`,
paddingLeft: `${left}px`,
}"
>
<RouterView />
</main>
</template>
+3 -1
View File
@@ -40,5 +40,7 @@ function handleSettingsOpen(open: boolean) {
<route lang="yaml">
meta:
layout: default
layout: stage
stageTransition:
name: bubble-wave-out
</route>
+103 -2
View File
@@ -1,6 +1,107 @@
<script setup lang="ts">
import { useSettings } from '@proj-airi/stage-ui/stores'
import { useDark } from '@vueuse/core'
import { storeToRefs } from 'pinia'
import { useI18n } from 'vue-i18n'
import IconItem from '../../components/Menu/IconItem.vue'
const { t } = useI18n()
const settings = storeToRefs(useSettings())
const dark = useDark()
function handleLanguageChange(event: Event) {
const target = event.target as HTMLSelectElement
settings.language.value = target.value
}
</script>
<template>
<div p2>
<h1>Settings</h1>
<div>
<h1 text-3xl>
Settings
</h1>
</div>
<div flex="~ col gap-4">
<div flex="~ col gap-4">
<IconItem title="Modules" description="Thinking, vision, speech synthesis, gaming, etc." icon="i-lucide:blocks" to="/settings/modules" />
<IconItem title="Providers" description="LLMs, speech providers, etc." icon="i-lucide:brain" to="/settings/providers" />
<IconItem title="Themes" description="Customize your stage!" icon="i-lucide:paintbrush" to="/settings/themes" />
</div>
<div>
<h2 text-2xl>
General
</h2>
</div>
<div flex="~ col gap-4">
<!-- Language Setting -->
<div
grid="~ cols-[150px_1fr]"
bg="neutral-100 dark:neutral-800"
hover="bg-neutral-200 dark:bg-neutral-700"
transition="all ease-in-out duration-250"
items-center gap-1.5 rounded-lg px-4 py-3
>
<div text="sm">
<span>{{ t('settings.language.title') }}</span>
</div>
<div flex="~ row" w-full justify-end>
<select
class="w-32"
bg="transparent"
text="sm right neutral-800 dark:neutral-100"
transition="all ease-in-out duration-250"
outline="none"
@change="handleLanguageChange"
>
<option value="en-US">
{{ t('settings.language.english') }}
</option>
<option value="zh-CN">
{{ t('settings.language.chinese') }}
</option>
</select>
</div>
</div>
<!-- Theme Setting -->
<label
bg="neutral-100 dark:neutral-800"
hover="bg-neutral-200 dark:bg-neutral-700"
transition="all ease-in-out duration-250"
w-full flex cursor-pointer rounded-lg px-4 py-3
>
<input
v-model="dark"
text="neutral-800 dark:neutral-100"
:checked="dark"
:aria-checked="dark"
type="checkbox"
hidden appearance-none outline-none
>
<div flex="~ row" w-full items-center gap-1.5>
<div text="sm" w-full flex-1>
<span>{{ t('settings.theme') }}</span>
</div>
<div select-none>
<Transition name="slide-away" mode="out-in">
<div
v-if="dark"
i-solar:moon-stars-bold-duotone
transition="all ease-in-out duration-250"
/>
<div
v-else
i-solar:sun-fog-bold-duotone
transition="all ease-in-out duration-250"
/>
</Transition>
</div>
</div>
</label>
</div>
<div fixed bottom-0 right-0 text="neutral-100/50 dark:neutral-500/20">
<div text="40" i-lucide:cog translate-x-10 translate-y-10 />
</div>
</div>
</template>
@@ -3,3 +3,9 @@
A
</div>
</template>
<route lang="yaml">
meta:
stageTransition:
name: slide
</route>
@@ -3,3 +3,9 @@
A
</div>
</template>
<route lang="yaml">
meta:
stageTransition:
name: slide
</route>