F-1 (Theme Application): Theme selection now applies to all active xterm.js
terminals at runtime via session store reactive propagation. TerminalView
watches sessionStore.activeTheme and calls terminal.options.theme = {...}.
F-5 (Tab Badges): isRootUser() now checks session.username, connection
options JSON, and connection tags — no longer hardcoded to false.
F-6 (Keyboard Shortcuts): Added Ctrl+W (close tab), Ctrl+Tab / Ctrl+Shift+Tab
(next/prev tab), Ctrl+1–9 (tab by index), Ctrl+B (toggle sidebar). Input
field guard prevents shortcuts from firing while typing.
F-7 (Status Bar Dimensions): StatusBar now reads live cols×rows from
sessionStore.activeDimensions. TerminalView hooks onResize to call
sessionStore.setTerminalDimensions(). Falls back to "120×40" until first resize.
F-10 (Multiple Sessions): Removed the "already connected" early-return guard.
Multiple SSH/RDP sessions to the same host are now allowed. Disambiguated tab
names auto-generated: "Asgard", "Asgard (2)", "Asgard (3)", etc.
F-11 (First-Run MobaConf): onMounted checks connectionStore.connections.length
after loadAll(). If empty, shows a dialog offering to import from MobaXTerm.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
90 lines
2.2 KiB
Vue
90 lines
2.2 KiB
Vue
<template>
|
|
<div
|
|
ref="containerRef"
|
|
class="terminal-container"
|
|
@focus="handleFocus"
|
|
/>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, onMounted, watch } from "vue";
|
|
import { useTerminal } from "@/composables/useTerminal";
|
|
import { useSessionStore } from "@/stores/session.store";
|
|
import "@/assets/css/terminal.css";
|
|
|
|
const props = defineProps<{
|
|
sessionId: string;
|
|
isActive: boolean;
|
|
}>();
|
|
|
|
const sessionStore = useSessionStore();
|
|
const containerRef = ref<HTMLElement | null>(null);
|
|
const { terminal, mount, fit } = useTerminal(props.sessionId);
|
|
|
|
onMounted(() => {
|
|
if (containerRef.value) {
|
|
mount(containerRef.value);
|
|
}
|
|
|
|
// Apply the current theme immediately if one is already active
|
|
if (sessionStore.activeTheme) {
|
|
applyTheme();
|
|
}
|
|
|
|
// Track terminal dimensions in the session store
|
|
terminal.onResize(({ cols, rows }) => {
|
|
sessionStore.setTerminalDimensions(props.sessionId, cols, rows);
|
|
});
|
|
});
|
|
|
|
// Re-fit and focus terminal when this tab becomes active
|
|
watch(
|
|
() => props.isActive,
|
|
(active) => {
|
|
if (active) {
|
|
// nextTick is not needed — fit and focus happen after the DOM update
|
|
setTimeout(() => {
|
|
fit();
|
|
terminal.focus();
|
|
}, 0);
|
|
}
|
|
},
|
|
);
|
|
|
|
/** Apply the session store's active theme to this terminal instance. */
|
|
function applyTheme(): void {
|
|
const theme = sessionStore.activeTheme;
|
|
if (!theme) return;
|
|
terminal.options.theme = {
|
|
background: theme.background,
|
|
foreground: theme.foreground,
|
|
cursor: theme.cursor,
|
|
black: theme.black,
|
|
red: theme.red,
|
|
green: theme.green,
|
|
yellow: theme.yellow,
|
|
blue: theme.blue,
|
|
magenta: theme.magenta,
|
|
cyan: theme.cyan,
|
|
white: theme.white,
|
|
brightBlack: theme.brightBlack,
|
|
brightRed: theme.brightRed,
|
|
brightGreen: theme.brightGreen,
|
|
brightYellow: theme.brightYellow,
|
|
brightBlue: theme.brightBlue,
|
|
brightMagenta: theme.brightMagenta,
|
|
brightCyan: theme.brightCyan,
|
|
brightWhite: theme.brightWhite,
|
|
};
|
|
}
|
|
|
|
// Watch for theme changes in the session store and apply to this terminal
|
|
watch(() => sessionStore.activeTheme, (newTheme) => {
|
|
if (newTheme) applyTheme();
|
|
});
|
|
|
|
function handleFocus(): void {
|
|
terminal.focus();
|
|
}
|
|
</script>
|