docs/internal/theme-usability-improvements.md
Analysis based on Nielsen Norman Group best practices and hands-on testing.
Both manual theme creation (Flow 3) and the interactive Theme Editor (Flow 2) were tested and verified to work. Several usability issues were identified during testing.
Severity: Critical
Observed: Title shows {name} and status shows Updated {path} instead of actual values
Impact: Users can't see what theme they're editing or where it's saved
Fix: Ensure editor.t() properly interpolates {name}, {path}, {theme}, {error} placeholders
Location: plugins/theme_editor.ts - calls to editor.t()
Severity: High
Observed: When navigating, there's no highlight showing which field is currently selected
Impact: Users can't tell which field will be edited when pressing Enter
Fix: Add background highlight or cursor indicator on the active field row
Location: plugins/theme_editor.ts:739 - applyHighlighting()
Severity: Medium Observed: Color changes only visible after saving and applying theme Impact: Users must save/apply to see results, slowing iteration Fix: Add real-time preview panel or apply changes temporarily while editing
Severity: Medium Observed: Theme list only shows names, not what they look like Impact: Users must try each theme to see it Fix: Add color swatches or mini-preview next to each theme name in selector
Severity: Critical
Observed: themes/ directory has nord.json, dracula.json, solarized-dark.json but they don't appear in theme selector
Impact: Users can't use these popular themes; creates confusion about what's available
Fix: Scan both themes/ directory and user themes directory in available_themes()
Location: src/view/theme.rs:1057-1085
// Current: only scans user themes
// Fix: also scan themes/ directory in the project
Severity: Low Observed: Hardcoded themes use hyphens (high-contrast), but underscore/hyphen normalization exists Impact: Potential confusion about valid theme names Fix: Document naming convention; auto-normalize on save
Severity: Low Observed: New themes start with name "custom" which is generic Impact: Users might accidentally overwrite or create poorly named themes Fix: Generate unique default names like "custom-1", "custom-2" or prompt for name first
Severity: High
Observed: Pressing 'q' immediately discards changes with only a status message
Impact: Accidental data loss
Fix: Show confirmation dialog: "Discard unsaved changes? [y/n]"
Location: plugins/theme_editor.ts:1237 - theme_editor_close()
Severity: Medium Observed: After editing a color, there's no way to revert to previous value Impact: Users must remember original values or restart Fix: Add undo command (Ctrl+Z) or "Reset field" option
Severity: High
Observed: Theme Editor always starts with default/empty theme, not current theme
Impact: To modify an existing theme, users must copy it first
Fix: Add option to "Edit Current Theme" or select theme to edit when opening
Location: plugins/theme_editor.ts:1184 - open_theme_editor()
Severity: Medium Observed: No command to remove custom themes Impact: Users must manually delete files Fix: Add "Delete Theme" command with confirmation
Severity: High Observed: Arrow keys move line-by-line including comment/description lines, but Enter only works on field lines Impact: Confusing - navigation and selection behave differently Fix Options:
Severity: Medium Observed: Uses both single-key shortcuts (c, n, s) and standard shortcuts (Enter, Tab) Impact: Learning curve; conflicts with text editing mental models Fix: Consider using Ctrl+key combinations for actions (Ctrl+S for save) to match editor conventions
Severity: Low
Observed: Hints shown in: status bar, footer panel, and ? command
Impact: Information scattered, may miss features
Fix: Consolidate help; make ? the primary help with comprehensive info
Severity: Medium Observed: Can save themes with invalid/incomplete data Impact: Broken theme files Fix: Validate all required fields before saving; highlight missing/invalid fields
Severity: Medium Observed: Saving with same name as existing theme overwrites without warning Impact: Accidental overwrite of themes Fix: Warn when name matches existing theme; offer "Overwrite" or "Rename"
Severity: Low Observed: Users can set any colors, including low-contrast combinations Impact: May create unusable/inaccessible themes Fix: Add contrast ratio indicator; warn for WCAG violations (< 4.5:1)
Severity: Medium Observed: Must navigate to each field to see what it affects Impact: Hard to find the right field to modify Fix: Keep descriptions always visible, or add "search fields" functionality
Severity: Medium Observed: Field names like "popup_border_fg" require understanding the UI Impact: Users must guess which field affects which part of the UI Fix: Add interactive mode: click on UI element to jump to its color field
Severity: Low Observed: Users must know color names or use hex values Impact: Discovery of available named colors is difficult Fix: Show named color palette picker, not just text suggestions
Severity: Low Observed: Must use command palette to access Impact: Slower access for frequent users Fix: Add configurable keybinding in default keymap
Severity: Low Observed: Must edit colors one at a time Impact: Tedious for comprehensive theme changes Fix: Add "Apply to all similar" (e.g., all backgrounds) or "Adjust brightness/saturation"
Severity: Low Observed: Only native JSON format supported Impact: Can't import from other editors or share in other formats Fix: Support importing from VS Code themes, base16, etc.
Severity: Low Observed: Copy dialog shows theme names but no preview Impact: Hard to choose base theme Fix: Show preview of each builtin theme when copying
Severity: Low Observed: Each field has comment line + field line + blank line = 3 lines per field Impact: Low information density; excessive scrolling Fix: Option to show compact view (field: value on single line, tooltip for description)
Severity: Low Observed: Sections reset to default expansion on reopen Impact: Users must re-collapse sections they don't need each time Fix: Remember expansion state in config
Severity: Medium
Observed: "Invalid color format" without showing what was entered
Impact: Hard to understand what went wrong
Fix: Show specific error: "Invalid color '#GGG': hex values must be 0-9 or A-F"
Location: plugins/theme_editor.ts:860 - parseColorInput()
Severity: Medium Observed: If theme JSON is malformed, unclear what happens Impact: Users may lose work Fix: Show specific JSON parse error with line number; offer to open in editor
Severity: Low Observed: Users must discover features through trial and error Impact: Steep learning curve Fix: Add first-run tooltip tour or "Getting Started" popup
Severity: Low Observed: Users creating manual JSON must examine existing files Impact: Barrier to advanced customization Fix: Add "Export as documented template" or link to docs from editor
? help is text-onlySeverity: Low Observed: Help shows keyboard shortcuts but no explanations Impact: Users know keys but not capabilities Fix: Show richer help panel with examples and descriptions
| Priority | Issue | Impact | Effort |
|---|---|---|---|
| P0 - Critical | 1.1 Localization placeholders | High | Low |
| P0 - Critical | 2.1 Built-in JSON themes missing | High | Low |
| P1 - High | 1.2 No visual field selection | High | Medium |
| P1 - High | 3.1 No discard confirmation | High | Low |
| P1 - High | 3.3 Can't edit existing themes | High | Medium |
| P1 - High | 4.1 Inconsistent navigation | Medium | Medium |
| P2 - Medium | 1.3 No live preview | Medium | High |
| P2 - Medium | 3.2 No undo | Medium | Medium |
| P2 - Medium | 5.2 Theme name collision | Medium | Low |
| P2 - Medium | 6.2 No visual mapping | Medium | High |
| P2 - Medium | 9.1 Generic error messages | Medium | Low |
| P3 - Low | 3.4 Delete themes | Medium | Low |
| P3 - Low | 5.3 Accessibility guidance | Low | Medium |
| P3 - Low | 7.2 Batch operations | Low | High |
| P3 - Low | 8.1 Compact view | Low | Medium |
These improvements provide significant usability gains with minimal development effort:
{name}themes/ directory in available_themes()// In src/view/theme.rs, modify available_themes()
pub fn available_themes() -> Vec<String> {
let mut themes: Vec<String> = vec![
"dark".to_string(),
"light".to_string(),
"high-contrast".to_string(),
"nostalgia".to_string(),
];
// ADD: Scan built-in themes directory
if let Ok(entries) = std::fs::read_dir("themes") {
for entry in entries.flatten() {
let path = entry.path();
if path.extension().is_some_and(|ext| ext == "json") {
if let Some(stem) = path.file_stem() {
let name = stem.to_string_lossy().to_string();
if !themes.iter().any(|t| t == &name) {
themes.push(name);
}
}
}
}
}
// Existing: Scan user themes directory
// ...
}
// In plugins/theme_editor.ts, modify theme_editor_close()
globalThis.theme_editor_close = function(): void {
if (!state.isOpen) return;
if (state.hasChanges) {
// Show confirmation prompt instead of immediate close
editor.startPrompt("Discard unsaved changes? (y/n)", "theme-discard-confirm");
return;
}
doClose();
};
// In applyHighlighting(), add highlight for current field
const currentField = getFieldAtCursor();
if (currentField) {
// Add background highlight to the current field's line
const fieldEntry = entries.find(e => e.properties?.path === currentField.path);
if (fieldEntry) {
addColorOverlay(bufferId, fieldByteOffset, fieldByteOffset + fieldLen,
[60, 60, 80], // Subtle highlight color
false // not bold
);
}
}