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:
@@ -134,6 +134,10 @@ class SecretPrompt {
|
||||
`;
|
||||
if (isNew) {
|
||||
formHtml += `
|
||||
<div class="password-strength-meter">
|
||||
<div class="strength-bar"><div class="strength-fill"></div></div>
|
||||
<span class="strength-label"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Confirm password</label>
|
||||
<input type="password" class="form-input master-confirm"
|
||||
@@ -166,6 +170,19 @@ class SecretPrompt {
|
||||
const errorEl = modal.querySelector('.secret-error');
|
||||
passInput.focus();
|
||||
|
||||
// Wire up the password strength meter for new vault creation.
|
||||
if (isNew) {
|
||||
const strengthFill = modal.querySelector('.strength-fill');
|
||||
const strengthLabel = modal.querySelector('.strength-label');
|
||||
passInput.addEventListener('input', () => {
|
||||
const result = _measureStrength(passInput.value);
|
||||
strengthFill.style.width = result.percent + '%';
|
||||
strengthFill.className = 'strength-fill strength-' + result.level;
|
||||
strengthLabel.textContent = result.label;
|
||||
strengthLabel.className = 'strength-label strength-' + result.level;
|
||||
});
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
const pw = passInput.value;
|
||||
if (!pw) {
|
||||
@@ -310,6 +327,42 @@ class SecretPrompt {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimates password strength based on length and character diversity.
|
||||
* Returns an object with { percent, level, label } for the strength meter.
|
||||
* @param {string} pw
|
||||
* @returns {{ percent: number, level: string, label: string }}
|
||||
* @private
|
||||
*/
|
||||
function _measureStrength(pw) {
|
||||
if (!pw) return { percent: 0, level: 'none', label: '' };
|
||||
|
||||
let score = 0;
|
||||
const len = pw.length;
|
||||
|
||||
// Length contribution (0–40 points)
|
||||
score += Math.min(len * 3, 40);
|
||||
|
||||
// Character-class diversity (0–40 points)
|
||||
const hasLower = /[a-z]/.test(pw);
|
||||
const hasUpper = /[A-Z]/.test(pw);
|
||||
const hasDigit = /[0-9]/.test(pw);
|
||||
const hasSymbol = /[^a-zA-Z0-9]/.test(pw);
|
||||
const classes = [hasLower, hasUpper, hasDigit, hasSymbol].filter(Boolean).length;
|
||||
score += classes * 10;
|
||||
|
||||
// Unique-character ratio bonus (0–20 points)
|
||||
const unique = new Set(pw).size;
|
||||
score += Math.min(Math.floor((unique / Math.max(len, 1)) * 20), 20);
|
||||
|
||||
score = Math.min(score, 100);
|
||||
|
||||
if (score < 25) return { percent: score, level: 'weak', label: 'Weak' };
|
||||
if (score < 50) return { percent: score, level: 'fair', label: 'Fair' };
|
||||
if (score < 75) return { percent: score, level: 'good', label: 'Good' };
|
||||
return { percent: score, level: 'strong', label: 'Strong' };
|
||||
}
|
||||
|
||||
window.NexusTerminal = window.NexusTerminal || {};
|
||||
window.NexusTerminal.SecretPrompt = SecretPrompt;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user