Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 180 additions & 0 deletions SETTINGS_ENHANCEMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
# Settings Enhancement: Keyboard Shortcuts and Appearance Tabs

## Implementation Complete ✅

This document describes the new tabbed settings interface with keyboard shortcuts and appearance customization.

## Features

### 1. Tabbed Settings Interface
Settings are now organized into three tabs:
- **General**: Interpreter paths, external editors, and file paths
- **Appearance**: Theme selection and color customization
- **Keyboard Shortcuts**: Editable keyboard shortcuts with modifier keys

### 2. Appearance Tab
- Theme dropdown with 3 built-in themes:
- Dark (Default)
- Light
- High Contrast
- 9 customizable color properties:
- Background, Foreground, Primary, Secondary, Accent
- Border, Error, Success, Warning
- Color pickers with hex input fields
- **Auto-custom theme creation**: When colors are modified, a new custom theme is automatically created
- Themes stored in `~/.PDV/themes/*.json`

### 3. Keyboard Shortcuts Tab
- List of customizable shortcuts for common actions
- Inline editor with:
- Modifier key checkboxes (Ctrl/Cmd, Shift, Alt)
- Key input field
- Save/Cancel actions
- Reset to defaults button
- Default shortcuts include:
- Execute Code: `Shift + Enter`
- Clear Console: `Ctrl/Cmd + K`
- New Tab: `Ctrl/Cmd + T`
- Close Tab: `Ctrl/Cmd + W`
- Open Settings: `Ctrl/Cmd + ,`
- And more...

## Technical Details

### Backend (Main Process)
- **themes.ts**: New module for theme management
- Initialize default themes
- Load/save themes
- Create custom themes
- Delete custom themes (except defaults)
- **IPC handlers**: Full communication bridge for theme operations
- **Unit tests**: 10 new tests for theme module (all passing)

