fix: 6 UX regressions — popups, themes, cursor, selection, status bar
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m51s
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m51s
Popup windows (tools/editor/help):
- CSP script-src 'self' blocked Tauri's inline IPC bridge scripts in
child WebviewWindows. Added 'unsafe-inline' to script-src. Still
restrictive (was null before SEC-4).
Theme application:
- Watcher on sessionStore.activeTheme needed { deep: true } — Pinia
reactive proxy identity doesn't change on object replacement
- LocalTerminalView.vue had ZERO theme support — added full applyTheme()
with watcher and mount-time application
- Container background now syncs with theme (was stuck on CSS variable)
Cursor blink:
- terminal.focus() after mount in useTerminal.ts — terminal opened
without focus, xterm.js rendered static outline instead of blinking block
Selection highlighting:
- applyTheme() was overwriting theme without selectionBackground/
selectionForeground/selectionInactiveBackground — selection invisible
after any theme change
- Removed !important from terminal.css that overrode canvas selection
- Bumped default selection opacity 0.3 → 0.4
Status bar:
- h-6 text-[10px] → h-8 text-xs (24px/10px → 32px/12px)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6acd674905
commit
aa2ef88ed7
@ -23,7 +23,7 @@
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' asset: https://asset.localhost data:; connect-src 'self' ipc: http://ipc.localhost"
|
||||
"csp": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' asset: https://asset.localhost data:; connect-src 'self' ipc: http://ipc.localhost"
|
||||
},
|
||||
"withGlobalTauri": false
|
||||
},
|
||||
|
||||
@ -20,9 +20,11 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Selection styling */
|
||||
/* Selection styling — let xterm.js theme handle selection colors.
|
||||
The !important override was removed because it conflicts with
|
||||
theme-driven selectionBackground set via terminal.options.theme. */
|
||||
.terminal-container .xterm-selection div {
|
||||
background-color: rgba(88, 166, 255, 0.3) !important;
|
||||
background-color: rgba(88, 166, 255, 0.3);
|
||||
}
|
||||
|
||||
/* Cursor styling */
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="h-6 flex items-center justify-between px-4 bg-[var(--wraith-bg-secondary)] border-t border-[var(--wraith-border)] text-[10px] text-[var(--wraith-text-muted)] shrink-0">
|
||||
<div class="h-8 flex items-center justify-between px-4 bg-[var(--wraith-bg-secondary)] border-t border-[var(--wraith-border)] text-xs text-[var(--wraith-text-muted)] shrink-0">
|
||||
<!-- Left: connection info -->
|
||||
<div class="flex items-center gap-3">
|
||||
<template v-if="sessionStore.activeSession">
|
||||
|
||||
@ -112,6 +112,8 @@ export interface ThemeDefinition {
|
||||
brightMagenta: string;
|
||||
brightCyan: string;
|
||||
brightWhite: string;
|
||||
selectionBackground?: string;
|
||||
selectionForeground?: string;
|
||||
isBuiltin?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
import { ref, onMounted, onBeforeUnmount, watch } from "vue";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { useTerminal } from "@/composables/useTerminal";
|
||||
import { useSessionStore } from "@/stores/session.store";
|
||||
import "@/assets/css/terminal.css";
|
||||
|
||||
const props = defineProps<{
|
||||
@ -19,13 +20,55 @@ const props = defineProps<{
|
||||
isActive: boolean;
|
||||
}>();
|
||||
|
||||
const sessionStore = useSessionStore();
|
||||
const containerRef = ref<HTMLElement | null>(null);
|
||||
const { terminal, mount, fit, destroy } = useTerminal(props.sessionId, "pty");
|
||||
|
||||
/** Apply the session store's active theme to this local terminal instance. */
|
||||
function applyTheme(): void {
|
||||
const theme = sessionStore.activeTheme;
|
||||
if (!theme) return;
|
||||
terminal.options.theme = {
|
||||
background: theme.background,
|
||||
foreground: theme.foreground,
|
||||
cursor: theme.cursor,
|
||||
cursorAccent: theme.background,
|
||||
selectionBackground: theme.selectionBackground ?? "rgba(88, 166, 255, 0.4)",
|
||||
selectionForeground: theme.selectionForeground ?? "#ffffff",
|
||||
selectionInactiveBackground: theme.selectionBackground ?? "rgba(88, 166, 255, 0.2)",
|
||||
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,
|
||||
};
|
||||
|
||||
if (containerRef.value) {
|
||||
containerRef.value.style.backgroundColor = theme.background;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (containerRef.value) {
|
||||
mount(containerRef.value);
|
||||
}
|
||||
|
||||
// Apply current theme immediately if one is already active
|
||||
if (sessionStore.activeTheme) {
|
||||
applyTheme();
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
fit();
|
||||
terminal.focus();
|
||||
@ -56,6 +99,11 @@ watch(
|
||||
},
|
||||
);
|
||||
|
||||
// Watch for theme changes and apply to this local terminal
|
||||
watch(() => sessionStore.activeTheme, (newTheme) => {
|
||||
if (newTheme) applyTheme();
|
||||
}, { deep: true });
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
destroy();
|
||||
});
|
||||
|
||||
@ -185,6 +185,10 @@ function applyTheme(): void {
|
||||
background: theme.background,
|
||||
foreground: theme.foreground,
|
||||
cursor: theme.cursor,
|
||||
cursorAccent: theme.background,
|
||||
selectionBackground: theme.selectionBackground ?? "rgba(88, 166, 255, 0.4)",
|
||||
selectionForeground: theme.selectionForeground ?? "#ffffff",
|
||||
selectionInactiveBackground: theme.selectionBackground ?? "rgba(88, 166, 255, 0.2)",
|
||||
black: theme.black,
|
||||
red: theme.red,
|
||||
green: theme.green,
|
||||
@ -202,12 +206,19 @@ function applyTheme(): void {
|
||||
brightCyan: theme.brightCyan,
|
||||
brightWhite: theme.brightWhite,
|
||||
};
|
||||
|
||||
// Sync the container background so areas outside the canvas match the theme
|
||||
if (containerRef.value) {
|
||||
containerRef.value.style.backgroundColor = theme.background;
|
||||
}
|
||||
}
|
||||
|
||||
// Watch for theme changes in the session store and apply to this terminal
|
||||
// Watch for theme changes in the session store and apply to this terminal.
|
||||
// Uses deep comparison because the theme is an object — a shallow watch may miss
|
||||
// updates if Pinia returns the same reactive proxy wrapper after reassignment.
|
||||
watch(() => sessionStore.activeTheme, (newTheme) => {
|
||||
if (newTheme) applyTheme();
|
||||
});
|
||||
}, { deep: true });
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (resizeDisposable) {
|
||||
|
||||
@ -14,7 +14,7 @@ const defaultTheme = {
|
||||
foreground: "#e0e0e0",
|
||||
cursor: "#58a6ff",
|
||||
cursorAccent: "#0d1117",
|
||||
selectionBackground: "rgba(88, 166, 255, 0.3)",
|
||||
selectionBackground: "rgba(88, 166, 255, 0.4)",
|
||||
selectionForeground: "#ffffff",
|
||||
black: "#0d1117",
|
||||
red: "#f85149",
|
||||
@ -155,6 +155,7 @@ export function useTerminal(sessionId: string, backend: 'ssh' | 'pty' = 'ssh'):
|
||||
// cell widths — producing tiny dashes and 200+ column terminals.
|
||||
document.fonts.ready.then(() => {
|
||||
fitAddon.fit();
|
||||
terminal.focus();
|
||||
});
|
||||
|
||||
// Right-click paste on the terminal's DOM element
|
||||
|
||||
Loading…
Reference in New Issue
Block a user