Files
nexus/frontend/src/css/splitpane.css
T
andy da6320c04b 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
2026-04-16 00:00:00 +01:00

224 lines
5.8 KiB
CSS

/* ==========================================================================
Nexus Terminal — Split Pane Layout
Draggable split panes within session panels for multi-terminal views.
========================================================================== */
/* -----------------------------------------------------------------------
Split container — replaces direct terminal-container when split
----------------------------------------------------------------------- */
.split-container {
display: flex;
width: 100%;
height: 100%;
overflow: hidden;
}
.split-container.split-horizontal {
flex-direction: column;
}
.split-container.split-vertical {
flex-direction: row;
}
/* -----------------------------------------------------------------------
Individual pane inside a split
----------------------------------------------------------------------- */
.split-pane {
position: relative;
overflow: hidden;
min-width: 100px;
min-height: 100px;
display: flex;
flex-direction: column;
}
/* Active pane indicator (subtle border glow) */
.split-pane.is-focused {
box-shadow: inset 0 0 0 1px var(--accent-muted);
}
/* -----------------------------------------------------------------------
Pane close button — only visible on hover
----------------------------------------------------------------------- */
.split-pane-close {
position: absolute;
top: var(--space-1);
right: var(--space-1);
width: 18px;
height: 18px;
display: flex;
align-items: center;
justify-content: center;
border: none;
border-radius: var(--radius-sm);
background: var(--bg-overlay);
color: var(--text-tertiary);
font-size: 11px;
line-height: 1;
cursor: pointer;
opacity: 0;
transition: opacity var(--transition-fast), background var(--transition-fast), color var(--transition-fast);
z-index: 5;
}
.split-pane:hover > .split-pane-close {
opacity: 1;
}
.split-pane-close:hover {
background: var(--error);
color: var(--text-primary);
}
/* -----------------------------------------------------------------------
Draggable divider between panes
----------------------------------------------------------------------- */
.split-divider {
flex-shrink: 0;
background: var(--border-subtle);
position: relative;
z-index: 2;
transition: background var(--transition-fast);
}
.split-divider:hover,
.split-divider.is-dragging {
background: var(--accent);
}
/* Vertical split → side-by-side panes → vertical divider bar */
.split-container.split-vertical > .split-divider {
width: 4px;
cursor: col-resize;
}
/* Horizontal split → stacked panes → horizontal divider bar */
.split-container.split-horizontal > .split-divider {
height: 4px;
cursor: row-resize;
}
/* Invisible larger hit-area for easier grabbing */
.split-divider::after {
content: '';
position: absolute;
}
.split-container.split-vertical > .split-divider::after {
top: 0;
bottom: 0;
left: -4px;
right: -4px;
}
.split-container.split-horizontal > .split-divider::after {
left: 0;
right: 0;
top: -4px;
bottom: -4px;
}
/* -----------------------------------------------------------------------
Empty pane placeholder — shown when a new pane needs a session
----------------------------------------------------------------------- */
.split-pane-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
gap: var(--space-3);
color: var(--text-tertiary);
font-size: var(--text-sm);
background: var(--bg-base);
padding: var(--space-4);
}
.split-pane-placeholder-icon {
opacity: 0.4;
}
.split-pane-placeholder-text {
text-align: center;
max-width: 200px;
line-height: var(--leading-normal);
}
/* Profile picker list in the placeholder */
.split-pane-profile-list {
display: flex;
flex-direction: column;
gap: var(--space-1);
max-height: 200px;
overflow-y: auto;
width: 100%;
max-width: 220px;
margin-top: var(--space-2);
}
.split-pane-profile-list::-webkit-scrollbar {
width: 4px;
}
.split-pane-profile-list::-webkit-scrollbar-track {
background: transparent;
}
.split-pane-profile-list::-webkit-scrollbar-thumb {
background: var(--border-strong);
border-radius: var(--radius-full);
}
.split-pane-profile-btn {
display: flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-1) var(--space-2);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-md);
background: var(--bg-surface);
color: var(--text-secondary);
font-size: var(--text-sm);
cursor: pointer;
transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
text-align: left;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.split-pane-profile-btn:hover {
background: var(--bg-hover);
color: var(--text-primary);
border-color: var(--accent-muted);
}
.split-pane-profile-btn .protocol-badge {
font-size: 9px;
font-weight: var(--weight-semibold);
text-transform: uppercase;
opacity: 0.7;
flex-shrink: 0;
}
/* -----------------------------------------------------------------------
Prevent text selection while dragging dividers
----------------------------------------------------------------------- */
body.split-resizing {
cursor: col-resize !important;
user-select: none !important;
-webkit-user-select: none !important;
}
body.split-resizing-row {
cursor: row-resize !important;
user-select: none !important;
-webkit-user-select: none !important;
}
/* Disable pointer events on iframes / xterm canvases during drag */
body.split-resizing .xterm,
body.split-resizing-row .xterm {
pointer-events: none;
}