### Frontend (Renderer Process)
- **Settings/index.tsx**: Updated with tab navigation
- **Settings/tabs/**:
- `GeneralTab.tsx`: Existing settings
- `AppearanceTab.tsx`: Theme and color customization
- `KeyboardShortcutsTab.tsx`: Keyboard shortcut editor
- **Updated styles**: New CSS for tabs and color pickers

### Data Structures

```typescript
interface Settings {
// Existing fields...
theme?: string;
customThemeColors?: ThemeColors;
keyboardShortcuts?: KeyboardShortcut[];
}

interface Theme {
id: string;
name: string;
colors: ThemeColors;
isCustom?: boolean;
}

interface ThemeColors {
background?: string;
foreground?: string;
primary?: string;
secondary?: string;
accent?: string;
border?: string;
error?: string;
success?: string;
warning?: string;
}

interface KeyboardShortcut {
action: string;
key: string;
modifiers?: string[];
}
```

## File System

```
~/.PDV/
├── settings/
│ └── config.json # User settings
└── themes/
├── dark.json # Default dark theme
├── light.json # Default light theme
├── high-contrast.json # Default high contrast theme
└── custom-{timestamp}.json # Auto-created custom themes
```

## Usage

### Customizing Theme
1. Open Settings (Cmd/Ctrl + ,)
2. Click **Appearance** tab
3. Select a base theme from dropdown
4. Modify any color using color pickers or hex inputs
5. System automatically creates a custom theme
6. Click **Save** to persist

### Editing Keyboard Shortcuts
1. Open Settings (Cmd/Ctrl + ,)
2. Click **Keyboard Shortcuts** tab
3. Click **Edit** on any shortcut
4. Check/uncheck modifier keys
5. Enter the key
6. Click **Save** in inline editor
7. Click **Save** in footer to persist

## Testing

All tests pass:
- ✅ 6 test files passing
- ✅ 29 tests passing (2 skipped)
- ✅ Build successful with no errors

New theme tests cover:
- Directory creation
- Default theme initialization
- Theme loading and listing
- Custom theme creation
- Theme deletion (with protection for defaults)

## Future Enhancements

Potential improvements:
- Apply theme colors to actual application UI
- Theme preview in dropdown
- Export/import themes as files
- Keyboard shortcut conflict detection
- Live keyboard shortcut application
- Theme color validation

## Files Modified

### Main Process
- `electron/main/themes.ts` (new)
- `electron/main/themes.test.ts` (new)
- `electron/main/settings.ts` (updated)
- `electron/main/ipc.ts` (updated)
- `electron/main/index.ts` (updated)
- `electron/preload.ts` (updated)

### Renderer Process
- `electron/renderer/src/components/Settings/index.tsx` (updated)
- `electron/renderer/src/components/Settings/styles.css` (updated)
- `electron/renderer/src/components/Settings/tabs/GeneralTab.tsx` (new)
- `electron/renderer/src/components/Settings/tabs/AppearanceTab.tsx` (new)
- `electron/renderer/src/components/Settings/tabs/KeyboardShortcutsTab.tsx` (new)

## Summary

✅ All requirements met:
- Multiple tabs in settings window
- Keyboard shortcuts editing tab with full customization
- GUI appearance tab with theme dropdown
- Color values shown alongside theme dropdown
- Selecting theme populates color values appropriately
- Themes stored in ~/.PDV/themes as JSON
- Modified colors create new custom theme automatically
- Comprehensive unit tests added and passing
10 changes: 10 additions & 0 deletions electron/main/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ if (!canCreateWindow) {
{
label: 'File',
submenu: [
{
label: 'Settings...',
accelerator: 'CommandOrControl+,',
click: (_, window) => {
if (window) {
window.webContents.send('open-settings');
}
}
},
{ type: 'separator' },
{ role: 'quit' }
]
},
Expand Down
103 changes: 103 additions & 0 deletions electron/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,26 @@ import {
ScriptRunResult,
ScriptParameter,
CommandBoxData,
Settings,
Theme,
ThemeColors,
KeyboardShortcut,
} from './ipc';
import { getKernelManager, resetKernelManager } from './kernel-manager';
import { loadConfig, updateConfig } from './config';
import { loadSettings, saveSettings } from './settings';
import {
listThemes,
loadTheme,
saveTheme,
deleteTheme,
createCustomTheme,
} from './themes';
import {
loadShortcuts,
saveShortcuts,
resetShortcuts,
} from './shortcuts';
import { spawn } from 'child_process';
import * as os from 'os';
import { FileScanner } from './file-scanner';
Expand Down Expand Up @@ -697,6 +714,92 @@ if (!canRegisterHandlers) {
}
});

// ============================================================================
// Settings Handlers
// ============================================================================

ipcMain.handle(IPC.settings.get, async (): Promise<Settings> => {
console.log('[IPC] settings:get');
return loadSettings();
});

ipcMain.handle(IPC.settings.set, async (_event, settings: Partial<Settings>): Promise<boolean> => {
console.log('[IPC] settings:set', settings);
try {
const current = loadSettings();
const updated = { ...current, ...settings };
saveSettings(updated);
console.log('[IPC] settings:set - success');
return true;
} catch (error) {
console.error('[IPC] settings:set error:', error);
return false;
}
});

// ============================================================================
// Theme Handlers
// ============================================================================

ipcMain.handle(IPC.themes.list, async (): Promise<Theme[]> => {
console.log('[IPC] themes:list');
return listThemes();
});

ipcMain.handle(IPC.themes.load, async (_event, themeId: string): Promise<Theme | null> => {
console.log('[IPC] themes:load', themeId);
return loadTheme(themeId);
});

ipcMain.handle(IPC.themes.save, async (_event, theme: Theme): Promise<boolean> => {
console.log('[IPC] themes:save', theme.id);
try {
saveTheme(theme);
return true;
} catch (error) {
console.error('[IPC] themes:save error:', error);
return false;
}
});

ipcMain.handle(IPC.themes.delete, async (_event, themeId: string): Promise<boolean> => {
console.log('[IPC] themes:delete', themeId);
return deleteTheme(themeId);
});

ipcMain.handle(
IPC.themes.createCustom,
async (_event, baseTheme: Theme, customColors: ThemeColors): Promise<Theme> => {
console.log('[IPC] themes:createCustom', baseTheme.id);
return createCustomTheme(baseTheme, customColors);
}
);

// ============================================================================
// Shortcuts Handlers
// ============================================================================

ipcMain.handle(IPC.shortcuts.load, async (): Promise<KeyboardShortcut[]> => {
console.log('[IPC] shortcuts:load');
return loadShortcuts();
});

ipcMain.handle(IPC.shortcuts.save, async (_event, shortcuts: KeyboardShortcut[]): Promise<boolean> => {
console.log('[IPC] shortcuts:save');
try {
saveShortcuts(shortcuts);
return true;
} catch (error) {
console.error('[IPC] shortcuts:save error:', error);
return false;
}
});

ipcMain.handle(IPC.shortcuts.reset, async (): Promise<KeyboardShortcut[]> => {
console.log('[IPC] shortcuts:reset');
return resetShortcuts();
});

// ============================================================================

console.log('[main] IPC handlers registered');
Expand Down
Loading
Loading