Phase 2: Split pane terminals, custom themes, and password strength meter

Split Pane Layout:
- Add SplitPaneManager with recursive tree-based pane splitting
- Support horizontal (Cmd+Shift+E) and vertical (Cmd+Shift+D) splits
- Draggable resize dividers with 100px minimum pane size
- Hover-visible close button to unsplit panes
- Session picker in new panes for connecting separate terminals
- Automatic xterm refit on all pane resize operations

Custom Terminal Themes:
- Add themes.js with 8 preset colour schemes: Charcoal (default),
  Solarized Dark, Monokai, Nord, Dracula, One Dark, Gruvbox Dark,
  Tokyo Night
- Add TerminalTheme preference to AppPreferences model
- Add colour scheme selector to Settings → Terminal tab
- Live-apply theme changes to all active terminals on save
- TerminalManager now uses themed colours instead of hardcoded values

Master Password Strength Meter:
- Add visual strength bar to vault creation dialog
- Entropy estimation based on length, character diversity, uniqueness
- Four levels: Weak (red), Fair (amber), Good (green), Strong (green)
- Animated transitions on strength changes
- Charcoal-themed CSS matching modal design
This commit is contained in:
2026-04-16 00:00:00 +01:00
parent 5a998aefb9
commit da6320c04b
12 changed files with 1257 additions and 28 deletions
+15 -25
View File
@@ -33,8 +33,9 @@ class TerminalManager {
* @returns {Terminal} The xterm.js Terminal instance.
*/
createTerminal(sessionId, containerId, profile) {
const themeName = (this.app.state.preferences || {}).terminalTheme || 'charcoal';
const term = new Terminal({
theme: this._buildTheme(),
theme: window.NexusTerminal.getTerminalTheme(themeName),
fontFamily: profile.terminalFontFamily || 'JetBrains Mono, Menlo, Monaco, Consolas, monospace',
fontSize: profile.terminalFontSize || 14,
scrollback: profile.terminalScrollback || 10000,
@@ -265,6 +266,17 @@ class TerminalManager {
if (entry) entry.term.focus();
}
/**
* Applies a named colour theme to all active terminal instances.
* @param {string} themeName
*/
applyTheme(themeName) {
const themeObj = window.NexusTerminal.getTerminalTheme(themeName);
for (const [, entry] of this.terminals) {
entry.term.options.theme = themeObj;
}
}
// ── Private helpers ──────────────────────────────────────────────
/**
@@ -273,30 +285,8 @@ class TerminalManager {
* @private
*/
_buildTheme() {
return {
background: '#1c1c1c',
foreground: '#e4e4e4',
cursor: '#4ecdc4',
cursorAccent: '#1c1c1c',
selectionBackground: 'rgba(78, 205, 196, 0.3)',
selectionForeground: '#ffffff',
black: '#1c1c1c',
red: '#ef5350',
green: '#66bb6a',
yellow: '#ffa726',
blue: '#42a5f5',
magenta: '#ab47bc',
cyan: '#4ecdc4',
white: '#e4e4e4',
brightBlack: '#555555',
brightRed: '#ff7043',
brightGreen: '#81c784',
brightYellow: '#ffcc02',
brightBlue: '#64b5f6',
brightMagenta: '#ce93d8',
brightCyan: '#80deea',
brightWhite: '#ffffff',
};
const themeName = (this.app.state.preferences || {}).terminalTheme || 'charcoal';
return window.NexusTerminal.getTerminalTheme(themeName);
}
}