refactor(stage-web,stage-tamagotchi,i18n): add all developer tools to system section, rename Appearance to System

This commit is contained in:
Neko Ayaka
2025-09-01 15:30:12 +08:00
parent a1f13e4ce7
commit 0a59323aca
25 changed files with 379 additions and 105 deletions
+10 -10
View File
@@ -23,25 +23,25 @@ const routeHeaderMetadataMap = computed(() => {
subtitle: t('settings.title'),
title: t('settings.pages.card.title'),
},
'/settings/appearance': {
'/settings/system': {
subtitle: t('settings.title'),
title: t('settings.pages.themes.title'),
title: t('settings.pages.system.title'),
},
'/settings/appearance/general': {
'/settings/system/general': {
subtitle: t('settings.title'),
title: t('settings.pages.themes.general.title'),
title: t('settings.pages.system.general.title'),
},
'/settings/appearance/color-scheme': {
'/settings/system/color-scheme': {
subtitle: t('settings.title'),
title: t('settings.pages.themes.color-scheme.title'),
title: t('settings.pages.system.color-scheme.title'),
},
'/settings/appearance/window-shortcuts': {
'/settings/system/window-shortcuts': {
subtitle: t('settings.title'),
title: t('tamagotchi.settings.pages.themes.window-shortcuts.title'),
title: t('tamagotchi.settings.pages.system.window-shortcuts.title'),
},
'/settings/appearance/developer': {
'/settings/system/developer': {
subtitle: t('settings.title'),
title: t('settings.pages.themes.developer.title'),
title: t('settings.pages.system.developer.title'),
},
'/settings/memory': {
subtitle: t('settings.title'),
@@ -132,3 +132,8 @@ const Key = defineComponent({
>
</div>
</template>
<route lang="yaml">
meta:
layout: settings
</route>
@@ -97,10 +97,10 @@ const settings = computed(() => [
to: '/settings/providers',
},
{
title: t('settings.pages.themes.title'),
description: t('settings.pages.themes.description'),
title: t('settings.pages.system.title'),
description: t('settings.pages.system.description'),
icon: 'i-solar:filters-bold-duotone',
to: '/settings/appearance',
to: '/settings/system',
},
])
</script>
@@ -1,9 +1,22 @@
<script setup lang="ts">
import { IconItem } from '@proj-airi/stage-ui/components'
import { useSettings } from '@proj-airi/stage-ui/stores/settings'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import CheckBar from '../../../components/Settings/CheckBar.vue'
const { t } = useI18n()
const settings = useSettings()
const menu = computed(() => [
{
title: t('settings.pages.system.sections.section.developer.sections.section.use-magic-keys.title'),
description: t('settings.pages.system.sections.section.developer.sections.section.use-magic-keys.description'),
icon: 'i-solar:sledgehammer-bold-duotone',
to: '/devtools/use-magic-keys',
},
])
</script>
<template>
@@ -17,7 +30,7 @@ const settings = useSettings()
:initial="{ opacity: 0, y: 10 }"
:enter="{ opacity: 1, y: 0 }"
:duration="250 + (19 * 10)"
:delay="19 * 50"
:delay="1 * 50"
transition="all ease-in-out duration-250"
/>
<CheckBar
@@ -31,10 +44,28 @@ const settings = useSettings()
:initial="{ opacity: 0, y: 10 }"
:enter="{ opacity: 1, y: 0 }"
:duration="250 + (20 * 10)"
:delay="20 * 50"
:delay="2 * 50"
transition="all ease-in-out duration-250"
/>
<div flex="~ col gap-4" pb-12>
<IconItem
v-for="(item, index) in menu"
:key="item.to"
v-motion
:initial="{ opacity: 0, y: 10 }"
:enter="{ opacity: 1, y: 0 }"
:duration="250"
:style="{
transitionDelay: `${index * 50}ms`, // delay between each item, unocss doesn't support dynamic generation of classes now
}"
:title="item.title"
:description="item.description"
:icon="item.icon"
:to="item.to"
/>
</div>
<div
v-motion
text="neutral-200/50 dark:neutral-600/20" pointer-events-none
@@ -7,28 +7,28 @@ const { t } = useI18n()
const settings = computed(() => [
{
title: t('settings.pages.themes.general.title'),
description: t('settings.pages.themes.general.description'),
title: t('settings.pages.system.general.title'),
description: t('settings.pages.system.general.description'),
icon: 'i-solar:emoji-funny-square-bold-duotone',
to: '/settings/appearance/general',
to: '/settings/system/general',
},
{
title: t('settings.pages.themes.color-scheme.title'),
description: t('settings.pages.themes.color-scheme.description'),
title: t('settings.pages.system.color-scheme.title'),
description: t('settings.pages.system.color-scheme.description'),
icon: 'i-solar:pallete-2-bold-duotone',
to: '/settings/appearance/color-scheme',
to: '/settings/system/color-scheme',
},
{
title: t('tamagotchi.settings.pages.themes.window-shortcuts.title'),
description: t('tamagotchi.settings.pages.themes.window-shortcuts.description'),
title: t('tamagotchi.settings.pages.system.window-shortcuts.title'),
description: t('tamagotchi.settings.pages.system.window-shortcuts.description'),
icon: 'i-solar:keyboard-bold-duotone',
to: '/settings/appearance/window-shortcuts',
to: '/settings/system/window-shortcuts',
},
{
title: t('settings.pages.themes.developer.title'),
description: t('settings.pages.themes.developer.description'),
title: t('settings.pages.system.developer.title'),
description: t('settings.pages.system.developer.description'),
icon: 'i-solar:code-bold-duotone',
to: '/settings/appearance/developer',
to: '/settings/system/developer',
},
])
</script>
@@ -62,8 +62,29 @@ async function extractColorsFromImage() {
try {
isCapturing.value = true
// Extract colors using Vibrant
const vibrant = new Vibrant(images.value[0])
// Load the image
const img = new window.Image()
img.crossOrigin = 'anonymous'
img.src = images.value[0]
await new Promise((resolve, reject) => {
img.onload = resolve
img.onerror = reject
})
// Create a canvas and draw only the top portion
const cropHeight = Math.floor(img.naturalHeight * 0.2) // top 20% of the image
const canvas = document.createElement('canvas')
canvas.width = img.naturalWidth
canvas.height = cropHeight
const ctx = canvas.getContext('2d')
if (ctx) {
ctx.drawImage(img, 0, 0, img.naturalWidth, cropHeight, 0, 0, img.naturalWidth, cropHeight)
}
// Convert canvas to data URL and use Vibrant on the cropped region
const dataUrl = canvas.toDataURL()
const vibrant = new Vibrant(dataUrl)
const palette = await vibrant.getPalette()
const colors = Object.values(palette)
@@ -0,0 +1,131 @@
<script setup lang="ts">
import { useMagicKeys } from '@vueuse/core'
import { computed, defineComponent, h } from 'vue'
const {
shift,
control,
escape,
tab,
v,
u,
e,
s,
v_u_e,
u_s_e,
i_Shift_Alt,
a_Shift_Alt,
n_Shift_Alt,
current,
} = useMagicKeys()
const keys = computed(() => Array.from(current))
const Key = defineComponent({
props: {
value: {
type: Boolean,
required: true,
},
},
render() {
return h('div', {
class: [
'font-mono px-4 py-2 rounded',
this.value
? 'opacity-100 text-primary bg-primary bg-opacity-15'
: 'opacity-50 bg-gray-600 bg-opacity-10 dark:(bg-gray-400 bg-opacity-10)',
],
}, this.$slots.default?.())
},
})
</script>
<template>
<div class="flex flex-col md:flex-row">
<img
class="m-auto h-38 transform py-8 transition duration-500"
:class="{ 'opacity-0': !v_u_e, 'rotate-180': shift }"
>
<div>
<div class="mb-5 mt-0 text-center">
Press the following keys to test out
</div>
<div class="flex justify-center gap-3">
<Key :value="v">
V
</Key>
<Key :value="u">
u
</Key>
<Key :value="e">
e
</Key>
<div class="mx-1" />
<Key :value="u">
U
</Key>
<Key :value="s">
s
</Key>
<Key :value="e">
e
</Key>
</div>
<div class="mt-3 flex justify-center gap-3">
<Key :value="escape">
Escape
</Key>
<Key :value="shift">
Shift
</Key>
<Key :value="control">
Control
</Key>
<Key :value="tab">
Tab
</Key>
</div>
<div class="mt-3 flex justify-center gap-3">
<Key :value="v_u_e">
Vue
</Key>
<Key :value="u_s_e">
Use
</Key>
</div>
<div class="mt-3 flex flex-col items-center gap-3">
<Key :value="i_Shift_Alt">
Shift + Alt + I
</Key>
<Key :value="a_Shift_Alt">
Shift + Alt + A
</Key>
<Key :value="n_Shift_Alt">
Shift + Alt + N
</Key>
</div>
<div class="mt-4 text-center">
<div>Keys Pressed</div>
<div class="mt-2 min-h-1.5em flex justify-center space-x-1">
<code
v-for="key in keys"
:key="key"
class="font-mono"
>
{{ key }}
</code>
</div>
</div>
</div>
<img
class="m-auto h-38 transform py-8 transition duration-500"
:class="{ 'opacity-0': !u_s_e, 'rotate-180': shift }"
>
</div>
</template>
@@ -1,56 +0,0 @@
<script setup lang="ts">
import { useSettings } from '@proj-airi/stage-ui/stores/settings'
import CheckBar from '../../../components/Settings/CheckBar.vue'
const settings = useSettings()
</script>
<template>
<CheckBar
v-model="settings.disableTransitions"
v-motion
mb-2
icon-on="i-solar:people-nearby-bold-duotone"
icon-off="i-solar:running-2-line-duotone"
text="settings.animations.stage-transitions.title"
:initial="{ opacity: 0, y: 10 }"
:enter="{ opacity: 1, y: 0 }"
:duration="250 + (19 * 10)"
:delay="19 * 50"
transition="all ease-in-out duration-250"
/>
<CheckBar
v-model="settings.usePageSpecificTransitions"
v-motion
:disabled="settings.disableTransitions"
icon-on="i-solar:running-2-line-duotone"
icon-off="i-solar:people-nearby-bold-duotone"
text="settings.animations.use-page-specific-transitions.title"
description="settings.animations.use-page-specific-transitions.description"
:initial="{ opacity: 0, y: 10 }"
:enter="{ opacity: 1, y: 0 }"
:duration="250 + (20 * 10)"
:delay="20 * 50"
transition="all ease-in-out duration-250"
/>
<div
v-motion
text="neutral-200/50 dark:neutral-600/20" pointer-events-none
fixed top="[65dvh]" right--15 z--1
: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-solar:code-bold-duotone />
</div>
</template>
<route lang="yaml">
meta:
layout: settings
stageTransition:
name: slide
</route>
+3 -3
View File
@@ -97,10 +97,10 @@ const settings = computed(() => [
to: '/settings/providers',
},
{
title: t('settings.pages.themes.title'),
description: t('settings.pages.themes.description'),
title: t('settings.pages.system.title'),
description: t('settings.pages.system.description'),
icon: 'i-solar:filters-bold-duotone',
to: '/settings/appearance',
to: '/settings/system',
},
])
</script>
@@ -0,0 +1,135 @@
<script setup lang="ts">
import { IconItem } from '@proj-airi/stage-ui/components'
import { useSettings } from '@proj-airi/stage-ui/stores/settings'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import CheckBar from '../../../components/Settings/CheckBar.vue'
const { t } = useI18n()
const settings = useSettings()
const menu = computed(() => [
{
title: 'Audio Record',
description: 'Test Audio related composables',
icon: 'i-solar:sledgehammer-bold-duotone',
to: '/devtools/audio-record',
},
{
title: 'Background Theme color blending',
description: 'Test blending & theme',
icon: 'i-solar:sledgehammer-bold-duotone',
to: '/devtools/background-gradient-blending',
},
{
title: 'Background removal (WebGPU required)',
description: 'Utility for background removal',
icon: 'i-solar:sledgehammer-bold-duotone',
to: '/devtools/background-removal',
},
{
title: 'Chat',
description: 'Chat',
icon: 'i-solar:sledgehammer-bold-duotone',
to: '/devtools/chat',
},
{
title: 'Gesture Circle (Desktop only)',
description: 'Test gesture recognition',
icon: 'i-solar:sledgehammer-bold-duotone',
to: '/devtools/gesture-circle',
},
{
title: 'Image',
description: 'Image',
icon: 'i-solar:sledgehammer-bold-duotone',
to: '/devtools/image',
},
{
title: 'Polaroid',
description: 'Utility for taking shots of models',
icon: 'i-solar:sledgehammer-bold-duotone',
to: '/devtools/polaroid',
},
{
title: t('settings.pages.system.sections.section.developer.sections.section.use-magic-keys.title'),
description: t('settings.pages.system.sections.section.developer.sections.section.use-magic-keys.description'),
icon: 'i-solar:sledgehammer-bold-duotone',
to: '/devtools/use-magic-keys',
},
{
title: 'Color extract',
description: 'Test color extraction',
icon: 'i-solar:sledgehammer-bold-duotone',
to: '/devtools/vibrant',
},
])
</script>
<template>
<CheckBar
v-model="settings.disableTransitions"
v-motion
mb-2
icon-on="i-solar:people-nearby-bold-duotone"
icon-off="i-solar:running-2-line-duotone"
text="settings.animations.stage-transitions.title"
:initial="{ opacity: 0, y: 10 }"
:enter="{ opacity: 1, y: 0 }"
:duration="250 + (19 * 10)"
:delay="1 * 50"
transition="all ease-in-out duration-250"
/>
<CheckBar
v-model="settings.usePageSpecificTransitions"
v-motion
:disabled="settings.disableTransitions"
icon-on="i-solar:running-2-line-duotone"
icon-off="i-solar:people-nearby-bold-duotone"
text="settings.animations.use-page-specific-transitions.title"
description="settings.animations.use-page-specific-transitions.description"
:initial="{ opacity: 0, y: 10 }"
:enter="{ opacity: 1, y: 0 }"
:duration="250 + (20 * 10)"
:delay="2 * 50"
transition="all ease-in-out duration-250"
/>
<div flex="~ col gap-4" pb-12>
<IconItem
v-for="(item, index) in menu"
:key="item.to"
v-motion
:initial="{ opacity: 0, y: 10 }"
:enter="{ opacity: 1, y: 0 }"
:duration="250"
:style="{
transitionDelay: `${index * 50}ms`, // delay between each item, unocss doesn't support dynamic generation of classes now
}"
:title="item.title"
:description="item.description"
:icon="item.icon"
:to="item.to"
/>
</div>
<div
v-motion
text="neutral-200/50 dark:neutral-600/20" pointer-events-none
fixed top="[65dvh]" right--15 z--1
: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-solar:code-bold-duotone />
</div>
</template>
<route lang="yaml">
meta:
layout: settings
stageTransition:
name: slide
</route>
@@ -7,22 +7,22 @@ const { t } = useI18n()
const settings = computed(() => [
{
title: t('settings.pages.themes.general.title'),
description: t('settings.pages.themes.general.description'),
title: t('settings.pages.system.general.title'),
description: t('settings.pages.system.general.description'),
icon: 'i-solar:emoji-funny-square-bold-duotone',
to: '/settings/appearance/general',
to: '/settings/system/general',
},
{
title: t('settings.pages.themes.color-scheme.title'),
description: t('settings.pages.themes.color-scheme.description'),
title: t('settings.pages.system.color-scheme.title'),
description: t('settings.pages.system.color-scheme.description'),
icon: 'i-solar:pallete-2-bold-duotone',
to: '/settings/appearance/color-scheme',
to: '/settings/system/color-scheme',
},
{
title: t('settings.pages.themes.developer.title'),
description: t('settings.pages.themes.developer.description'),
title: t('settings.pages.system.developer.title'),
description: t('settings.pages.system.developer.description'),
icon: 'i-solar:code-bold-duotone',
to: '/settings/appearance/developer',
to: '/settings/system/developer',
},
])
</script>
+10 -3
View File
@@ -25,7 +25,9 @@ dialogs:
start: Let's do it!
select-model: Choose model
no-models: No available models
no-models-help: Please return to the previous step and check your API key, or check the network connection.
no-models-help: >-
Please return to the previous step and check your API key, or check the
network connection.
language:
title: Language
description: >
@@ -467,7 +469,7 @@ pages:
scene:
description: Configure the environment where the character lives
title: Scene
themes:
system:
color-scheme:
description: Change the color scheme of the stage.
title: Color Scheme
@@ -490,6 +492,11 @@ pages:
title: Color Scheme
developer:
title: Developer
sections:
section:
use-magic-keys:
title: useMagicKeys
description: Test shortcuts
theme-presets:
presets:
- colors:
@@ -554,7 +561,7 @@ pages:
porcelain and paintings
title: Chinese Traditional Colors
title: Color Scheme Presets
title: Appearance
title: System
sections:
section:
general:
@@ -6,7 +6,7 @@ pages:
mcp-server:
description: Connect and manage MCP server and tools
title: MCP Server
themes:
system:
sections:
section:
window-shortcuts:
@@ -6,7 +6,7 @@ pages:
mcp-server:
description: Conectar y gestionar servidor MCP y herramientas
title: Servidor MCP
themes:
system:
sections:
section:
window-shortcuts:
@@ -6,7 +6,7 @@ pages:
mcp-server:
description: Возможность подключения и управления MCP сервером с инструментами
title: MCP Сервер
themes:
system:
sections:
section:
window-shortcuts:
@@ -6,7 +6,7 @@ pages:
mcp-server:
description: Kết nối và quản lý máy chủ MCP và các công cụ
title: Máy chủ MCP
themes:
system:
sections:
section:
window-shortcuts:
@@ -6,7 +6,7 @@ pages:
mcp-server:
description: 连接与管理 MCP 服务器和工具
title: MCP 服务器
themes:
system:
sections:
section:
window-shortcuts: