feat(electrobun): settings overhaul — fonts, shells, providers, retention, chords

- Settings drawer: responsive width clamp(24rem, 45vw, 50rem)
- System font detection: fc-list for UI fonts (preferred sans-serif starred)
  and mono fonts (Nerd Fonts starred), fallback to hardcoded lists
- Scrollback: default 5000, min 1000, step 500
- Shell detection: system.shells RPC, pre-selects $SHELL login shell
- Provider enablement: provider.scan gates toggle, unavailable shown as N/A
- Session retention: count 0-100 (0=Keep all), age 0-365 (0=Forever)
- Chord keybindings: Ctrl+K → Ctrl+S style multi-key sequences,
  1s prefix wait, arrow separator display, 26 tests passing
This commit is contained in:
Hibryda 2026-03-25 01:42:34 +01:00
parent afaa2253de
commit 1de6c93e01
9 changed files with 346 additions and 187 deletions

View file

@ -202,10 +202,53 @@ describe('conflict detection', () => {
describe('capture mode', () => {
it('chordFromEvent records full chord for capture', () => {
// Simulate user pressing Ctrl+Shift+X in capture mode
const chord = chordFromEvent({
ctrlKey: true, metaKey: false, shiftKey: true, altKey: false, key: 'x',
});
expect(chord).toBe('Ctrl+Shift+X');
});
});
// ── Chord sequence helpers ──────────────────────────────────────────────────
function chordParts(chord: string): string[] {
return chord.split(' ').filter(Boolean);
}
function formatChord(chord: string): string {
return chordParts(chord).join(' \u2192 ');
}
describe('chord sequences', () => {
it('chordParts splits single chord', () => {
expect(chordParts('Ctrl+K')).toEqual(['Ctrl+K']);
});
it('chordParts splits multi-key chord', () => {
expect(chordParts('Ctrl+K Ctrl+S')).toEqual(['Ctrl+K', 'Ctrl+S']);
});
it('formatChord adds arrow separator', () => {
expect(formatChord('Ctrl+K Ctrl+S')).toBe('Ctrl+K \u2192 Ctrl+S');
});
it('formatChord passes through single chord', () => {
expect(formatChord('Ctrl+Shift+F')).toBe('Ctrl+Shift+F');
});
it('setChord stores chord sequence', () => {
const state = createKeybindingState();
state.setChord('palette', 'Ctrl+K Ctrl+P');
const b = state.getBindings().find(b => b.id === 'palette');
expect(b?.chord).toBe('Ctrl+K Ctrl+P');
});
it('conflict detection works with chord sequences', () => {
const state = createKeybindingState();
state.setChord('palette', 'Ctrl+K Ctrl+P');
state.setChord('settings', 'Ctrl+K Ctrl+P');
const conflicts = state.findConflicts('Ctrl+K Ctrl+P', 'palette');
expect(conflicts).toHaveLength(1);
expect(conflicts[0].id).toBe('settings');
});
});