feat: Show a warning for 10 seconds when disconnected from the server and then automatically hide, Show disconnected in header when disconnected from server
This commit is contained in:
parent
c59640202c
commit
b8b9d36d63
|
@ -13,6 +13,8 @@
|
|||
### Improvements
|
||||
- 클라이언트: (friendly) 모바일 환경에서 서버와 연결이 끊어졌을 때 표시되는 경고창의 UI 개선
|
||||
- 클라이언트: (friendly) 모바일 환경에서 스크롤을 내리면 플로팅 버튼이 감춰지도록 변경
|
||||
- 클라이언트: (friendly) 서버와 연결이 끊어졌을 때 10초간 경고를 표시한 후 자동으로 숨기기
|
||||
- 클라이언트: (friendly) 서버와 연결이 끊어졌을 때 헤더에 연결 끊김 표시
|
||||
- 클라이언트: Google Translate 서비스 추가 (thanks to @ltlapy)
|
||||
- 클라이언트: DeepL과 Google Translate를 선택할 수 있는 옵션 추가
|
||||
- 클라이언트: Enter 키를 눌러 보내기 옵션 추가
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<div v-if="show" ref="el" class="fdidabkb" :class="{ slim: narrow, thin: thin_ }" :style="{ background: bg }" @click="onClick">
|
||||
<div v-if="hasDisconnected && isMobile && narrow && hasTabs" class="buttons left">
|
||||
<button v-tooltip.noDelay="i18n.ts.reload" class="_button button disconnected" @click.stop="reload" @touchstart="preventDrag"><i class="fa-solid fa-bolt"></i></button>
|
||||
</div>
|
||||
<template v-if="metadata">
|
||||
<div v-if="!hideTitle" class="titleContainer" @click="showTabsPopup">
|
||||
<MkAvatar v-if="metadata.avatar" class="avatar" :user="metadata.avatar" :disable-preview="true" :show-indicator="true"/>
|
||||
|
@ -29,6 +32,7 @@
|
|||
<template v-for="action in actions">
|
||||
<button v-tooltip.noDelay="action.text" class="_button button" :class="{ highlighted: action.highlighted }" @click.stop="action.handler" @touchstart="preventDrag"><i :class="action.icon"></i></button>
|
||||
</template>
|
||||
<button v-if="hasDisconnected && !isMobile && (!narrow || hideTitle)" v-tooltip.noDelay="i18n.ts.reload" class="_button button disconnected disconnected-right" @click="reload" @touchstart="preventDrag"><i class="fa-solid fa-bolt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -41,6 +45,15 @@ import { scrollToTop } from '@/scripts/scroll';
|
|||
import { i18n } from '@/i18n';
|
||||
import { globalEvents } from '@/events';
|
||||
import { injectPageMetadata } from '@/scripts/page-metadata';
|
||||
import { deviceKind } from '@/scripts/device-kind';
|
||||
import { stream } from '@/stream';
|
||||
|
||||
const MOBILE_THRESHOLD = 500;
|
||||
|
||||
const isMobile = ref(deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD);
|
||||
window.addEventListener('resize', () => {
|
||||
isMobile.value = deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD;
|
||||
});
|
||||
|
||||
type Tab = {
|
||||
key?: string | null;
|
||||
|
@ -124,6 +137,10 @@ function onTabClick(tab: Tab, ev: MouseEvent): void {
|
|||
}
|
||||
}
|
||||
|
||||
function reload() {
|
||||
location.reload();
|
||||
}
|
||||
|
||||
const calcBg = () => {
|
||||
const rawBg = metadata?.bg || 'var(--bg)';
|
||||
const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
|
||||
|
@ -131,6 +148,13 @@ const calcBg = () => {
|
|||
bg.value = tinyBg.toRgbString();
|
||||
};
|
||||
|
||||
let hasDisconnected = $ref(false);
|
||||
|
||||
function onDisconnected() {
|
||||
hasDisconnected = true;
|
||||
}
|
||||
stream.on('_disconnected_', onDisconnected);
|
||||
|
||||
let ro: ResizeObserver | null;
|
||||
|
||||
onMounted(() => {
|
||||
|
@ -167,6 +191,8 @@ onMounted(() => {
|
|||
onUnmounted(() => {
|
||||
globalEvents.off('themeChanged', calcBg);
|
||||
if (ro) ro.disconnect();
|
||||
|
||||
stream.off('_disconnected_', onDisconnected);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -216,12 +242,28 @@ onUnmounted(() => {
|
|||
height: var(--height);
|
||||
margin: 0 var(--margin);
|
||||
|
||||
&.right {
|
||||
margin-left: auto;
|
||||
&.left {
|
||||
margin-right: auto;
|
||||
|
||||
> .disconnected {
|
||||
transition: opacity 1s, transform 1s;
|
||||
}
|
||||
}
|
||||
|
||||
&:empty {
|
||||
width: var(--height);
|
||||
&.right {
|
||||
margin-left: auto;
|
||||
|
||||
&:empty {
|
||||
width: var(--height);
|
||||
}
|
||||
|
||||
> .disconnected {
|
||||
transition: opacity 1s, transform 1s;
|
||||
}
|
||||
|
||||
> .disconnected-right {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
> .button {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<div v-if="show" ref="el" class="fdidabkb" :class="{ slim: narrow, thin: thin_ }" :style="{ background: bg }" @click="onClick">
|
||||
<div v-if="hasDisconnected && isMobile && narrow && hasTabs" class="buttons left">
|
||||
<button v-tooltip.noDelay="i18n.ts.reload" class="_button button disconnected" @click.stop="reload" @touchstart="preventDrag"><i class="fa-solid fa-bolt"></i></button>
|
||||
</div>
|
||||
<template v-if="metadata">
|
||||
<div v-if="!hideTitle" class="titleContainer" @click="showTabsPopup">
|
||||
<MkAvatar v-if="metadata.avatar" class="avatar" :user="metadata.avatar" :disable-preview="true" :show-indicator="true"/>
|
||||
|
@ -29,6 +32,7 @@
|
|||
<template v-for="action in actions">
|
||||
<button v-tooltip.noDelay="action.text" class="_button button" :class="{ highlighted: action.highlighted }" @click.stop="action.handler" @touchstart="preventDrag"><i :class="action.icon"></i></button>
|
||||
</template>
|
||||
<button v-if="hasDisconnected && !isMobile && (!narrow || hideTitle)" v-tooltip.noDelay="i18n.ts.reload" class="_button button disconnected disconnected-right" @click="reload" @touchstart="preventDrag"><i class="fa-solid fa-bolt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -41,6 +45,15 @@ import { scrollToTop } from '@/scripts/scroll';
|
|||
import { i18n } from '@/i18n';
|
||||
import { globalEvents } from '@/events';
|
||||
import { injectPageMetadata } from '@/scripts/page-metadata';
|
||||
import { stream } from '@/stream';
|
||||
import { deviceKind } from '@/scripts/device-kind';
|
||||
|
||||
const MOBILE_THRESHOLD = 500;
|
||||
|
||||
const isMobile = ref(deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD);
|
||||
window.addEventListener('resize', () => {
|
||||
isMobile.value = deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD;
|
||||
});
|
||||
|
||||
type Tab = {
|
||||
key?: string | null;
|
||||
|
@ -124,6 +137,10 @@ function onTabClick(tab: Tab, ev: MouseEvent): void {
|
|||
}
|
||||
}
|
||||
|
||||
function reload() {
|
||||
location.reload();
|
||||
}
|
||||
|
||||
const calcBg = () => {
|
||||
const rawBg = metadata?.bg || 'var(--bg)';
|
||||
const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
|
||||
|
@ -131,6 +148,13 @@ const calcBg = () => {
|
|||
bg.value = tinyBg.toRgbString();
|
||||
};
|
||||
|
||||
let hasDisconnected = $ref(false);
|
||||
|
||||
function onDisconnected() {
|
||||
hasDisconnected = true;
|
||||
}
|
||||
stream.on('_disconnected_', onDisconnected);
|
||||
|
||||
let ro: ResizeObserver | null;
|
||||
|
||||
onMounted(() => {
|
||||
|
@ -167,6 +191,8 @@ onMounted(() => {
|
|||
onUnmounted(() => {
|
||||
globalEvents.off('themeChanged', calcBg);
|
||||
if (ro) ro.disconnect();
|
||||
|
||||
stream.off('_disconnected_', onDisconnected);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -216,12 +242,28 @@ onUnmounted(() => {
|
|||
height: var(--height);
|
||||
margin: 0 var(--margin);
|
||||
|
||||
&.right {
|
||||
margin-left: auto;
|
||||
&.left {
|
||||
margin-right: auto;
|
||||
|
||||
> .disconnected {
|
||||
transition: opacity 1s, transform 1s;
|
||||
}
|
||||
}
|
||||
|
||||
&:empty {
|
||||
width: var(--height);
|
||||
&.right {
|
||||
margin-left: auto;
|
||||
|
||||
&:empty {
|
||||
width: var(--height);
|
||||
}
|
||||
|
||||
> .disconnected {
|
||||
transition: opacity 1s, transform 1s;
|
||||
}
|
||||
|
||||
> .disconnected-right {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
> .button {
|
||||
|
|
|
@ -1,28 +1,44 @@
|
|||
<template>
|
||||
<div v-if="hasDisconnected && $store.state.serverDisconnectedBehavior === 'quiet'" class="nsbbhtug" :class="{ friendly: isFriendly }" @click="resetDisconnected">
|
||||
<div class="text">{{ i18n.ts.disconnectedFromServer }}</div>
|
||||
<div class="command">
|
||||
<button class="_textButton" @click="reload">{{ i18n.ts.reload }}</button>
|
||||
<button class="_textButton">{{ i18n.ts.doNothing }}</button>
|
||||
<transition v-if="showing && hasDisconnected && $store.state.serverDisconnectedBehavior === 'quiet'" :name="$store.state.animation && isFriendly ? 'friendly' : ''" appear>
|
||||
<div class="nsbbhtug" :class="{ friendly: isFriendly }" @click="resetDisconnected">
|
||||
<div class="text">{{ i18n.ts.disconnectedFromServer }}</div>
|
||||
<div class="command">
|
||||
<button class="_textButton" @click="reload">{{ i18n.ts.reload }}</button>
|
||||
<button class="_textButton">{{ i18n.ts.doNothing }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onUnmounted, ref } from 'vue';
|
||||
import { onMounted, onUnmounted, ref } from 'vue';
|
||||
import { stream } from '@/stream';
|
||||
import { i18n } from '@/i18n';
|
||||
|
||||
const isFriendly = $ref(localStorage.getItem('ui') === 'friendly');
|
||||
|
||||
let showing = $ref(true);
|
||||
let hasDisconnected = $ref(false);
|
||||
let currentTimeout = $ref(0);
|
||||
|
||||
function timeout() {
|
||||
currentTimeout = window.setTimeout(() => {
|
||||
showing = !isFriendly;
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
function clearTimeout() {
|
||||
window.clearTimeout(currentTimeout);
|
||||
}
|
||||
|
||||
function onDisconnected() {
|
||||
hasDisconnected = true;
|
||||
timeout();
|
||||
}
|
||||
|
||||
function resetDisconnected() {
|
||||
hasDisconnected = false;
|
||||
clearTimeout();
|
||||
}
|
||||
|
||||
function reload() {
|
||||
|
@ -37,6 +53,14 @@ onUnmounted(() => {
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.friendly-enter-active, .friendly-leave-active {
|
||||
// transition: opacity 0.3s, transform 0.3s !important;
|
||||
}
|
||||
.friendly-enter-from, .friendly-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(-250px);
|
||||
}
|
||||
|
||||
.nsbbhtug {
|
||||
position: fixed;
|
||||
z-index: 16385;
|
||||
|
@ -60,6 +84,7 @@ onUnmounted(() => {
|
|||
bottom: initial;
|
||||
right: initial;
|
||||
border-radius: initial;
|
||||
transition: opacity 0.5s, transform 0.5s;
|
||||
|
||||
> .text {
|
||||
padding: 0.7em;
|
||||
|
|
Loading…
Reference in a new issue