experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor(modes): remove settings mode and minor modes (simplify to page/group/default)

+30 -136
+3 -19
backend/electron/datastore.ts
··· 1669 1669 1670 1670 // ==================== Mode Helpers (Context-based replacements for modes.ts) ==================== 1671 1671 1672 - export type MajorModeId = 'page' | 'group' | 'settings' | 'default'; 1673 - export type MinorModeId = 'preview' | 'edit' | 'annotate' | 'search'; 1672 + export type MajorModeId = 'page' | 'group' | 'default'; 1674 1673 1675 1674 /** 1676 1675 * Detect the appropriate major mode based on URL 1677 1676 */ 1678 1677 export function detectModeFromUrl(url: string): MajorModeId { 1679 1678 if (!url) return 'default'; 1680 - 1681 - // Settings page 1682 - if (url.includes('/settings/') || url.includes('settings.html')) { 1683 - return 'settings'; 1684 - } 1685 1679 1686 1680 // Groups extension 1687 1681 if (url.includes('/groups/') || url.includes('groups.html')) { ··· 1724 1718 */ 1725 1719 export function checkModeConditions( 1726 1720 windowId: number, 1727 - requiredMajorMode?: MajorModeId, 1728 - requiredMinorModes?: MinorModeId[] 1721 + requiredMajorMode?: MajorModeId 1729 1722 ): boolean { 1730 1723 const entry = getContextEntry('mode', windowId); 1731 1724 const currentMode = entry?.value as MajorModeId | undefined; 1732 1725 1733 1726 // No mode state = default mode 1734 1727 if (!currentMode) { 1735 - if (requiredMajorMode && requiredMajorMode !== 'default') { 1736 - return false; 1737 - } 1738 - if (requiredMinorModes && requiredMinorModes.length > 0) { 1739 - return false; 1740 - } 1741 - return true; 1728 + return !requiredMajorMode || requiredMajorMode === 'default'; 1742 1729 } 1743 1730 1744 1731 // Check major mode 1745 1732 if (requiredMajorMode && currentMode !== requiredMajorMode) { 1746 1733 return false; 1747 1734 } 1748 - 1749 - // Minor modes not implemented in context API yet - always pass 1750 - // (minor modes were rarely used and can be added later if needed) 1751 1735 1752 1736 return true; 1753 1737 }
+10 -43
backend/electron/ipc.ts
··· 165 165 import { 166 166 detectModeFromUrl, 167 167 type MajorModeId, 168 - type MinorModeId, 169 168 } from './datastore.js'; 170 169 171 170 // ============================================================================ ··· 2451 2450 registerGlobalShortcut(msg.shortcut, msg.source, callback); 2452 2451 } else { 2453 2452 // Build mode conditions if provided 2454 - const modeConditions = (msg.mode || msg.minorModes?.length) 2455 - ? { majorMode: msg.mode, minorModes: msg.minorModes } 2456 - : undefined; 2453 + const modeConditions = msg.mode ? { majorMode: msg.mode } : undefined; 2457 2454 registerLocalShortcut(msg.shortcut, msg.source, callback, modeConditions); 2458 2455 } 2459 2456 }); ··· 2470 2467 } 2471 2468 } else { 2472 2469 // Build mode conditions if provided 2473 - const modeConditions = (msg.mode || msg.minorModes?.length) 2474 - ? { majorMode: msg.mode, minorModes: msg.minorModes } 2475 - : undefined; 2470 + const modeConditions = msg.mode ? { majorMode: msg.mode } : undefined; 2476 2471 unregisterLocalShortcut(msg.shortcut, msg.source, modeConditions); 2477 2472 } 2478 2473 }); ··· 2918 2913 * New code should use the context API (api.context) instead. 2919 2914 */ 2920 2915 export function registerModesHandlers(): void { 2921 - // Mode definitions (hardcoded since modes.ts is removed) 2922 - const MAJOR_MODES = [ 2923 - { id: 'default', name: 'Default', description: 'Standard browsing mode', type: 'major' }, 2924 - { id: 'page', name: 'Page', description: 'Viewing a web page', type: 'major' }, 2925 - { id: 'group', name: 'Group', description: 'Managing tab groups', type: 'major' }, 2926 - { id: 'settings', name: 'Settings', description: 'Application settings', type: 'major' }, 2927 - ]; 2928 - const MINOR_MODES = [ 2929 - { id: 'preview', name: 'Preview', description: 'Preview mode (read-only)', type: 'minor' }, 2930 - { id: 'edit', name: 'Edit', description: 'Edit mode', type: 'minor' }, 2931 - { id: 'annotate', name: 'Annotate', description: 'Annotation mode', type: 'minor' }, 2932 - { id: 'search', name: 'Search', description: 'Search mode active', type: 'minor' }, 2916 + // Mode definitions 2917 + const MODES = [ 2918 + { id: 'default', name: 'Default', description: 'Standard browsing mode' }, 2919 + { id: 'page', name: 'Page', description: 'Viewing a web page' }, 2920 + { id: 'group', name: 'Group', description: 'Managing tab groups' }, 2933 2921 ]; 2934 2922 2935 2923 // Get mode state for a window (uses context API) ··· 2948 2936 2949 2937 const entry = getContextEntry('mode', windowId); 2950 2938 const state = { 2951 - major: (entry?.value as MajorModeId) || 'default', 2952 - minors: [] as MinorModeId[] // Minor modes not implemented in context API 2939 + major: (entry?.value as MajorModeId) || 'default' 2953 2940 }; 2954 2941 return { success: true, data: state }; 2955 2942 } catch (error) { ··· 2980 2967 publish(getSystemAddress(), PubSubScopes.GLOBAL, 'modes:changed', { 2981 2968 windowId, 2982 2969 major: data.mode, 2983 - minors: [], 2984 2970 }); 2985 2971 2986 2972 return { success: true }; ··· 2990 2976 } 2991 2977 }); 2992 2978 2993 - // Minor modes - stub implementations (not used in context API) 2994 - ipcMain.handle('modes:enableMinorMode', async () => { 2995 - return { success: true }; // No-op, minor modes not implemented 2996 - }); 2997 - 2998 - ipcMain.handle('modes:disableMinorMode', async () => { 2999 - return { success: true }; // No-op, minor modes not implemented 3000 - }); 3001 - 3002 - ipcMain.handle('modes:toggleMinorMode', async () => { 3003 - return { success: true, data: false }; // No-op, minor modes not implemented 3004 - }); 3005 - 3006 2979 // List all available modes 3007 2980 ipcMain.handle('modes:listModes', async () => { 3008 - try { 3009 - return { success: true, data: [...MAJOR_MODES, ...MINOR_MODES] }; 3010 - } catch (error) { 3011 - const message = error instanceof Error ? error.message : String(error); 3012 - return { success: false, error: message }; 3013 - } 2981 + return { success: true, data: MODES }; 3014 2982 }); 3015 2983 3016 2984 // Get command context for current state ··· 3033 3001 const context = { 3034 3002 windowId, 3035 3003 mode: { 3036 - major: (entry?.value as MajorModeId) || 'default', 3037 - minors: [] as MinorModeId[] 3004 + major: (entry?.value as MajorModeId) || 'default' 3038 3005 }, 3039 3006 url, 3040 3007 title,
+6 -8
backend/electron/shortcuts.ts
··· 9 9 */ 10 10 11 11 import { DEBUG } from './config.js'; 12 - import { checkModeConditions, type MajorModeId, type MinorModeId } from './datastore.js'; 12 + import { checkModeConditions, type MajorModeId } from './datastore.js'; 13 13 14 14 // Lazy-load Electron modules to allow testing without Electron 15 15 let globalShortcut: typeof import('electron').globalShortcut | null = null; ··· 39 39 40 40 interface ModeConditions { 41 41 majorMode?: MajorModeId; 42 - minorModes?: MinorModeId[]; 43 42 } 44 43 45 44 interface LocalShortcutEntry { ··· 226 225 227 226 // If mode-conditional, add to array (allows same key with different modes) 228 227 // If not mode-conditional, replace any existing non-conditional entry 229 - if (modeConditions?.majorMode || modeConditions?.minorModes?.length) { 228 + if (modeConditions?.majorMode) { 230 229 // Mode-conditional: add to array 231 230 entries.push(entry); 232 231 } else { 233 232 // Non-conditional: find and replace any existing non-conditional entry 234 - const nonConditionalIndex = entries.findIndex(e => !e.modeConditions?.majorMode && !e.modeConditions?.minorModes?.length); 233 + const nonConditionalIndex = entries.findIndex(e => !e.modeConditions?.majorMode); 235 234 if (nonConditionalIndex >= 0) { 236 235 entries[nonConditionalIndex] = entry; 237 236 } else { ··· 266 265 } 267 266 268 267 // No mode conditions - remove non-conditional entries 269 - return entry.modeConditions?.majorMode || entry.modeConditions?.minorModes?.length; 268 + return !!entry.modeConditions?.majorMode; 270 269 }); 271 270 272 271 if (filtered.length > 0) { ··· 291 290 for (const entry of entries) { 292 291 if (inputMatchesShortcut(input, entry.parsed)) { 293 292 // Check mode conditions if specified 294 - if (entry.modeConditions?.majorMode || entry.modeConditions?.minorModes?.length) { 293 + if (entry.modeConditions?.majorMode) { 295 294 // Need a window ID to check mode 296 295 if (focusedWindowId === undefined && BrowserWindow) { 297 296 // Try to get focused window ··· 302 301 if (focusedWindowId !== undefined) { 303 302 const modeMatches = checkModeConditions( 304 303 focusedWindowId, 305 - entry.modeConditions.majorMode, 306 - entry.modeConditions.minorModes 304 + entry.modeConditions.majorMode 307 305 ); 308 306 309 307 if (modeMatches) {
+2 -24
backend/types/api.ts
··· 42 42 * Only one major mode can be active per window at a time. 43 43 * Inspired by Emacs major modes. 44 44 */ 45 - export type MajorModeId = 'page' | 'group' | 'settings' | 'default'; 46 - 47 - /** 48 - * Minor modes are optional features that can be combined. 49 - * Multiple minor modes can be active simultaneously. 50 - * Inspired by Emacs minor modes. 51 - */ 52 - export type MinorModeId = 'preview' | 'edit' | 'annotate' | 'search'; 45 + export type MajorModeId = 'page' | 'group' | 'default'; 53 46 54 47 /** 55 48 * Mode metadata for display and behavior 56 49 */ 57 50 export interface ModeInfo { 58 - id: MajorModeId | MinorModeId; 51 + id: MajorModeId; 59 52 name: string; 60 53 description?: string; 61 - /** Whether this is a major (exclusive) or minor (stackable) mode */ 62 - type: 'major' | 'minor'; 63 54 } 64 55 65 56 /** ··· 68 59 export interface WindowModeState { 69 60 /** Current major mode */ 70 61 major: MajorModeId; 71 - /** Active minor modes */ 72 - minors: MinorModeId[]; 73 62 } 74 63 75 64 /** ··· 98 87 /** Set the major mode for a window */ 99 88 setMajorMode(mode: MajorModeId, windowId?: number | null): Promise<ApiResult<void>>; 100 89 101 - /** Enable a minor mode for a window */ 102 - enableMinorMode(mode: MinorModeId, windowId?: number | null): Promise<ApiResult<void>>; 103 - 104 - /** Disable a minor mode for a window */ 105 - disableMinorMode(mode: MinorModeId, windowId?: number | null): Promise<ApiResult<void>>; 106 - 107 - /** Toggle a minor mode for a window */ 108 - toggleMinorMode(mode: MinorModeId, windowId?: number | null): Promise<ApiResult<boolean>>; 109 - 110 90 /** Get all available modes */ 111 91 listModes(): Promise<ApiResult<ModeInfo[]>>; 112 92 ··· 121 101 global?: boolean; 122 102 /** Only trigger shortcut when in this major mode */ 123 103 mode?: MajorModeId; 124 - /** Only trigger shortcut when these minor modes are active */ 125 - minorModes?: MinorModeId[]; 126 104 } 127 105 128 106 export interface IShortcutsApi {
+9 -42
preload.js
··· 113 113 * @param {function} cb - Callback function when shortcut is triggered 114 114 * @param {object} options - Optional configuration 115 115 * @param {boolean} options.global - If true, shortcut works even when app doesn't have focus (default: false) 116 - * @param {string} options.mode - Only trigger in this major mode ('page', 'group', 'settings', 'default') 117 - * @param {string[]} options.minorModes - Only trigger when these minor modes are active 116 + * @param {string} options.mode - Only trigger in this major mode ('page', 'group', 'default') 118 117 */ 119 118 register: (shortcut, cb, options = {}) => { 120 119 const isGlobal = options.global === true; ··· 128 127 shortcut, 129 128 replyTopic, 130 129 global: isGlobal, 131 - mode: options.mode, 132 - minorModes: options.minorModes 130 + mode: options.mode 133 131 }); 134 132 135 133 ipcRenderer.on(replyTopic, (ev, msg) => { ··· 152 150 source: sourceAddress, 153 151 shortcut, 154 152 global: isGlobal, 155 - mode: options.mode, 156 - minorModes: options.minorModes 153 + mode: options.mode 157 154 }); 158 155 } 159 156 }; ··· 1579 1576 }); 1580 1577 1581 1578 // ==================== Modes API ==================== 1582 - // Context-aware command system with major/minor modes 1579 + // Context-aware command system 1583 1580 api.modes = { 1584 1581 /** 1585 1582 * Get the current mode state for a window 1586 1583 * @param {number|null} windowId - Window ID (null = current/last focused) 1587 - * @returns {Promise<{success: boolean, data?: {major: string, minors: string[]}, error?: string}>} 1584 + * @returns {Promise<{success: boolean, data?: {major: string}, error?: string}>} 1588 1585 */ 1589 1586 getWindowMode: (windowId = null) => { 1590 1587 return ipcRenderer.invoke('modes:getWindowMode', { windowId }); ··· 1592 1589 1593 1590 /** 1594 1591 * Set the major mode for a window 1595 - * @param {string} mode - Major mode ID ('page', 'group', 'settings', 'default') 1592 + * @param {string} mode - Major mode ID ('page', 'group', 'default') 1596 1593 * @param {number|null} windowId - Window ID (null = current/last focused) 1597 1594 * @returns {Promise<{success: boolean, error?: string}>} 1598 1595 */ ··· 1601 1598 }, 1602 1599 1603 1600 /** 1604 - * Enable a minor mode for a window 1605 - * @param {string} mode - Minor mode ID ('preview', 'edit', 'annotate', 'search') 1606 - * @param {number|null} windowId - Window ID (null = current/last focused) 1607 - * @returns {Promise<{success: boolean, error?: string}>} 1608 - */ 1609 - enableMinorMode: (mode, windowId = null) => { 1610 - return ipcRenderer.invoke('modes:enableMinorMode', { mode, windowId }); 1611 - }, 1612 - 1613 - /** 1614 - * Disable a minor mode for a window 1615 - * @param {string} mode - Minor mode ID 1616 - * @param {number|null} windowId - Window ID (null = current/last focused) 1617 - * @returns {Promise<{success: boolean, error?: string}>} 1618 - */ 1619 - disableMinorMode: (mode, windowId = null) => { 1620 - return ipcRenderer.invoke('modes:disableMinorMode', { mode, windowId }); 1621 - }, 1622 - 1623 - /** 1624 - * Toggle a minor mode for a window 1625 - * @param {string} mode - Minor mode ID 1626 - * @param {number|null} windowId - Window ID (null = current/last focused) 1627 - * @returns {Promise<{success: boolean, data?: boolean, error?: string}>} data is true if now enabled 1628 - */ 1629 - toggleMinorMode: (mode, windowId = null) => { 1630 - return ipcRenderer.invoke('modes:toggleMinorMode', { mode, windowId }); 1631 - }, 1632 - 1633 - /** 1634 - * Get all available modes (major and minor) 1635 - * @returns {Promise<{success: boolean, data?: Array<{id: string, name: string, description: string, type: string}>, error?: string}>} 1601 + * Get all available modes 1602 + * @returns {Promise<{success: boolean, data?: Array<{id: string, name: string, description: string}>, error?: string}>} 1636 1603 */ 1637 1604 listModes: () => { 1638 1605 return ipcRenderer.invoke('modes:listModes'); ··· 1653 1620 */ 1654 1621 onModeChange: (callback) => { 1655 1622 api.subscribe('modes:changed', (msg) => { 1656 - callback({ major: msg.major, minors: msg.minors }, msg.windowId); 1623 + callback({ major: msg.major }, msg.windowId); 1657 1624 }, api.scopes.GLOBAL); 1658 1625 } 1659 1626 };