notepad improvements

This commit is contained in:
Egor 2025-09-23 13:09:20 -07:00
parent 3c77be8dbb
commit 42b817949c
11 changed files with 308 additions and 49 deletions

View file

@ -72,7 +72,7 @@ export const StatusBar = ({ maxDataPoints = 60 }: StatusBarProps) => {
bg={colorScheme === 'dark' ? 'dark.6' : 'gray.1'} bg={colorScheme === 'dark' ? 'dark.6' : 'gray.1'}
> >
<Group gap="xs"> <Group gap="xs">
<Tooltip label="Notepad"> <Tooltip label="Notepad" disabled={isVisible}>
<ActionIcon <ActionIcon
variant={isVisible ? 'filled' : 'subtle'} variant={isVisible ? 'filled' : 'subtle'}
size="sm" size="sm"

View file

@ -0,0 +1,31 @@
import { Text, Button, Group } from '@mantine/core';
import { Modal } from '@/components/Modal';
interface CloseConfirmModalProps {
isOpen: boolean;
tabTitle: string;
onConfirm: () => void;
onCancel: () => void;
}
export const CloseConfirmModal = ({
isOpen,
tabTitle,
onConfirm,
onCancel,
}: CloseConfirmModalProps) => (
<Modal opened={isOpen} onClose={onCancel} title="Confirm Close Tab" size="sm">
<Text size="sm" mb="md">
The tab &ldquo;{tabTitle}&rdquo; contains content. Closing it will
permanently delete this data. Are you sure you want to close it?
</Text>
<Group justify="flex-end">
<Button variant="subtle" onClick={onCancel}>
Cancel
</Button>
<Button color="red" onClick={onConfirm}>
Close Tab
</Button>
</Group>
</Modal>
);

View file

@ -1,11 +1,12 @@
import { useEffect, useRef, useState, type MouseEvent } from 'react'; import { useEffect, useRef, useState, type MouseEvent } from 'react';
import { Box, Paper, ActionIcon } from '@mantine/core'; import { Box, Paper, ActionIcon } from '@mantine/core';
import { X, Plus } from 'lucide-react'; import { X } from 'lucide-react';
import { useNotepadStore } from '@/stores/notepad'; import { useNotepadStore } from '@/stores/notepad';
import { usePreferencesStore } from '@/stores/preferences'; import { usePreferencesStore } from '@/stores/preferences';
import { NOTEPAD_MIN_WIDTH, NOTEPAD_MIN_HEIGHT } from '@/constants/notepad'; import { NOTEPAD_MIN_WIDTH, NOTEPAD_MIN_HEIGHT } from '@/constants/notepad';
import { NotepadTabs } from './Tabs.tsx'; import { NotepadTabs } from './Tabs.tsx';
import { NotepadEditor } from './Editor.tsx'; import { NotepadEditor } from './Editor.tsx';
import { CloseConfirmModal } from './CloseConfirmModal.tsx';
export const NotepadContainer = () => { export const NotepadContainer = () => {
const { const {
@ -14,6 +15,7 @@ export const NotepadContainer = () => {
tabs, tabs,
activeTabId, activeTabId,
addTab, addTab,
removeTab,
isLoaded, isLoaded,
isVisible, isVisible,
setVisible, setVisible,
@ -22,6 +24,15 @@ export const NotepadContainer = () => {
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const [resizeDirection, setResizeDirection] = useState<string | null>(null); const [resizeDirection, setResizeDirection] = useState<string | null>(null);
const [confirmCloseModal, setConfirmCloseModal] = useState<{
isOpen: boolean;
tabId: string | null;
tabTitle: string;
}>({
isOpen: false,
tabId: null,
tabTitle: '',
});
const activeTab = tabs.find((tab) => tab.id === activeTabId); const activeTab = tabs.find((tab) => tab.id === activeTabId);
@ -30,6 +41,32 @@ export const NotepadContainer = () => {
addTab(newTab); addTab(newTab);
}; };
const handleTabCloseRequest = (tabId: string) => {
const tab = tabs.find((t) => t.id === tabId);
if (!tab) return;
if (tab.content.trim().length > 0) {
setConfirmCloseModal({
isOpen: true,
tabId,
tabTitle: tab.title,
});
} else {
removeTab(tabId);
}
};
const handleConfirmClose = () => {
if (confirmCloseModal.tabId) {
removeTab(confirmCloseModal.tabId);
}
setConfirmCloseModal({ isOpen: false, tabId: null, tabTitle: '' });
};
const handleCancelClose = () => {
setConfirmCloseModal({ isOpen: false, tabId: null, tabTitle: '' });
};
const handleResizeStart = const handleResizeStart =
(direction: string) => (e: MouseEvent<HTMLDivElement>) => { (direction: string) => (e: MouseEvent<HTMLDivElement>) => {
e.stopPropagation(); e.stopPropagation();
@ -87,11 +124,11 @@ export const NotepadContainer = () => {
withBorder withBorder
style={{ style={{
position: 'fixed', position: 'fixed',
left: 5, left: 0,
bottom: 5, bottom: 24,
width: position.width, width: position.width,
height: position.height, height: position.height,
zIndex: 1000, zIndex: 100,
backgroundColor: backgroundColor:
resolvedColorScheme === 'dark' resolvedColorScheme === 'dark'
? 'var(--mantine-color-dark-6)' ? 'var(--mantine-color-dark-6)'
@ -132,11 +169,6 @@ export const NotepadContainer = () => {
width: 12, width: 12,
height: 12, height: 12,
cursor: 'ne-resize', cursor: 'ne-resize',
backgroundColor:
resolvedColorScheme === 'dark'
? 'var(--mantine-color-dark-5)'
: 'var(--mantine-color-gray-4)',
borderRadius: '2px',
}} }}
onMouseDown={handleResizeStart('top-right')} onMouseDown={handleResizeStart('top-right')}
/> />
@ -155,7 +187,10 @@ export const NotepadContainer = () => {
minHeight: 28, minHeight: 28,
}} }}
> >
<NotepadTabs /> <NotepadTabs
onCreateNewTab={handleCreateNewTab}
onCloseTab={handleTabCloseRequest}
/>
<Box <Box
style={{ style={{
@ -166,10 +201,6 @@ export const NotepadContainer = () => {
flexShrink: 0, flexShrink: 0,
}} }}
> >
<ActionIcon variant="subtle" size="xs" onClick={handleCreateNewTab}>
<Plus size={12} />
</ActionIcon>
<ActionIcon <ActionIcon
variant="subtle" variant="subtle"
size="xs" size="xs"
@ -185,6 +216,13 @@ export const NotepadContainer = () => {
{activeTab && <NotepadEditor tab={activeTab} />} {activeTab && <NotepadEditor tab={activeTab} />}
</Box> </Box>
</Box> </Box>
<CloseConfirmModal
isOpen={confirmCloseModal.isOpen}
tabTitle={confirmCloseModal.tabTitle}
onConfirm={handleConfirmClose}
onCancel={handleCancelClose}
/>
</Paper> </Paper>
); );
}; };

View file

@ -1,9 +1,16 @@
import { useCallback, useEffect, useState, useRef } from 'react'; import {
useCallback,
useEffect,
useState,
useRef,
type MouseEvent,
} from 'react';
import { Box } from '@mantine/core'; import { Box } from '@mantine/core';
import CodeMirror, { type ReactCodeMirrorRef } from '@uiw/react-codemirror'; import CodeMirror, { type ReactCodeMirrorRef } from '@uiw/react-codemirror';
import { search } from '@codemirror/search'; import { search } from '@codemirror/search';
import { EditorView } from '@codemirror/view'; import { EditorView, highlightActiveLine, keymap } from '@codemirror/view';
import { oneDark } from '@codemirror/theme-one-dark'; import { oneDark } from '@codemirror/theme-one-dark';
import { history, historyKeymap } from '@codemirror/commands';
import { useNotepadStore } from '@/stores/notepad'; import { useNotepadStore } from '@/stores/notepad';
import { usePreferencesStore } from '@/stores/preferences'; import { usePreferencesStore } from '@/stores/preferences';
import type { NotepadTab } from '@/types/electron'; import type { NotepadTab } from '@/types/electron';
@ -13,7 +20,8 @@ interface NotepadEditorProps {
} }
export const NotepadEditor = ({ tab }: NotepadEditorProps) => { export const NotepadEditor = ({ tab }: NotepadEditorProps) => {
const { saveTabContent } = useNotepadStore(); const { saveTabContent, showLineNumbers, setShowLineNumbers } =
useNotepadStore();
const { resolvedColorScheme } = usePreferencesStore(); const { resolvedColorScheme } = usePreferencesStore();
const [content, setContent] = useState(tab.content); const [content, setContent] = useState(tab.content);
const [saveTimeout, setSaveTimeout] = useState<ReturnType< const [saveTimeout, setSaveTimeout] = useState<ReturnType<
@ -38,6 +46,14 @@ export const NotepadEditor = ({ tab }: NotepadEditorProps) => {
[tab.id, saveTabContent, saveTimeout] [tab.id, saveTabContent, saveTimeout]
); );
const handleEditorContextMenu = (e: MouseEvent) => {
const target = e.target as HTMLElement;
if (target.closest('.cm-gutters') || target.closest('.cm-lineNumbers')) {
e.preventDefault();
setShowLineNumbers(false);
}
};
const handleBoxClick = useCallback(() => { const handleBoxClick = useCallback(() => {
if (editorRef.current?.view) { if (editorRef.current?.view) {
editorRef.current.view.focus(); editorRef.current.view.focus();
@ -59,6 +75,9 @@ export const NotepadEditor = ({ tab }: NotepadEditorProps) => {
const extensions = [ const extensions = [
search(), search(),
history(),
keymap.of(historyKeymap),
highlightActiveLine(),
EditorView.lineWrapping, EditorView.lineWrapping,
EditorView.theme({ EditorView.theme({
'&': { '&': {
@ -72,12 +91,13 @@ export const NotepadEditor = ({ tab }: NotepadEditorProps) => {
return ( return (
<Box <Box
h="100%" h="100%"
onClick={handleBoxClick}
onContextMenu={handleEditorContextMenu}
style={{ style={{
overflow: 'hidden', overflow: 'hidden',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
}} }}
onClick={handleBoxClick}
> >
<CodeMirror <CodeMirror
ref={editorRef} ref={editorRef}
@ -86,7 +106,7 @@ export const NotepadEditor = ({ tab }: NotepadEditorProps) => {
theme={theme} theme={theme}
extensions={extensions} extensions={extensions}
basicSetup={{ basicSetup={{
lineNumbers: true, lineNumbers: showLineNumbers,
foldGutter: false, foldGutter: false,
dropCursor: false, dropCursor: false,
allowMultipleSelections: false, allowMultipleSelections: false,

View file

@ -1,9 +1,21 @@
import { type MouseEvent, type DragEvent, useState } from 'react'; import {
import { Box, ActionIcon, Text } from '@mantine/core'; type MouseEvent,
import { X } from 'lucide-react'; type DragEvent,
type KeyboardEvent,
useState,
useRef,
useEffect,
} from 'react';
import { Box, ActionIcon, Text, TextInput } from '@mantine/core';
import { X, Plus } from 'lucide-react';
import { useNotepadStore } from '@/stores/notepad'; import { useNotepadStore } from '@/stores/notepad';
import { usePreferencesStore } from '@/stores/preferences'; import { usePreferencesStore } from '@/stores/preferences';
interface NotepadTabsProps {
onCreateNewTab: () => Promise<void>;
onCloseTab: (tabId: string) => void;
}
interface TabProps { interface TabProps {
id: string; id: string;
index: number; index: number;
@ -14,7 +26,10 @@ interface TabProps {
onDragStart: (e: DragEvent, index: number) => void; onDragStart: (e: DragEvent, index: number) => void;
onDragOver: (e: DragEvent) => void; onDragOver: (e: DragEvent) => void;
onDrop: (e: DragEvent, index: number) => void; onDrop: (e: DragEvent, index: number) => void;
onRename: (newTitle: string) => void;
isDragOver: boolean; isDragOver: boolean;
showLineNumbers: boolean;
setShowLineNumbers: (show: boolean) => void;
} }
const Tab = ({ const Tab = ({
@ -26,14 +41,77 @@ const Tab = ({
onDragStart, onDragStart,
onDragOver, onDragOver,
onDrop, onDrop,
onRename,
isDragOver, isDragOver,
showLineNumbers,
setShowLineNumbers,
}: TabProps) => { }: TabProps) => {
const { resolvedColorScheme } = usePreferencesStore(); const { resolvedColorScheme } = usePreferencesStore();
const [isEditing, setIsEditing] = useState(false);
const [editingTitle, setEditingTitle] = useState(title);
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
if (isEditing && inputRef.current) {
inputRef.current.focus();
inputRef.current.select();
}
}, [isEditing]);
const handleTitleClick = (e: MouseEvent) => {
e.stopPropagation();
if (!isActive) {
onSelect();
}
};
const handleTitleDoubleClick = (e: MouseEvent) => {
e.stopPropagation();
if (isActive) {
setIsEditing(true);
setEditingTitle(title);
}
};
const handleInputKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
handleSaveTitle();
} else if (e.key === 'Escape') {
setIsEditing(false);
setEditingTitle(title);
}
};
const handleInputBlur = () => {
handleSaveTitle();
};
const handleSaveTitle = () => {
const trimmedTitle = editingTitle.trim();
if (trimmedTitle && trimmedTitle !== title) {
onRename(trimmedTitle);
}
setIsEditing(false);
};
const handleTabClick = () => {
if (!isEditing) {
onSelect();
}
};
const handleMouseDown = (e: MouseEvent) => {
if (e.button === 1) {
e.preventDefault();
onClose(e);
}
};
return ( return (
<Box <Box
draggable draggable={!isEditing}
onClick={onSelect} onClick={handleTabClick}
onMouseDown={handleMouseDown}
onDragStart={(e) => onDragStart(e, index)} onDragStart={(e) => onDragStart(e, index)}
onDragOver={onDragOver} onDragOver={onDragOver}
onDrop={(e) => onDrop(e, index)} onDrop={(e) => onDrop(e, index)}
@ -53,7 +131,7 @@ const Tab = ({
? 'var(--mantine-color-dark-4)' ? 'var(--mantine-color-dark-4)'
: 'var(--mantine-color-gray-3)' : 'var(--mantine-color-gray-3)'
}`, }`,
cursor: 'pointer', cursor: isEditing ? 'default' : 'pointer',
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
gap: '4px', gap: '4px',
@ -62,8 +140,39 @@ const Tab = ({
opacity: isDragOver ? 0.5 : 1, opacity: isDragOver ? 0.5 : 1,
}} }}
> >
{isEditing ? (
<TextInput
ref={inputRef}
value={editingTitle}
onChange={(e) => setEditingTitle(e.target.value)}
onKeyDown={handleInputKeyDown}
onBlur={handleInputBlur}
size="xs"
variant="unstyled"
style={{
flex: 1,
minWidth: 0,
}}
styles={{
input: {
fontSize: 'var(--mantine-font-size-xs)',
padding: 0,
minHeight: 'auto',
height: 'auto',
lineHeight: 1,
},
}}
/>
) : (
<Text <Text
size="xs" size="xs"
onClick={handleTitleClick}
onDoubleClick={handleTitleDoubleClick}
onContextMenu={(e) => {
e.preventDefault();
e.stopPropagation();
setShowLineNumbers(!showLineNumbers);
}}
style={{ style={{
overflow: 'hidden', overflow: 'hidden',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
@ -73,6 +182,7 @@ const Tab = ({
> >
{title} {title}
</Text> </Text>
)}
<ActionIcon variant="subtle" size="xs" onClick={onClose}> <ActionIcon variant="subtle" size="xs" onClick={onClose}>
<X size={10} /> <X size={10} />
@ -81,9 +191,19 @@ const Tab = ({
); );
}; };
export const NotepadTabs = () => { export const NotepadTabs = ({
const { tabs, activeTabId, setActiveTab, removeTab, reorderTabs } = onCreateNewTab,
useNotepadStore(); onCloseTab,
}: NotepadTabsProps) => {
const {
tabs,
activeTabId,
setActiveTab,
reorderTabs,
updateTab,
showLineNumbers,
setShowLineNumbers,
} = useNotepadStore();
const { resolvedColorScheme } = usePreferencesStore(); const { resolvedColorScheme } = usePreferencesStore();
const [draggedTabIndex, setDraggedTabIndex] = useState<number | null>(null); const [draggedTabIndex, setDraggedTabIndex] = useState<number | null>(null);
const [dragOverIndex, setDragOverIndex] = useState<number | null>(null); const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);
@ -94,7 +214,19 @@ export const NotepadTabs = () => {
const handleTabClose = (e: MouseEvent, tabId: string) => { const handleTabClose = (e: MouseEvent, tabId: string) => {
e.stopPropagation(); e.stopPropagation();
removeTab(tabId); onCloseTab(tabId);
};
const handleTabRename = (tabId: string, newTitle: string) => {
updateTab(tabId, { title: newTitle });
};
const handleTabBarContextMenu = (e: MouseEvent) => {
e.preventDefault();
if (!showLineNumbers) {
setShowLineNumbers(true);
}
}; };
const handleDragStart = (e: DragEvent, index: number) => { const handleDragStart = (e: DragEvent, index: number) => {
@ -130,6 +262,7 @@ export const NotepadTabs = () => {
return ( return (
<Box <Box
onContextMenu={handleTabBarContextMenu}
style={{ style={{
borderBottom: `1px solid ${ borderBottom: `1px solid ${
resolvedColorScheme === 'dark' resolvedColorScheme === 'dark'
@ -154,13 +287,28 @@ export const NotepadTabs = () => {
title={tab.title} title={tab.title}
onSelect={() => handleTabSelect(tab.id)} onSelect={() => handleTabSelect(tab.id)}
onClose={(e) => handleTabClose(e, tab.id)} onClose={(e) => handleTabClose(e, tab.id)}
onRename={(newTitle) => handleTabRename(tab.id, newTitle)}
onDragStart={handleDragStart} onDragStart={handleDragStart}
onDragOver={handleDragOver} onDragOver={handleDragOver}
onDrop={handleDrop} onDrop={handleDrop}
isDragOver={dragOverIndex === index} isDragOver={dragOverIndex === index}
showLineNumbers={showLineNumbers}
setShowLineNumbers={setShowLineNumbers}
/> />
</Box> </Box>
))} ))}
<ActionIcon
variant="subtle"
size="xs"
onClick={onCreateNewTab}
style={{
margin: '4px',
alignSelf: 'center',
}}
>
<Plus size={12} />
</ActionIcon>
</Box> </Box>
); );
}; };

View file

@ -1,6 +1,4 @@
export const DEFAULT_NOTEPAD_POSITION = { export const DEFAULT_NOTEPAD_POSITION = {
x: 0,
y: 0,
width: 400, width: 400,
height: 400, height: 400,
}; };

View file

@ -89,6 +89,7 @@ async function downloadFile(asset: GitHubAsset, tempPackedFilePath: string) {
if (totalBytes > 0) { if (totalBytes > 0) {
const progress = (downloadedBytes / totalBytes) * 100; const progress = (downloadedBytes / totalBytes) * 100;
const now = Date.now(); const now = Date.now();
if (now - lastProgressUpdate > 100) { if (now - lastProgressUpdate > 100) {
mainWindow.webContents.send('download-progress', progress); mainWindow.webContents.send('download-progress', progress);
lastProgressUpdate = now; lastProgressUpdate = now;

View file

@ -117,6 +117,16 @@ const appAPI: AppAPI = {
ipcRenderer.removeListener('window-unmaximized', handler); ipcRenderer.removeListener('window-unmaximized', handler);
}; };
}, },
onLineNumbersChanged: (callback) => {
const handler = (_: IpcRendererEvent, showLineNumbers: boolean) =>
callback(showLineNumbers);
ipcRenderer.on('line-numbers-changed', handler);
return () => {
ipcRenderer.removeListener('line-numbers-changed', handler);
};
},
}; };
const configAPI: ConfigAPI = { const configAPI: ConfigAPI = {

View file

@ -13,6 +13,7 @@ interface NotepadStore extends NotepadState {
reorderTabs: (fromIndex: number, toIndex: number) => void; reorderTabs: (fromIndex: number, toIndex: number) => void;
setPosition: (position: NotepadState['position']) => void; setPosition: (position: NotepadState['position']) => void;
setVisible: (visible: boolean) => void; setVisible: (visible: boolean) => void;
setShowLineNumbers: (showLineNumbers: boolean) => void;
loadState: () => Promise<void>; loadState: () => Promise<void>;
saveState: () => Promise<void>; saveState: () => Promise<void>;
saveTabContent: (tabId: string, content: string) => Promise<void>; saveTabContent: (tabId: string, content: string) => Promise<void>;
@ -24,6 +25,7 @@ export const useNotepadStore = create<NotepadStore>()(
activeTabId: null, activeTabId: null,
position: DEFAULT_NOTEPAD_POSITION, position: DEFAULT_NOTEPAD_POSITION,
isVisible: false, isVisible: false,
showLineNumbers: true,
isLoaded: false, isLoaded: false,
setTabs: (tabs) => set({ tabs }), setTabs: (tabs) => set({ tabs }),
@ -85,6 +87,10 @@ export const useNotepadStore = create<NotepadStore>()(
set({ isVisible: visible }); set({ isVisible: visible });
}, },
setShowLineNumbers: (showLineNumbers) => {
set({ showLineNumbers });
},
loadState: async () => { loadState: async () => {
try { try {
const savedState = await window.electronAPI.notepad.loadState(); const savedState = await window.electronAPI.notepad.loadState();
@ -106,6 +112,7 @@ export const useNotepadStore = create<NotepadStore>()(
activeTabId: savedState.activeTabId || tabsWithContent[0]?.id || null, activeTabId: savedState.activeTabId || tabsWithContent[0]?.id || null,
position: savedState.position, position: savedState.position,
isVisible: savedState.isVisible, isVisible: savedState.isVisible,
showLineNumbers: savedState.showLineNumbers ?? true,
isLoaded: true, isLoaded: true,
}); });
} catch { } catch {
@ -132,6 +139,7 @@ export const useNotepadStore = create<NotepadStore>()(
activeTabId: state.activeTabId, activeTabId: state.activeTabId,
position: state.position, position: state.position,
isVisible: state.isVisible, isVisible: state.isVisible,
showLineNumbers: state.showLineNumbers,
}); });
}, },
@ -148,6 +156,7 @@ useNotepadStore.subscribe(
activeTabId: state.activeTabId, activeTabId: state.activeTabId,
position: state.position, position: state.position,
isVisible: state.isVisible, isVisible: state.isVisible,
showLineNumbers: state.showLineNumbers,
}), }),
() => { () => {
if (useNotepadStore.getState().isLoaded) { if (useNotepadStore.getState().isLoaded) {
@ -159,7 +168,8 @@ useNotepadStore.subscribe(
a.tabs === b.tabs && a.tabs === b.tabs &&
a.activeTabId === b.activeTabId && a.activeTabId === b.activeTabId &&
a.position === b.position && a.position === b.position &&
a.isVisible === b.isVisible, a.isVisible === b.isVisible &&
a.showLineNumbers === b.showLineNumbers,
} }
); );

View file

@ -174,6 +174,9 @@ export interface AppAPI {
quitAndInstall: () => Promise<void>; quitAndInstall: () => Promise<void>;
isUpdateDownloaded: () => Promise<boolean>; isUpdateDownloaded: () => Promise<boolean>;
onWindowStateToggle: (callback: () => void) => () => void; onWindowStateToggle: (callback: () => void) => () => void;
onLineNumbersChanged: (
callback: (showLineNumbers: boolean) => void
) => () => void;
} }
export interface ConfigAPI { export interface ConfigAPI {
@ -221,24 +224,22 @@ export interface NotepadState {
tabs: NotepadTab[]; tabs: NotepadTab[];
activeTabId: string | null; activeTabId: string | null;
position: { position: {
x: number;
y: number;
width: number; width: number;
height: number; height: number;
}; };
isVisible: boolean; isVisible: boolean;
showLineNumbers: boolean;
} }
export interface SavedNotepadState { export interface SavedNotepadState {
tabs: SavedNotepadTab[]; tabs: SavedNotepadTab[];
activeTabId: string | null; activeTabId: string | null;
position: { position: {
x: number;
y: number;
width: number; width: number;
height: number; height: number;
}; };
isVisible: boolean; isVisible: boolean;
showLineNumbers?: boolean;
} }
export interface NotepadAPI { export interface NotepadAPI {

4
src/types/ipc.d.ts vendored
View file

@ -4,7 +4,8 @@ export type IPCChannel =
| 'versions-updated' | 'versions-updated'
| 'kobold-output' | 'kobold-output'
| 'window-maximized' | 'window-maximized'
| 'window-unmaximized'; | 'window-unmaximized'
| 'line-numbers-changed';
export interface IPCChannelPayloads { export interface IPCChannelPayloads {
'download-progress': [progress: number]; 'download-progress': [progress: number];
@ -13,4 +14,5 @@ export interface IPCChannelPayloads {
'kobold-output': [message: string]; 'kobold-output': [message: string];
'window-maximized': []; 'window-maximized': [];
'window-unmaximized': []; 'window-unmaximized': [];
'line-numbers-changed': [showLineNumbers: boolean];
} }