mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-09-12 18:44:25 +08:00
fix: 修复设置页页眉回弹和状态色辨识度 #281
- 在侧栏布局滚动容器统一阻止纵向 overscroll - 拆分状态指示色与成功文本色,提升在线状态辨识度 - 统一连接、运行及键盘 LED 等状态点样式
This commit is contained in:
@@ -48,13 +48,13 @@ const keysDisplay = computed(() => {
|
|||||||
<div class="flex items-center justify-between text-xs px-2 py-0.5">
|
<div class="flex items-center justify-between text-xs px-2 py-0.5">
|
||||||
<div v-if="keyboardLedEnabled" class="flex items-center gap-1">
|
<div v-if="keyboardLedEnabled" class="flex items-center gap-1">
|
||||||
<Badge variant="outline" class="h-4 gap-1 px-1 text-[10px] text-foreground">
|
<Badge variant="outline" class="h-4 gap-1 px-1 text-[10px] text-foreground">
|
||||||
<span class="size-1.5 rounded-full" :class="capsLock ? 'bg-success' : 'bg-warning'" />C
|
<span class="size-1.5 rounded-full" :class="capsLock ? 'bg-status-active' : 'bg-warning'" />C
|
||||||
</Badge>
|
</Badge>
|
||||||
<Badge variant="outline" class="h-4 gap-1 px-1 text-[10px] text-foreground">
|
<Badge variant="outline" class="h-4 gap-1 px-1 text-[10px] text-foreground">
|
||||||
<span class="size-1.5 rounded-full" :class="numLock ? 'bg-success' : 'bg-warning'" />N
|
<span class="size-1.5 rounded-full" :class="numLock ? 'bg-status-active' : 'bg-warning'" />N
|
||||||
</Badge>
|
</Badge>
|
||||||
<Badge variant="outline" class="h-4 gap-1 px-1 text-[10px] text-foreground">
|
<Badge variant="outline" class="h-4 gap-1 px-1 text-[10px] text-foreground">
|
||||||
<span class="size-1.5 rounded-full" :class="scrollLock ? 'bg-success' : 'bg-warning'" />S
|
<span class="size-1.5 rounded-full" :class="scrollLock ? 'bg-status-active' : 'bg-warning'" />S
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="text-[10px] text-muted-foreground/60">
|
<div v-else class="text-[10px] text-muted-foreground/60">
|
||||||
@@ -87,15 +87,15 @@ const keysDisplay = computed(() => {
|
|||||||
<Separator orientation="vertical" class="h-5" />
|
<Separator orientation="vertical" class="h-5" />
|
||||||
<template v-if="keyboardLedEnabled">
|
<template v-if="keyboardLedEnabled">
|
||||||
<Badge variant="outline" class="mx-1 gap-1.5 text-foreground">
|
<Badge variant="outline" class="mx-1 gap-1.5 text-foreground">
|
||||||
<span class="size-1.5 rounded-full" :class="capsLock ? 'bg-success' : 'bg-warning'" />
|
<span class="size-1.5 rounded-full" :class="capsLock ? 'bg-status-active' : 'bg-warning'" />
|
||||||
{{ t('infobar.caps') }}
|
{{ t('infobar.caps') }}
|
||||||
</Badge>
|
</Badge>
|
||||||
<Badge variant="outline" class="mx-1 gap-1.5 text-foreground">
|
<Badge variant="outline" class="mx-1 gap-1.5 text-foreground">
|
||||||
<span class="size-1.5 rounded-full" :class="numLock ? 'bg-success' : 'bg-warning'" />
|
<span class="size-1.5 rounded-full" :class="numLock ? 'bg-status-active' : 'bg-warning'" />
|
||||||
{{ t('infobar.num') }}
|
{{ t('infobar.num') }}
|
||||||
</Badge>
|
</Badge>
|
||||||
<Badge variant="outline" class="mx-1 gap-1.5 text-foreground">
|
<Badge variant="outline" class="mx-1 gap-1.5 text-foreground">
|
||||||
<span class="size-1.5 rounded-full" :class="scrollLock ? 'bg-success' : 'bg-warning'" />
|
<span class="size-1.5 rounded-full" :class="scrollLock ? 'bg-status-active' : 'bg-warning'" />
|
||||||
{{ t('infobar.scroll') }}
|
{{ t('infobar.scroll') }}
|
||||||
</Badge>
|
</Badge>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -714,8 +714,8 @@ onUnmounted(() => {
|
|||||||
<span class="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1">
|
<span class="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1">
|
||||||
<span :class="msdConnected ? 'text-success' : 'text-muted-foreground'" class="flex items-center gap-1.5">
|
<span :class="msdConnected ? 'text-success' : 'text-muted-foreground'" class="flex items-center gap-1.5">
|
||||||
<span class="relative flex size-2">
|
<span class="relative flex size-2">
|
||||||
<span v-if="msdConnected" class="absolute inline-flex h-full w-full animate-ping rounded-full bg-success opacity-75"></span>
|
<span v-if="msdConnected" class="absolute inline-flex size-full animate-ping rounded-full bg-status-active opacity-75"></span>
|
||||||
<span :class="msdConnected ? 'bg-success' : 'bg-muted-foreground'" class="relative inline-flex size-2 rounded-full"></span>
|
<span :class="msdConnected ? 'bg-status-active' : 'bg-muted-foreground'" class="relative inline-flex size-2 rounded-full"></span>
|
||||||
</span>
|
</span>
|
||||||
{{ msdConnected ? t('common.connected') : t('common.disconnected') }}
|
{{ msdConnected ? t('common.connected') : t('common.disconnected') }}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -529,8 +529,8 @@ onUnmounted(() => {
|
|||||||
<Item variant="muted" size="sm"><ItemContent><ItemDescription>{{ t('stats.connectionType') }}</ItemDescription><ItemTitle class="flex items-center gap-1.5">
|
<Item variant="muted" size="sm"><ItemContent><ItemDescription>{{ t('stats.connectionType') }}</ItemDescription><ItemTitle class="flex items-center gap-1.5">
|
||||||
<span
|
<span
|
||||||
:class="[
|
:class="[
|
||||||
'inline-block w-2 h-2 rounded-full',
|
'inline-block size-2 rounded-full',
|
||||||
currentStats.isRelay ? 'bg-warning' : 'bg-success'
|
currentStats.isRelay ? 'bg-warning' : 'bg-status-active'
|
||||||
]"
|
]"
|
||||||
/>
|
/>
|
||||||
{{ currentStats.isRelay ? t('stats.relay') : t('stats.p2p') }}
|
{{ currentStats.isRelay ? t('stats.relay') : t('stats.p2p') }}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ onMounted(() => {
|
|||||||
const statusColor = computed(() => {
|
const statusColor = computed(() => {
|
||||||
switch (props.status) {
|
switch (props.status) {
|
||||||
case 'connected':
|
case 'connected':
|
||||||
return 'bg-success'
|
return 'bg-status-active'
|
||||||
case 'connecting':
|
case 'connecting':
|
||||||
return 'bg-warning animate-pulse'
|
return 'bg-warning animate-pulse'
|
||||||
case 'disconnected':
|
case 'disconnected':
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const props = defineProps<{
|
|||||||
<div
|
<div
|
||||||
data-slot="sidebar-content"
|
data-slot="sidebar-content"
|
||||||
data-sidebar="content"
|
data-sidebar="content"
|
||||||
:class="cn('flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden', props.class)"
|
:class="cn('flex min-h-0 flex-1 flex-col gap-2 overflow-auto overscroll-y-none group-data-[collapsible=icon]:overflow-hidden', props.class)"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const props = defineProps<{
|
|||||||
<main
|
<main
|
||||||
data-slot="sidebar-inset"
|
data-slot="sidebar-inset"
|
||||||
:class="cn(
|
:class="cn(
|
||||||
'bg-background relative flex w-full flex-1 flex-col',
|
'bg-background relative flex min-h-0 w-full flex-1 flex-col overflow-y-auto overscroll-y-none',
|
||||||
'md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2',
|
'md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2',
|
||||||
props.class,
|
props.class,
|
||||||
)"
|
)"
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
--destructive-foreground: oklch(98.48% 0 0);
|
--destructive-foreground: oklch(98.48% 0 0);
|
||||||
--success: oklch(52.7% 0.154 150.07);
|
--success: oklch(52.7% 0.154 150.07);
|
||||||
--success-foreground: oklch(98.48% 0 0);
|
--success-foreground: oklch(98.48% 0 0);
|
||||||
|
/* Compact state indicators need stronger luminance separation than success text. */
|
||||||
|
--status-active: oklch(72.3% 0.219 149.58);
|
||||||
--warning: oklch(55.4% 0.135 66.44);
|
--warning: oklch(55.4% 0.135 66.44);
|
||||||
--warning-foreground: oklch(98.48% 0 0);
|
--warning-foreground: oklch(98.48% 0 0);
|
||||||
--info: oklch(54.6% 0.245 262.88);
|
--info: oklch(54.6% 0.245 262.88);
|
||||||
@@ -111,6 +113,7 @@
|
|||||||
--color-destructive-foreground: var(--destructive-foreground);
|
--color-destructive-foreground: var(--destructive-foreground);
|
||||||
--color-success: var(--success);
|
--color-success: var(--success);
|
||||||
--color-success-foreground: var(--success-foreground);
|
--color-success-foreground: var(--success-foreground);
|
||||||
|
--color-status-active: var(--status-active);
|
||||||
--color-warning: var(--warning);
|
--color-warning: var(--warning);
|
||||||
--color-warning-foreground: var(--warning-foreground);
|
--color-warning-foreground: var(--warning-foreground);
|
||||||
--color-info: var(--info);
|
--color-info: var(--info);
|
||||||
|
|||||||
@@ -368,7 +368,7 @@ function watchdogRequestError(error: unknown, action: 'enable' | 'disable'): str
|
|||||||
|
|
||||||
const watchdogStatusClass = computed(() => {
|
const watchdogStatusClass = computed(() => {
|
||||||
switch (watchdogStatusKey.value) {
|
switch (watchdogStatusKey.value) {
|
||||||
case 'running': return 'bg-success'
|
case 'running': return 'bg-status-active'
|
||||||
case 'error': return 'bg-destructive'
|
case 'error': return 'bg-destructive'
|
||||||
default: return 'bg-muted-foreground'
|
default: return 'bg-muted-foreground'
|
||||||
}
|
}
|
||||||
@@ -819,7 +819,7 @@ function otgCheckStatusText(level: OtgSelfCheckLevel): string {
|
|||||||
function otgGroupStatusClass(status: OtgCheckGroupStatus): string {
|
function otgGroupStatusClass(status: OtgCheckGroupStatus): string {
|
||||||
if (status === 'error') return 'bg-destructive'
|
if (status === 'error') return 'bg-destructive'
|
||||||
if (status === 'warn') return 'bg-warning'
|
if (status === 'warn') return 'bg-warning'
|
||||||
if (status === 'ok') return 'bg-success'
|
if (status === 'ok') return 'bg-status-active'
|
||||||
return 'bg-muted-foreground/40'
|
return 'bg-muted-foreground/40'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1778,7 +1778,7 @@ function getExtStatusClass(status: ExtensionStatus | undefined): string {
|
|||||||
switch (status.state) {
|
switch (status.state) {
|
||||||
case 'unavailable': return 'bg-muted-foreground'
|
case 'unavailable': return 'bg-muted-foreground'
|
||||||
case 'stopped': return 'bg-muted-foreground'
|
case 'stopped': return 'bg-muted-foreground'
|
||||||
case 'running': return 'bg-success'
|
case 'running': return 'bg-status-active'
|
||||||
default: return 'bg-muted-foreground'
|
default: return 'bg-muted-foreground'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2470,7 +2470,7 @@ function getRustdeskStatusClass(status: string | null | undefined): string {
|
|||||||
switch (status) {
|
switch (status) {
|
||||||
case 'running':
|
case 'running':
|
||||||
case 'registered':
|
case 'registered':
|
||||||
case 'connected': return 'bg-success'
|
case 'connected': return 'bg-status-active'
|
||||||
case 'starting':
|
case 'starting':
|
||||||
case 'connecting': return 'bg-warning'
|
case 'connecting': return 'bg-warning'
|
||||||
case 'stopped':
|
case 'stopped':
|
||||||
@@ -2648,7 +2648,7 @@ function getVncServiceStatusText(status: string | undefined): string {
|
|||||||
|
|
||||||
function getVncStatusClass(status: string | undefined): string {
|
function getVncStatusClass(status: string | undefined): string {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 'running': return 'bg-success'
|
case 'running': return 'bg-status-active'
|
||||||
case 'starting': return 'bg-warning'
|
case 'starting': return 'bg-warning'
|
||||||
case 'stopped': return 'bg-muted-foreground'
|
case 'stopped': return 'bg-muted-foreground'
|
||||||
default:
|
default:
|
||||||
@@ -2671,7 +2671,7 @@ function getRtspServiceStatusText(status: string | undefined): string {
|
|||||||
|
|
||||||
function getRtspStatusClass(status: string | undefined): string {
|
function getRtspStatusClass(status: string | undefined): string {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 'running': return 'bg-success'
|
case 'running': return 'bg-status-active'
|
||||||
case 'starting': return 'bg-warning'
|
case 'starting': return 'bg-warning'
|
||||||
case 'stopped': return 'bg-muted-foreground'
|
case 'stopped': return 'bg-muted-foreground'
|
||||||
default:
|
default:
|
||||||
@@ -2761,7 +2761,7 @@ watch(isWindows, () => {
|
|||||||
</SidebarContent>
|
</SidebarContent>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
|
||||||
<SidebarInset class="min-w-0 overflow-y-auto">
|
<SidebarInset class="min-w-0">
|
||||||
<!-- Mobile Header -->
|
<!-- Mobile Header -->
|
||||||
<div class="md:hidden sticky top-0 z-20 flex items-center px-3 sm:px-4 py-2 sm:py-3 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/70">
|
<div class="md:hidden sticky top-0 z-20 flex items-center px-3 sm:px-4 py-2 sm:py-3 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/70">
|
||||||
<SidebarTrigger class="mr-1.5 size-8 sm:mr-2 sm:size-9" />
|
<SidebarTrigger class="mr-1.5 size-8 sm:mr-2 sm:size-9" />
|
||||||
@@ -4362,7 +4362,7 @@ watch(isWindows, () => {
|
|||||||
<!-- Status and controls -->
|
<!-- Status and controls -->
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div :class="['w-2 h-2 rounded-full', getExtStatusClass(extensions?.ttyd?.status)]" />
|
<div :class="['size-2 rounded-full', getExtStatusClass(extensions?.ttyd?.status)]" />
|
||||||
<span class="text-sm">{{ getExtStatusText(extensions?.ttyd?.status) }}</span>
|
<span class="text-sm">{{ getExtStatusText(extensions?.ttyd?.status) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
@@ -4453,7 +4453,7 @@ watch(isWindows, () => {
|
|||||||
<!-- Status and controls -->
|
<!-- Status and controls -->
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div :class="['w-2 h-2 rounded-full', getExtStatusClass(extensions?.gostc?.status)]" />
|
<div :class="['size-2 rounded-full', getExtStatusClass(extensions?.gostc?.status)]" />
|
||||||
<span class="text-sm">{{ getExtStatusText(extensions?.gostc?.status) }}</span>
|
<span class="text-sm">{{ getExtStatusText(extensions?.gostc?.status) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
@@ -4548,7 +4548,7 @@ watch(isWindows, () => {
|
|||||||
<!-- Status and controls -->
|
<!-- Status and controls -->
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div :class="['w-2 h-2 rounded-full', getExtStatusClass(extensions?.easytier?.status)]" />
|
<div :class="['size-2 rounded-full', getExtStatusClass(extensions?.easytier?.status)]" />
|
||||||
<span class="text-sm">{{ getExtStatusText(extensions?.easytier?.status) }}</span>
|
<span class="text-sm">{{ getExtStatusText(extensions?.easytier?.status) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
@@ -4654,7 +4654,7 @@ watch(isWindows, () => {
|
|||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div :class="['w-2 h-2 rounded-full', getExtStatusClass(extensions?.frpc?.status)]" />
|
<div :class="['size-2 rounded-full', getExtStatusClass(extensions?.frpc?.status)]" />
|
||||||
<span class="text-sm">{{ getExtStatusText(extensions?.frpc?.status) }}</span>
|
<span class="text-sm">{{ getExtStatusText(extensions?.frpc?.status) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
@@ -4828,7 +4828,7 @@ watch(isWindows, () => {
|
|||||||
<CardContent class="space-y-4">
|
<CardContent class="space-y-4">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div :class="['w-2 h-2 rounded-full', getRtspStatusClass(rtspStatus?.service_status)]" />
|
<div :class="['size-2 rounded-full', getRtspStatusClass(rtspStatus?.service_status)]" />
|
||||||
<span class="text-sm">{{ getRtspServiceStatusText(rtspStatus?.service_status) }}</span>
|
<span class="text-sm">{{ getRtspServiceStatusText(rtspStatus?.service_status) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
@@ -4954,7 +4954,7 @@ watch(isWindows, () => {
|
|||||||
<CardContent class="space-y-4">
|
<CardContent class="space-y-4">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div :class="['w-2 h-2 rounded-full', getVncStatusClass(vncStatus?.service_status)]" />
|
<div :class="['size-2 rounded-full', getVncStatusClass(vncStatus?.service_status)]" />
|
||||||
<span class="text-sm">{{ getVncServiceStatusText(vncStatus?.service_status) }}</span>
|
<span class="text-sm">{{ getVncServiceStatusText(vncStatus?.service_status) }}</span>
|
||||||
<template v-if="vncStatus?.connection_count">
|
<template v-if="vncStatus?.connection_count">
|
||||||
<span class="text-muted-foreground">|</span>
|
<span class="text-muted-foreground">|</span>
|
||||||
@@ -5077,11 +5077,11 @@ watch(isWindows, () => {
|
|||||||
<!-- Status and controls -->
|
<!-- Status and controls -->
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div :class="['w-2 h-2 rounded-full', getRustdeskStatusClass(rustdeskStatus?.service_status)]" />
|
<div :class="['size-2 rounded-full', getRustdeskStatusClass(rustdeskStatus?.service_status)]" />
|
||||||
<span class="text-sm">{{ getRustdeskServiceStatusText(rustdeskStatus?.service_status) }}</span>
|
<span class="text-sm">{{ getRustdeskServiceStatusText(rustdeskStatus?.service_status) }}</span>
|
||||||
<template v-if="rustdeskStatus?.rendezvous_status">
|
<template v-if="rustdeskStatus?.rendezvous_status">
|
||||||
<span class="text-muted-foreground">|</span>
|
<span class="text-muted-foreground">|</span>
|
||||||
<div :class="['w-2 h-2 rounded-full', getRustdeskStatusClass(rustdeskStatus?.rendezvous_status)]" />
|
<div :class="['size-2 rounded-full', getRustdeskStatusClass(rustdeskStatus?.rendezvous_status)]" />
|
||||||
<span class="text-sm text-muted-foreground">{{ getRustdeskRendezvousStatusText(rustdeskStatus?.rendezvous_status) }}</span>
|
<span class="text-sm text-muted-foreground">{{ getRustdeskRendezvousStatusText(rustdeskStatus?.rendezvous_status) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user