Files
Nexus/frontend/src/components/terminal/TerminalToolbar.vue
T

185 lines
5.7 KiB
Vue
Raw Normal View History

<template>
<div class="d-flex align-center justify-space-between px-3 py-1 shrink-0 terminal-toolbar">
<div class="d-flex align-center ga-2 min-w-0 terminal-toolbar__meta">
<div class="min-w-0">
<div class="text-body-2 font-weight-medium text-truncate">
{{ session?.serverName || '...' }}
</div>
<div
v-if="session?.serverDomain"
class="text-caption text-truncate text-medium-emphasis font-mono"
>
{{ session.serverDomain }}
</div>
</div>
<span
v-if="session?.cwd"
class="text-caption font-mono terminal-toolbar__cwd text-medium-emphasis hidden-sm-and-down"
:title="session.cwd"
>
{{ session.cwd }}
</span>
<v-chip v-if="session" :color="statusColor" variant="tonal" size="x-small" label>
<template #prepend>
<v-icon start size="8">mdi-circle</v-icon>
</template>
{{ statusLabel }}
</v-chip>
<span v-if="session?.uptime" class="text-caption text-medium-emphasis hidden-sm-and-down">
{{ session.uptime }}
</span>
<span
v-if="session?.pingMs !== null && session?.pingMs !== undefined"
class="text-caption text-medium-emphasis hidden-sm-and-down"
>
{{ session.pingMs }}ms
</span>
</div>
<div class="d-flex align-center ga-1 terminal-toolbar-actions shrink-0">
<div class="d-none d-md-flex align-center ga-2">
<v-btn
v-if="session"
variant="tonal"
color="deep-orange"
size="x-small"
prepend-icon="mdi-login-variant"
title="一键登录宝塔面板"
class="terminal-toolbar__bt-login"
:loading="btLoginLoading"
:disabled="btLoginLoading"
@click="$emit('bt-login')"
>
宝塔登录
</v-btn>
<span class="text-caption text-medium-emphasis shrink-0">字号</span>
<v-btn variant="tonal" size="x-small" @click="$emit('font-change', -1)"></v-btn>
<span class="text-body-2 font-weight-medium terminal-toolbar__font-size">
{{ fontSize }}
</span>
<v-btn variant="tonal" size="x-small" @click="$emit('font-change', 1)">+</v-btn>
<v-select
:model-value="scrollback"
:items="scrollbackOptions"
item-title="title"
item-value="value"
label="回滚"
density="compact"
hide-details
variant="outlined"
class="terminal-toolbar-scrollback"
@update:model-value="$emit('scrollback-change', $event)"
/>
</div>
<v-menu location="bottom end">
<template #activator="{ props: menuProps }">
<v-btn
v-bind="menuProps"
class="d-md-none"
size="x-small"
variant="tonal"
icon="mdi-cog-outline"
/>
</template>
<v-list density="compact" nav class="py-1">
<v-list-item
v-if="session"
:disabled="btLoginLoading"
@click="$emit('bt-login')"
>
<template #prepend>
<v-icon color="deep-orange">mdi-login-variant</v-icon>
</template>
<v-list-item-title>一键登录宝塔</v-list-item-title>
</v-list-item>
<v-divider v-if="session" class="my-1" />
<v-list-subheader>字号 {{ fontSize }}</v-list-subheader>
<v-list-item @click="$emit('font-change', -1)">
<v-list-item-title>缩小</v-list-item-title>
</v-list-item>
<v-list-item @click="$emit('font-change', 1)">
<v-list-item-title>放大</v-list-item-title>
</v-list-item>
<v-divider class="my-1" />
<v-list-subheader>回滚行数</v-list-subheader>
<v-list-item
v-for="opt in scrollbackOptions"
:key="opt.value"
:active="scrollback === opt.value"
@click="$emit('scrollback-change', opt.value)"
>
<v-list-item-title>{{ opt.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<v-btn variant="tonal" size="x-small" icon="mdi-fullscreen" title="全屏" @click="$emit('fullscreen')" />
<v-btn
variant="tonal"
size="x-small"
color="error"
icon="mdi-link-off"
title="断开"
@click="$emit('disconnect')"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import {
sessionStatusColor,
sessionStatusLabel,
type TermSessionData,
} from '@/composables/terminal/types'
import { scrollbackOptions } from '@/composables/terminal/useTerminalSettings'
const props = defineProps<{
session: TermSessionData | null
fontSize: number
scrollback: number
btLoginLoading?: boolean
}>()
defineEmits<{
'font-change': [delta: number]
'scrollback-change': [value: number]
fullscreen: []
disconnect: []
'bt-login': []
}>()
const statusLabel = computed(() =>
props.session ? sessionStatusLabel(props.session) : '',
)
const statusColor = computed(() =>
props.session ? sessionStatusColor(props.session) : 'grey',
)
</script>
<style scoped>
.terminal-toolbar {
background: rgb(var(--v-theme-surface));
border-bottom: 1px solid rgb(var(--v-theme-surface-variant));
min-height: 36px;
}
.terminal-toolbar__cwd {
max-width: min(28vw, 240px);
}
.terminal-toolbar__font-size {
min-width: 1.25rem;
text-align: center;
}
.terminal-toolbar-scrollback {
min-width: 6.5rem;
max-width: 7.5rem;
}
.terminal-toolbar__bt-login {
font-weight: 600;
letter-spacing: 0.01em;
text-transform: none;
}
.font-mono {
font-family: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', Menlo, monospace;
}
</style>