fix(stage-*): qr should have dark mode adapted, connection component moved
This commit is contained in:
@@ -107,7 +107,7 @@ const isTransparent = computed(() => {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
const { isNearAnyBorder: isAroundWindowBorder } = useElectronMouseAroundWindowBorder({ threshold: 30 })
|
const { isNearAnyBorder: isAroundWindowBorder } = useElectronMouseAroundWindowBorder({ threshold: 10 })
|
||||||
const isAroundWindowBorderFor250Ms = refDebounced(isAroundWindowBorder, 250)
|
const isAroundWindowBorderFor250Ms = refDebounced(isAroundWindowBorder, 250)
|
||||||
|
|
||||||
const setIgnoreMouseEvents = useElectronEventaInvoke(electron.window.setIgnoreMouseEvents)
|
const setIgnoreMouseEvents = useElectronEventaInvoke(electron.window.setIgnoreMouseEvents)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ConnectionSettings from '@proj-airi/stage-pages/pages/settings/connection/ConnectionSettings.vue'
|
|
||||||
|
|
||||||
import { isStageTamagotchi } from '@proj-airi/stage-shared'
|
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 { Callout, FieldCheckbox, FieldInput, SelectTab } from '@proj-airi/ui'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
@@ -53,80 +52,61 @@ const exposureModeOptions = computed(() => [
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ConnectionSettings>
|
<div>
|
||||||
<template #platform-specific>
|
<Callout
|
||||||
<!-- TODO: show connected remote -->
|
v-if="lastApplyError"
|
||||||
<FieldCheckbox
|
theme="orange"
|
||||||
v-model="websocketTlsEnabled"
|
:label="t('settings.websocket-secure-enabled.title')"
|
||||||
v-motion
|
>
|
||||||
:initial="{ opacity: 0, y: 10 }"
|
{{ lastApplyError }}
|
||||||
:enter="{ opacity: 1, y: 0 }"
|
</Callout>
|
||||||
:duration="250 + (5 * 10)"
|
<ConnectionSettings>
|
||||||
:delay="5 * 50"
|
<template #platform-specific>
|
||||||
:label="t('settings.websocket-secure-enabled.title')"
|
<!-- TODO: show connected remote -->
|
||||||
:description="t('settings.websocket-secure-enabled.description')"
|
<FieldCheckbox
|
||||||
/>
|
v-model="websocketTlsEnabled"
|
||||||
|
:label="t('settings.websocket-secure-enabled.title')"
|
||||||
<div
|
:description="t('settings.websocket-secure-enabled.description')"
|
||||||
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>
|
|
||||||
|
|
||||||
<FieldInput
|
<div
|
||||||
v-if="showDesktopServerControls && showAdvancedHostname"
|
v-if="showDesktopServerControls"
|
||||||
v-model="hostname"
|
:class="['flex', 'flex-col', 'gap-2']"
|
||||||
v-motion
|
>
|
||||||
:initial="{ opacity: 0, y: 10 }"
|
<div :class="['text-sm', 'font-medium', 'text-neutral-900', 'dark:text-neutral-100']">
|
||||||
:enter="{ opacity: 1, y: 0 }"
|
{{ t('settings.pages.connection.server-hostname.label') }}
|
||||||
:duration="250 + (7 * 10)"
|
</div>
|
||||||
:delay="7 * 50"
|
<div :class="['text-xs', 'text-neutral-500', 'dark:text-neutral-400']">
|
||||||
:label="t('settings.pages.connection.server-hostname.advanced-label')"
|
{{ t('settings.pages.connection.server-hostname.description') }}
|
||||||
:description="t('settings.pages.connection.server-hostname.advanced-description')"
|
</div>
|
||||||
placeholder="192.168.1.25"
|
<SelectTab
|
||||||
/>
|
v-model="exposureMode"
|
||||||
|
size="sm"
|
||||||
|
:options="exposureModeOptions"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<FieldInput
|
<FieldInput
|
||||||
v-if="showDesktopServerControls"
|
v-if="showDesktopServerControls && showAdvancedHostname"
|
||||||
v-model="authToken"
|
v-model="hostname"
|
||||||
v-motion
|
:label="t('settings.pages.connection.server-hostname.advanced-label')"
|
||||||
:initial="{ opacity: 0, y: 10 }"
|
:description="t('settings.pages.connection.server-hostname.advanced-description')"
|
||||||
:enter="{ opacity: 1, y: 0 }"
|
placeholder="192.168.1.25"
|
||||||
: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')"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Callout
|
<FieldInput
|
||||||
v-if="lastApplyError"
|
v-if="showDesktopServerControls"
|
||||||
theme="orange"
|
v-model="authToken"
|
||||||
:label="t('settings.websocket-secure-enabled.title')"
|
type="password"
|
||||||
>
|
:label="t('settings.pages.connection.server-auth-token.label')"
|
||||||
{{ lastApplyError }}
|
:description="t('settings.pages.connection.server-auth-token.description')"
|
||||||
</Callout>
|
:placeholder="t('settings.pages.connection.server-auth-token.placeholder')"
|
||||||
|
/>
|
||||||
|
|
||||||
<ServerChannelQrCard />
|
<ServerChannelQrCard />
|
||||||
</template>
|
</template>
|
||||||
</ConnectionSettings>
|
</ConnectionSettings>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<route lang="yaml">
|
<route lang="yaml">
|
||||||
|
|||||||
+4
-3
@@ -3,7 +3,7 @@ import type { ServerChannelQrPayload } from '@proj-airi/stage-shared/server-chan
|
|||||||
|
|
||||||
import { errorMessageFrom } from '@moeru/std'
|
import { errorMessageFrom } from '@moeru/std'
|
||||||
import { useElectronEventaInvoke } from '@proj-airi/electron-vueuse'
|
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 { storeToRefs } from 'pinia'
|
||||||
import { renderSVG } from 'uqr'
|
import { renderSVG } from 'uqr'
|
||||||
import { computed, shallowRef, watch } from 'vue'
|
import { computed, shallowRef, watch } from 'vue'
|
||||||
@@ -12,6 +12,7 @@ import { useI18n } from 'vue-i18n'
|
|||||||
import { electronGetServerChannelQrPayload } from '../../../../shared/eventa'
|
import { electronGetServerChannelQrPayload } from '../../../../shared/eventa'
|
||||||
import { useServerChannelSettingsStore } from '../../../stores/settings/server-channel'
|
import { useServerChannelSettingsStore } from '../../../stores/settings/server-channel'
|
||||||
|
|
||||||
|
const { isDark } = useTheme()
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const getServerChannelQrPayload = useElectronEventaInvoke(electronGetServerChannelQrPayload)
|
const getServerChannelQrPayload = useElectronEventaInvoke(electronGetServerChannelQrPayload)
|
||||||
const { authToken, hostname, tlsConfig } = storeToRefs(useServerChannelSettingsStore())
|
const { authToken, hostname, tlsConfig } = storeToRefs(useServerChannelSettingsStore())
|
||||||
@@ -38,7 +39,7 @@ const qrCodeSource = computed(() => {
|
|||||||
ecc: 'M',
|
ecc: 'M',
|
||||||
pixelSize: 8,
|
pixelSize: 8,
|
||||||
whiteColor: 'transparent',
|
whiteColor: 'transparent',
|
||||||
blackColor: '#111827',
|
blackColor: isDark.value ? '#D5D5D5' : '#121212',
|
||||||
})
|
})
|
||||||
|
|
||||||
return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`
|
return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`
|
||||||
@@ -94,7 +95,7 @@ watch([hostname, tlsConfig, authToken], () => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
:class="[
|
: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',
|
'flex flex-col gap-4',
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ const { statusMessage, statusTone, handleStatus } = createDataSettingsStatusStat
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="['flex flex-col gap-4 pb-4']">
|
<div :class="['flex flex-col gap-4 pb-4']">
|
||||||
<DesktopFolderSection @status="handleStatus" />
|
|
||||||
<StatusBanner v-if="statusMessage" :message="statusMessage" :tone="statusTone" />
|
<StatusBanner v-if="statusMessage" :message="statusMessage" :tone="statusTone" />
|
||||||
|
<DesktopFolderSection @status="handleStatus" />
|
||||||
<ChatsSection @status="handleStatus" />
|
<ChatsSection @status="handleStatus" />
|
||||||
<ModelsModulesSection @status="handleStatus" />
|
<ModelsModulesSection @status="handleStatus" />
|
||||||
<DesktopResetSection @status="handleStatus" />
|
<DesktopResetSection @status="handleStatus" />
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ConnectionSettings from './ConnectionSettings.vue'
|
import { ConnectionSettings } from '@proj-airi/stage-ui/components'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ defineProps<Props>()
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="[
|
: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 === '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 === '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',
|
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'
|
||||||
+2
-1
@@ -1,10 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useModsServerChannelStore } from '@proj-airi/stage-ui/stores/mods/api/channel-server'
|
|
||||||
import { FieldInput } from '@proj-airi/ui'
|
import { FieldInput } from '@proj-airi/ui'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
import { useModsServerChannelStore } from '../../../../stores/mods/api/channel-server'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const { websocketUrl } = storeToRefs(useModsServerChannelStore())
|
const { websocketUrl } = storeToRefs(useModsServerChannelStore())
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
export * from './about'
|
export * from './about'
|
||||||
export * from './chat'
|
export * from './chat'
|
||||||
|
export * from './connection'
|
||||||
export * from './dialogs'
|
export * from './dialogs'
|
||||||
export * from './hologram'
|
export * from './hologram'
|
||||||
export * from './providers'
|
export * from './providers'
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
<script
|
<script
|
||||||
setup
|
setup
|
||||||
lang="ts"
|
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'
|
import { Input } from '../input'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
<script
|
<script
|
||||||
setup
|
setup
|
||||||
lang="ts"
|
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
|
// Define button variants for better type safety and maintainability
|
||||||
type InputVariant = 'primary' | 'secondary' | 'primary-dimmed'
|
type InputVariant = 'primary' | 'secondary' | 'primary-dimmed'
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user