mirror of
https://github.com/lone-cloud/gerbil
synced 2026-06-03 19:54:44 -07:00
notepad improvements
This commit is contained in:
parent
3c77be8dbb
commit
42b817949c
11 changed files with 308 additions and 49 deletions
|
|
@ -72,7 +72,7 @@ export const StatusBar = ({ maxDataPoints = 60 }: StatusBarProps) => {
|
|||
bg={colorScheme === 'dark' ? 'dark.6' : 'gray.1'}
|
||||
>
|
||||
<Group gap="xs">
|
||||
<Tooltip label="Notepad">
|
||||
<Tooltip label="Notepad" disabled={isVisible}>
|
||||
<ActionIcon
|
||||
variant={isVisible ? 'filled' : 'subtle'}
|
||||
size="sm"
|
||||
|
|
|
|||
31
src/components/Notepad/CloseConfirmModal.tsx
Normal file
31
src/components/Notepad/CloseConfirmModal.tsx
Normal 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 “{tabTitle}” 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>
|
||||
);
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
import { useEffect, useRef, useState, type MouseEvent } from 'react';
|
||||
import { Box, Paper, ActionIcon } from '@mantine/core';
|
||||
import { X, Plus } from 'lucide-react';
|
||||
import { X } from 'lucide-react';
|
||||
import { useNotepadStore } from '@/stores/notepad';
|
||||
import { usePreferencesStore } from '@/stores/preferences';
|
||||
import { NOTEPAD_MIN_WIDTH, NOTEPAD_MIN_HEIGHT } from '@/constants/notepad';
|
||||
import { NotepadTabs } from './Tabs.tsx';
|
||||
import { NotepadEditor } from './Editor.tsx';
|
||||
import { CloseConfirmModal } from './CloseConfirmModal.tsx';
|
||||
|
||||
export const NotepadContainer = () => {
|
||||
const {
|
||||
|
|
@ -14,6 +15,7 @@ export const NotepadContainer = () => {
|
|||
tabs,
|
||||
activeTabId,
|
||||
addTab,
|
||||
removeTab,
|
||||
isLoaded,
|
||||
isVisible,
|
||||
setVisible,
|
||||
|
|
@ -22,6 +24,15 @@ export const NotepadContainer = () => {
|
|||
|
||||
const containerRef = useRef<HTMLDivElement>(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);
|
||||
|
||||
|
|
@ -30,6 +41,32 @@ export const NotepadContainer = () => {
|
|||
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 =
|
||||
(direction: string) => (e: MouseEvent<HTMLDivElement>) => {
|
||||
e.stopPropagation();
|
||||
|
|
@ -87,11 +124,11 @@ export const NotepadContainer = () => {
|
|||
withBorder
|
||||
style={{
|
||||
position: 'fixed',
|
||||
left: 5,
|
||||
bottom: 5,
|
||||
left: 0,
|
||||
bottom: 24,
|
||||
width: position.width,
|
||||
height: position.height,
|
||||
zIndex: 1000,
|
||||
zIndex: 100,
|
||||
backgroundColor:
|
||||
resolvedColorScheme === 'dark'
|
||||
? 'var(--mantine-color-dark-6)'
|
||||
|
|
@ -132,11 +169,6 @@ export const NotepadContainer = () => {
|
|||
width: 12,
|
||||
height: 12,
|
||||
cursor: 'ne-resize',
|
||||
backgroundColor:
|
||||
resolvedColorScheme === 'dark'
|
||||
? 'var(--mantine-color-dark-5)'
|
||||
: 'var(--mantine-color-gray-4)',
|
||||
borderRadius: '2px',
|
||||
}}
|
||||
onMouseDown={handleResizeStart('top-right')}
|
||||
/>
|
||||
|
|
@ -155,7 +187,10 @@ export const NotepadContainer = () => {
|
|||
minHeight: 28,
|
||||
}}
|
||||
>
|
||||
<NotepadTabs />
|
||||
<NotepadTabs
|
||||
onCreateNewTab={handleCreateNewTab}
|
||||
onCloseTab={handleTabCloseRequest}
|
||||
/>
|
||||
|
||||
<Box
|
||||
style={{
|
||||
|
|
@ -166,10 +201,6 @@ export const NotepadContainer = () => {
|
|||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<ActionIcon variant="subtle" size="xs" onClick={handleCreateNewTab}>
|
||||
<Plus size={12} />
|
||||
</ActionIcon>
|
||||
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
size="xs"
|
||||
|
|
@ -185,6 +216,13 @@ export const NotepadContainer = () => {
|
|||
{activeTab && <NotepadEditor tab={activeTab} />}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<CloseConfirmModal
|
||||
isOpen={confirmCloseModal.isOpen}
|
||||
tabTitle={confirmCloseModal.tabTitle}
|
||||
onConfirm={handleConfirmClose}
|
||||
onCancel={handleCancelClose}
|
||||
/>
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 CodeMirror, { type ReactCodeMirrorRef } from '@uiw/react-codemirror';
|
||||
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 { history, historyKeymap } from '@codemirror/commands';
|
||||
import { useNotepadStore } from '@/stores/notepad';
|
||||
import { usePreferencesStore } from '@/stores/preferences';
|
||||
import type { NotepadTab } from '@/types/electron';
|
||||
|
|
@ -13,7 +20,8 @@ interface NotepadEditorProps {
|
|||
}
|
||||
|
||||
export const NotepadEditor = ({ tab }: NotepadEditorProps) => {
|
||||
const { saveTabContent } = useNotepadStore();
|
||||
const { saveTabContent, showLineNumbers, setShowLineNumbers } =
|
||||
useNotepadStore();
|
||||
const { resolvedColorScheme } = usePreferencesStore();
|
||||
const [content, setContent] = useState(tab.content);
|
||||
const [saveTimeout, setSaveTimeout] = useState<ReturnType<
|
||||
|
|
@ -38,6 +46,14 @@ export const NotepadEditor = ({ tab }: NotepadEditorProps) => {
|
|||
[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(() => {
|
||||
if (editorRef.current?.view) {
|
||||
editorRef.current.view.focus();
|
||||
|
|
@ -59,6 +75,9 @@ export const NotepadEditor = ({ tab }: NotepadEditorProps) => {
|
|||
|
||||
const extensions = [
|
||||
search(),
|
||||
history(),
|
||||
keymap.of(historyKeymap),
|
||||
highlightActiveLine(),
|
||||
EditorView.lineWrapping,
|
||||
EditorView.theme({
|
||||
'&': {
|
||||
|
|
@ -72,12 +91,13 @@ export const NotepadEditor = ({ tab }: NotepadEditorProps) => {
|
|||
return (
|
||||
<Box
|
||||
h="100%"
|
||||
onClick={handleBoxClick}
|
||||
onContextMenu={handleEditorContextMenu}
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
onClick={handleBoxClick}
|
||||
>
|
||||
<CodeMirror
|
||||
ref={editorRef}
|
||||
|
|
@ -86,7 +106,7 @@ export const NotepadEditor = ({ tab }: NotepadEditorProps) => {
|
|||
theme={theme}
|
||||
extensions={extensions}
|
||||
basicSetup={{
|
||||
lineNumbers: true,
|
||||
lineNumbers: showLineNumbers,
|
||||
foldGutter: false,
|
||||
dropCursor: false,
|
||||
allowMultipleSelections: false,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,21 @@
|
|||
import { type MouseEvent, type DragEvent, useState } from 'react';
|
||||
import { Box, ActionIcon, Text } from '@mantine/core';
|
||||
import { X } from 'lucide-react';
|
||||
import {
|
||||
type MouseEvent,
|
||||
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 { usePreferencesStore } from '@/stores/preferences';
|
||||
|
||||
interface NotepadTabsProps {
|
||||
onCreateNewTab: () => Promise<void>;
|
||||
onCloseTab: (tabId: string) => void;
|
||||
}
|
||||
|
||||
interface TabProps {
|
||||
id: string;
|
||||
index: number;
|
||||
|
|
@ -14,7 +26,10 @@ interface TabProps {
|
|||
onDragStart: (e: DragEvent, index: number) => void;
|
||||
onDragOver: (e: DragEvent) => void;
|
||||
onDrop: (e: DragEvent, index: number) => void;
|
||||
onRename: (newTitle: string) => void;
|
||||
isDragOver: boolean;
|
||||
showLineNumbers: boolean;
|
||||
setShowLineNumbers: (show: boolean) => void;
|
||||
}
|
||||
|
||||
const Tab = ({
|
||||
|
|
@ -26,14 +41,77 @@ const Tab = ({
|
|||
onDragStart,
|
||||
onDragOver,
|
||||
onDrop,
|
||||
onRename,
|
||||
isDragOver,
|
||||
showLineNumbers,
|
||||
setShowLineNumbers,
|
||||
}: TabProps) => {
|
||||
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 (
|
||||
<Box
|
||||
draggable
|
||||
onClick={onSelect}
|
||||
draggable={!isEditing}
|
||||
onClick={handleTabClick}
|
||||
onMouseDown={handleMouseDown}
|
||||
onDragStart={(e) => onDragStart(e, index)}
|
||||
onDragOver={onDragOver}
|
||||
onDrop={(e) => onDrop(e, index)}
|
||||
|
|
@ -53,7 +131,7 @@ const Tab = ({
|
|||
? 'var(--mantine-color-dark-4)'
|
||||
: 'var(--mantine-color-gray-3)'
|
||||
}`,
|
||||
cursor: 'pointer',
|
||||
cursor: isEditing ? 'default' : 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '4px',
|
||||
|
|
@ -62,17 +140,49 @@ const Tab = ({
|
|||
opacity: isDragOver ? 0.5 : 1,
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
size="xs"
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
{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
|
||||
size="xs"
|
||||
onClick={handleTitleClick}
|
||||
onDoubleClick={handleTitleDoubleClick}
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setShowLineNumbers(!showLineNumbers);
|
||||
}}
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<ActionIcon variant="subtle" size="xs" onClick={onClose}>
|
||||
<X size={10} />
|
||||
|
|
@ -81,9 +191,19 @@ const Tab = ({
|
|||
);
|
||||
};
|
||||
|
||||
export const NotepadTabs = () => {
|
||||
const { tabs, activeTabId, setActiveTab, removeTab, reorderTabs } =
|
||||
useNotepadStore();
|
||||
export const NotepadTabs = ({
|
||||
onCreateNewTab,
|
||||
onCloseTab,
|
||||
}: NotepadTabsProps) => {
|
||||
const {
|
||||
tabs,
|
||||
activeTabId,
|
||||
setActiveTab,
|
||||
reorderTabs,
|
||||
updateTab,
|
||||
showLineNumbers,
|
||||
setShowLineNumbers,
|
||||
} = useNotepadStore();
|
||||
const { resolvedColorScheme } = usePreferencesStore();
|
||||
const [draggedTabIndex, setDraggedTabIndex] = useState<number | null>(null);
|
||||
const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);
|
||||
|
|
@ -94,7 +214,19 @@ export const NotepadTabs = () => {
|
|||
|
||||
const handleTabClose = (e: MouseEvent, tabId: string) => {
|
||||
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) => {
|
||||
|
|
@ -130,6 +262,7 @@ export const NotepadTabs = () => {
|
|||
|
||||
return (
|
||||
<Box
|
||||
onContextMenu={handleTabBarContextMenu}
|
||||
style={{
|
||||
borderBottom: `1px solid ${
|
||||
resolvedColorScheme === 'dark'
|
||||
|
|
@ -154,13 +287,28 @@ export const NotepadTabs = () => {
|
|||
title={tab.title}
|
||||
onSelect={() => handleTabSelect(tab.id)}
|
||||
onClose={(e) => handleTabClose(e, tab.id)}
|
||||
onRename={(newTitle) => handleTabRename(tab.id, newTitle)}
|
||||
onDragStart={handleDragStart}
|
||||
onDragOver={handleDragOver}
|
||||
onDrop={handleDrop}
|
||||
isDragOver={dragOverIndex === index}
|
||||
showLineNumbers={showLineNumbers}
|
||||
setShowLineNumbers={setShowLineNumbers}
|
||||
/>
|
||||
</Box>
|
||||
))}
|
||||
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
size="xs"
|
||||
onClick={onCreateNewTab}
|
||||
style={{
|
||||
margin: '4px',
|
||||
alignSelf: 'center',
|
||||
}}
|
||||
>
|
||||
<Plus size={12} />
|
||||
</ActionIcon>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
export const DEFAULT_NOTEPAD_POSITION = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 400,
|
||||
height: 400,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ async function downloadFile(asset: GitHubAsset, tempPackedFilePath: string) {
|
|||
if (totalBytes > 0) {
|
||||
const progress = (downloadedBytes / totalBytes) * 100;
|
||||
const now = Date.now();
|
||||
|
||||
if (now - lastProgressUpdate > 100) {
|
||||
mainWindow.webContents.send('download-progress', progress);
|
||||
lastProgressUpdate = now;
|
||||
|
|
|
|||
|
|
@ -117,6 +117,16 @@ const appAPI: AppAPI = {
|
|||
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 = {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ interface NotepadStore extends NotepadState {
|
|||
reorderTabs: (fromIndex: number, toIndex: number) => void;
|
||||
setPosition: (position: NotepadState['position']) => void;
|
||||
setVisible: (visible: boolean) => void;
|
||||
setShowLineNumbers: (showLineNumbers: boolean) => void;
|
||||
loadState: () => Promise<void>;
|
||||
saveState: () => Promise<void>;
|
||||
saveTabContent: (tabId: string, content: string) => Promise<void>;
|
||||
|
|
@ -24,6 +25,7 @@ export const useNotepadStore = create<NotepadStore>()(
|
|||
activeTabId: null,
|
||||
position: DEFAULT_NOTEPAD_POSITION,
|
||||
isVisible: false,
|
||||
showLineNumbers: true,
|
||||
isLoaded: false,
|
||||
|
||||
setTabs: (tabs) => set({ tabs }),
|
||||
|
|
@ -85,6 +87,10 @@ export const useNotepadStore = create<NotepadStore>()(
|
|||
set({ isVisible: visible });
|
||||
},
|
||||
|
||||
setShowLineNumbers: (showLineNumbers) => {
|
||||
set({ showLineNumbers });
|
||||
},
|
||||
|
||||
loadState: async () => {
|
||||
try {
|
||||
const savedState = await window.electronAPI.notepad.loadState();
|
||||
|
|
@ -106,6 +112,7 @@ export const useNotepadStore = create<NotepadStore>()(
|
|||
activeTabId: savedState.activeTabId || tabsWithContent[0]?.id || null,
|
||||
position: savedState.position,
|
||||
isVisible: savedState.isVisible,
|
||||
showLineNumbers: savedState.showLineNumbers ?? true,
|
||||
isLoaded: true,
|
||||
});
|
||||
} catch {
|
||||
|
|
@ -132,6 +139,7 @@ export const useNotepadStore = create<NotepadStore>()(
|
|||
activeTabId: state.activeTabId,
|
||||
position: state.position,
|
||||
isVisible: state.isVisible,
|
||||
showLineNumbers: state.showLineNumbers,
|
||||
});
|
||||
},
|
||||
|
||||
|
|
@ -148,6 +156,7 @@ useNotepadStore.subscribe(
|
|||
activeTabId: state.activeTabId,
|
||||
position: state.position,
|
||||
isVisible: state.isVisible,
|
||||
showLineNumbers: state.showLineNumbers,
|
||||
}),
|
||||
() => {
|
||||
if (useNotepadStore.getState().isLoaded) {
|
||||
|
|
@ -159,7 +168,8 @@ useNotepadStore.subscribe(
|
|||
a.tabs === b.tabs &&
|
||||
a.activeTabId === b.activeTabId &&
|
||||
a.position === b.position &&
|
||||
a.isVisible === b.isVisible,
|
||||
a.isVisible === b.isVisible &&
|
||||
a.showLineNumbers === b.showLineNumbers,
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
|||
9
src/types/electron.d.ts
vendored
9
src/types/electron.d.ts
vendored
|
|
@ -174,6 +174,9 @@ export interface AppAPI {
|
|||
quitAndInstall: () => Promise<void>;
|
||||
isUpdateDownloaded: () => Promise<boolean>;
|
||||
onWindowStateToggle: (callback: () => void) => () => void;
|
||||
onLineNumbersChanged: (
|
||||
callback: (showLineNumbers: boolean) => void
|
||||
) => () => void;
|
||||
}
|
||||
|
||||
export interface ConfigAPI {
|
||||
|
|
@ -221,24 +224,22 @@ export interface NotepadState {
|
|||
tabs: NotepadTab[];
|
||||
activeTabId: string | null;
|
||||
position: {
|
||||
x: number;
|
||||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
isVisible: boolean;
|
||||
showLineNumbers: boolean;
|
||||
}
|
||||
|
||||
export interface SavedNotepadState {
|
||||
tabs: SavedNotepadTab[];
|
||||
activeTabId: string | null;
|
||||
position: {
|
||||
x: number;
|
||||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
isVisible: boolean;
|
||||
showLineNumbers?: boolean;
|
||||
}
|
||||
|
||||
export interface NotepadAPI {
|
||||
|
|
|
|||
4
src/types/ipc.d.ts
vendored
4
src/types/ipc.d.ts
vendored
|
|
@ -4,7 +4,8 @@ export type IPCChannel =
|
|||
| 'versions-updated'
|
||||
| 'kobold-output'
|
||||
| 'window-maximized'
|
||||
| 'window-unmaximized';
|
||||
| 'window-unmaximized'
|
||||
| 'line-numbers-changed';
|
||||
|
||||
export interface IPCChannelPayloads {
|
||||
'download-progress': [progress: number];
|
||||
|
|
@ -13,4 +14,5 @@ export interface IPCChannelPayloads {
|
|||
'kobold-output': [message: string];
|
||||
'window-maximized': [];
|
||||
'window-unmaximized': [];
|
||||
'line-numbers-changed': [showLineNumbers: boolean];
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue