fix(stage-ui): stabilize connection status animation (#2365)
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import { useLampFlickerAnimation } from '@proj-airi/stage-ui/composables/use-lamp-flicker-animation'
|
||||
import { useModsServerChannelStore } from '@proj-airi/stage-ui/stores/mods/api/channel-server'
|
||||
import { lampFlickerAnimationClass } from '@proj-airi/ui'
|
||||
import { storeToRefs } from 'pinia'
|
||||
@@ -11,8 +10,6 @@ const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const { connected } = storeToRefs(useModsServerChannelStore())
|
||||
|
||||
const { flickerStyle, onAnimationIteration } = useLampFlickerAnimation(() => !connected.value)
|
||||
|
||||
const statusSize = {
|
||||
border: 'border-2',
|
||||
icon: 'size-6',
|
||||
@@ -66,11 +63,7 @@ function openConnectionSettings() {
|
||||
:title="tooltipLabel"
|
||||
@click="openConnectionSettings"
|
||||
>
|
||||
<div
|
||||
:class="iconClasses"
|
||||
:style="flickerStyle"
|
||||
@animationiteration="onAnimationIteration"
|
||||
/>
|
||||
<div :class="iconClasses" />
|
||||
</button>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { useElectronEventaInvoke } from '@proj-airi/electron-vueuse'
|
||||
import { useLampFlickerAnimation } from '@proj-airi/stage-ui/composables/use-lamp-flicker-animation'
|
||||
import { useModsServerChannelStore } from '@proj-airi/stage-ui/stores/mods/api/channel-server'
|
||||
import { lampFlickerAnimationClass } from '@proj-airi/ui'
|
||||
import { storeToRefs } from 'pinia'
|
||||
@@ -21,8 +20,6 @@ const { t } = useI18n()
|
||||
const { connected } = storeToRefs(useModsServerChannelStore())
|
||||
const openSettings = useElectronEventaInvoke(electronOpenSettings)
|
||||
|
||||
const { flickerStyle, onAnimationIteration } = useLampFlickerAnimation(() => !connected.value)
|
||||
|
||||
const iconClasses = computed(() => {
|
||||
return [
|
||||
'i-mingcute:link-3-line',
|
||||
@@ -51,7 +48,7 @@ const tooltipLabel = computed(() => {
|
||||
:title="tooltipLabel"
|
||||
@click="openSettings({ route: '/settings/connection' })"
|
||||
>
|
||||
<div :class="iconClasses" :style="flickerStyle" @animationiteration="onAnimationIteration" />
|
||||
<div :class="iconClasses" />
|
||||
</ControlButton>
|
||||
<template #tooltip>
|
||||
{{ tooltipLabel }}
|
||||
|
||||
@@ -12,7 +12,6 @@ export * from './use-chat-session/summary'
|
||||
export * from './use-hearing-playground-segments'
|
||||
export * from './use-inference-preload'
|
||||
export * from './use-inference-status'
|
||||
export * from './use-lamp-flicker-animation'
|
||||
export * from './use-linked-accounts'
|
||||
export * from './use-model-preload'
|
||||
export * from './use-optimistic'
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
import type { MaybeRefOrGetter } from 'vue'
|
||||
|
||||
import { lampFlickerAnimationClass } from '@proj-airi/ui'
|
||||
import { computed, ref, toValue, watch } from 'vue'
|
||||
|
||||
export { lampFlickerAnimationClass }
|
||||
|
||||
const LAMP_FLICKER_DELAY_VAR = '--lamp-flicker-delay'
|
||||
const LAMP_FLICKER_DURATION_VAR = '--lamp-flicker-duration'
|
||||
|
||||
/**
|
||||
* Drives randomized keyframe timing for `.lamp-flicker-animation` from `@proj-airi/ui/main.css` while `flickerActive` is true.
|
||||
* Import `@proj-airi/ui/main.css` from the app global stylesheet (e.g. `styles/main.css`). When inactive, delay resets to 0s.
|
||||
*/
|
||||
export function useLampFlickerAnimation(flickerActive: MaybeRefOrGetter<boolean>) {
|
||||
const flickerDuration = ref('6.4s')
|
||||
const flickerDelay = ref('0s')
|
||||
|
||||
function randomizeFlicker(resetPhase = false) {
|
||||
flickerDuration.value = `${(5.8 + Math.random() * 1.8).toFixed(2)}s`
|
||||
|
||||
if (resetPhase) {
|
||||
flickerDelay.value = `${(-Math.random() * 5.4).toFixed(2)}s`
|
||||
return
|
||||
}
|
||||
|
||||
flickerDelay.value = '0s'
|
||||
}
|
||||
|
||||
function onAnimationIteration() {
|
||||
if (toValue(flickerActive)) {
|
||||
randomizeFlicker()
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => toValue(flickerActive),
|
||||
(active) => {
|
||||
if (!active) {
|
||||
flickerDelay.value = '0s'
|
||||
return
|
||||
}
|
||||
|
||||
randomizeFlicker(true)
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
const flickerStyle = computed(() => {
|
||||
if (!toValue(flickerActive)) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return {
|
||||
[LAMP_FLICKER_DELAY_VAR]: flickerDelay.value,
|
||||
[LAMP_FLICKER_DURATION_VAR]: flickerDuration.value,
|
||||
} as Record<string, string>
|
||||
})
|
||||
|
||||
return {
|
||||
flickerStyle,
|
||||
onAnimationIteration,
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,2 @@
|
||||
/** Global class from `@proj-airi/ui/main.css`; pairs with useLampFlickerAnimation in stage-ui. */
|
||||
/** Global offline-status animation class from `@proj-airi/ui/main.css`. */
|
||||
export const lampFlickerAnimationClass = 'lamp-flicker-animation' as const
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Opacity “lamp flicker” for offline / warning icons.
|
||||
* Timing is driven by useLampFlickerAnimation (@proj-airi/stage-ui) via
|
||||
* --lamp-flicker-delay and --lamp-flicker-duration.
|
||||
* Loaded via @proj-airi/ui/main.css (import from app `styles/main.css`).
|
||||
*/
|
||||
@keyframes lamp-flicker-keyframes {
|
||||
@@ -78,11 +76,7 @@
|
||||
}
|
||||
|
||||
.lamp-flicker-animation {
|
||||
animation-delay: var(--lamp-flicker-delay, 0s);
|
||||
animation-duration: var(--lamp-flicker-duration, 6.4s);
|
||||
animation-iteration-count: infinite;
|
||||
animation-name: lamp-flicker-keyframes;
|
||||
animation-timing-function: ease-in-out;
|
||||
animation: lamp-flicker-keyframes 6.4s ease-in-out infinite;
|
||||
filter: drop-shadow(0 0 0.14rem rgb(251 191 36 / 0.18));
|
||||
will-change: opacity;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user