fix(stage-*): qr should have dark mode adapted, connection component moved

This commit is contained in:
Neko Ayaka
2026-04-08 01:06:40 +08:00
parent 1326a3c31a
commit 160176b33a
12 changed files with 70 additions and 81 deletions
@@ -107,7 +107,7 @@ const isTransparent = computed(() => {
return true
})
const { isNearAnyBorder: isAroundWindowBorder } = useElectronMouseAroundWindowBorder({ threshold: 30 })
const { isNearAnyBorder: isAroundWindowBorder } = useElectronMouseAroundWindowBorder({ threshold: 10 })
const isAroundWindowBorderFor250Ms = refDebounced(isAroundWindowBorder, 250)
const setIgnoreMouseEvents = useElectronEventaInvoke(electron.window.setIgnoreMouseEvents)
@@ -1,7 +1,6 @@
<script setup lang="ts">
import ConnectionSettings from '@proj-airi/stage-pages/pages/settings/connection/ConnectionSettings.vue'
import { isStageTamagotchi } from '@proj-airi/stage-shared'
import { ConnectionSettings } from '@proj-airi/stage-ui/components'
import { Callout, FieldCheckbox, FieldInput, SelectTab } from '@proj-airi/ui'
import { storeToRefs } from 'pinia'
import { computed } from 'vue'
@@ -53,80 +52,61 @@ const exposureModeOptions = computed(() => [
</script>
<template>
<ConnectionSettings>
<template #platform-specific>
<!-- TODO: show connected remote -->
<FieldCheckbox
v-model="websocketTlsEnabled"
v-motion
:initial="{ opacity: 0, y: 10 }"
:enter="{ opacity: 1, y: 0 }"
:duration="250 + (5 * 10)"
:delay="5 * 50"
:label="t('settings.websocket-secure-enabled.title')"
:description="t('settings.websocket-secure-enabled.description')"
/>
<div
v-if="showDesktopServerControls"
v-motion
:initial="{ opacity: 0, y: 10 }"
:enter="{ opacity: 1, y: 0 }"
:duration="250 + (6 * 10)"
:delay="6 * 50"
:class="['flex', 'flex-col', 'gap-2']"
>
<div :class="['text-sm', 'font-medium', 'text-neutral-900', 'dark:text-neutral-100']">
{{ t('settings.pages.connection.server-hostname.label') }}
</div>
<div :class="['text-xs', 'text-neutral-500', 'dark:text-neutral-400']">
{{ t('settings.pages.connection.server-hostname.description') }}
</div>
<SelectTab
v-model="exposureMode"
size="sm"
:options="exposureModeOptions"
<div>
<Callout
v-if="lastApplyError"
theme="orange"
:label="t('settings.websocket-secure-enabled.title')"
>
{{ lastApplyError }}
</Callout>
<ConnectionSettings>
<template #platform-specific>
<!-- TODO: show connected remote -->
<FieldCheckbox
v-model="websocketTlsEnabled"
:label="t('settings.websocket-secure-enabled.title')"
:description="t('settings.websocket-secure-enabled.description')"
/>
</div>
<FieldInput
v-if="showDesktopServerControls && showAdvancedHostname"
v-model="hostname"
v-motion
:initial="{ opacity: 0, y: 10 }"
:enter="{ opacity: 1, y: 0 }"
:duration="250 + (7 * 10)"
:delay="7 * 50"
:label="t('settings.pages.connection.server-hostname.advanced-label')"
:description="t('settings.pages.connection.server-hostname.advanced-description')"
placeholder="192.168.1.25"
/>
<div
v-if="showDesktopServerControls"
:class="['flex', 'flex-col', 'gap-2']"
>
<div :class="['text-sm', 'font-medium', 'text-neutral-900', 'dark:text-neutral-100']">
{{ t('settings.pages.connection.server-hostname.label') }}
</div>
<div :class="['text-xs', 'text-neutral-500', 'dark:text-neutral-400']">
{{ t('settings.pages.connection.server-hostname.description') }}
</div>
<SelectTab
v-model="exposureMode"
size="sm"
:options="exposureModeOptions"
/>
</div>
<FieldInput
v-if="showDesktopServerControls"
v-model="authToken"
v-motion
:initial="{ opacity: 0, y: 10 }"
:enter="{ opacity: 1, y: 0 }"
:duration="250 + (8 * 10)"
:delay="8 * 50"
secure
:label="t('settings.pages.connection.server-auth-token.label')"
:description="t('settings.pages.connection.server-auth-token.description')"
:placeholder="t('settings.pages.connection.server-auth-token.placeholder')"
/>
<FieldInput
v-if="showDesktopServerControls && showAdvancedHostname"
v-model="hostname"
:label="t('settings.pages.connection.server-hostname.advanced-label')"
:description="t('settings.pages.connection.server-hostname.advanced-description')"
placeholder="192.168.1.25"
/>
<Callout
v-if="lastApplyError"
theme="orange"
:label="t('settings.websocket-secure-enabled.title')"
>
{{ lastApplyError }}
</Callout>
<FieldInput
v-if="showDesktopServerControls"
v-model="authToken"
type="password"
:label="t('settings.pages.connection.server-auth-token.label')"
:description="t('settings.pages.connection.server-auth-token.description')"
:placeholder="t('settings.pages.connection.server-auth-token.placeholder')"
/>
<ServerChannelQrCard />
</template>
</ConnectionSettings>
<ServerChannelQrCard />
</template>
</ConnectionSettings>
</div>
</template>
<route lang="yaml">
@@ -3,7 +3,7 @@ import type { ServerChannelQrPayload } from '@proj-airi/stage-shared/server-chan
import { errorMessageFrom } from '@moeru/std'
import { useElectronEventaInvoke } from '@proj-airi/electron-vueuse'
import { Button, Callout, Collapsible } from '@proj-airi/ui'
import { Button, Callout, Collapsible, useTheme } from '@proj-airi/ui'
import { storeToRefs } from 'pinia'
import { renderSVG } from 'uqr'
import { computed, shallowRef, watch } from 'vue'
@@ -12,6 +12,7 @@ import { useI18n } from 'vue-i18n'
import { electronGetServerChannelQrPayload } from '../../../../shared/eventa'
import { useServerChannelSettingsStore } from '../../../stores/settings/server-channel'
const { isDark } = useTheme()
const { t } = useI18n()
const getServerChannelQrPayload = useElectronEventaInvoke(electronGetServerChannelQrPayload)
const { authToken, hostname, tlsConfig } = storeToRefs(useServerChannelSettingsStore())
@@ -38,7 +39,7 @@ const qrCodeSource = computed(() => {
ecc: 'M',
pixelSize: 8,
whiteColor: 'transparent',
blackColor: '#111827',
blackColor: isDark.value ? '#D5D5D5' : '#121212',
})
return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`
@@ -94,7 +95,7 @@ watch([hostname, tlsConfig, authToken], () => {
<div
:class="[
'mt-3 rounded-2xl border border-neutral-200/70 bg-white/70 p-4 dark:border-neutral-700/70 dark:bg-neutral-900/50',
'mt-3 rounded-xl bg-white/70 p-4 dark:bg-neutral-900/50',
'flex flex-col gap-4',
]"
>
@@ -14,8 +14,8 @@ const { statusMessage, statusTone, handleStatus } = createDataSettingsStatusStat
<template>
<div :class="['flex flex-col gap-4 pb-4']">
<DesktopFolderSection @status="handleStatus" />
<StatusBanner v-if="statusMessage" :message="statusMessage" :tone="statusTone" />
<DesktopFolderSection @status="handleStatus" />
<ChatsSection @status="handleStatus" />
<ModelsModulesSection @status="handleStatus" />
<DesktopResetSection @status="handleStatus" />
@@ -1,5 +1,5 @@
<script setup lang="ts">
import ConnectionSettings from './ConnectionSettings.vue'
import { ConnectionSettings } from '@proj-airi/stage-ui/components'
</script>
<template>
@@ -12,7 +12,7 @@ defineProps<Props>()
<template>
<div
:class="[
'rounded-xl border px-4 py-3 text-sm shadow-sm',
'rounded-xl border-2 px-4 py-3 text-sm shadow-sm',
tone === 'success' && 'border-emerald-300/80 bg-emerald-50/80 text-emerald-700 dark:border-emerald-500/40 dark:bg-emerald-500/10 dark:text-emerald-200',
tone === 'error' && 'border-red-300/80 bg-red-50/80 text-red-700 dark:border-red-500/50 dark:bg-red-500/10 dark:text-red-200',
tone === 'neutral' && 'border-neutral-200/70 bg-white/70 text-neutral-700 dark:border-neutral-700/70 dark:bg-neutral-900/60 dark:text-neutral-200',
@@ -0,0 +1 @@
export * from './settings'
@@ -0,0 +1 @@
export { default as ConnectionSettings } from './index.vue'
@@ -1,10 +1,11 @@
<script setup lang="ts">
import { useModsServerChannelStore } from '@proj-airi/stage-ui/stores/mods/api/channel-server'
import { FieldInput } from '@proj-airi/ui'
import { storeToRefs } from 'pinia'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useModsServerChannelStore } from '../../../../stores/mods/api/channel-server'
const { t } = useI18n()
const { websocketUrl } = storeToRefs(useModsServerChannelStore())
@@ -1,5 +1,6 @@
export * from './about'
export * from './chat'
export * from './connection'
export * from './dialogs'
export * from './hologram'
export * from './providers'
@@ -1,8 +1,10 @@
<script
setup
lang="ts"
generic="InputType extends 'number' | string, T = InputType extends 'number' ? (number | undefined) : ((string | undefined))"
generic="InputType extends 'number' | InputTypeHTMLAttribute | string, T = InputType extends 'number' ? (number | undefined) : ((string | undefined))"
>
import type { InputTypeHTMLAttribute } from 'vue'
import { Input } from '../input'
const props = withDefaults(defineProps<{
@@ -1,8 +1,10 @@
<script
setup
lang="ts"
generic="InputType extends 'number' | string, T = InputType extends 'number' ? (number | undefined) : ((string | undefined))"
generic="InputType extends 'number' | InputTypeHTMLAttribute | string, T = InputType extends 'number' ? (number | undefined) : ((string | undefined))"
>
import type { InputTypeHTMLAttribute } from 'vue'
// Define button variants for better type safety and maintainability
type InputVariant = 'primary' | 'secondary' | 'primary-dimmed'