Skip to content

Commit 446ce82

Browse files
Refactor App initialization
1 parent 4286a2f commit 446ce82

File tree

6 files changed

+141
-129
lines changed

6 files changed

+141
-129
lines changed

src/App.tsx

Lines changed: 12 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
1-
import { invoke } from "@tauri-apps/api/core";
2-
import { emit, listen } from "@tauri-apps/api/event";
3-
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
41
import { enableMapSet } from "immer";
52
import { useEffect } from "react";
63
import { useKeymapContext } from "@/features/keymaps/hooks/use-keymap-context";
74
import { useKeymaps } from "@/features/keymaps/hooks/use-keymaps";
5+
import { useRemoteConnection } from "@/features/remote/hooks/use-remote-connection";
6+
import { useRemoteWindowClose } from "@/features/remote/hooks/use-remote-window-close";
87
import { FontStyleInjector } from "@/features/settings/components/font-style-injector";
8+
import { useContextMenuPrevention } from "@/features/window/hooks/use-context-menu-prevention";
9+
import { useFontLoading } from "@/features/window/hooks/use-font-loading";
10+
import { usePlatformSetup } from "@/features/window/hooks/use-platform-setup";
911
import { useScroll } from "@/features/window/hooks/use-scroll";
1012
import { initializeIconThemes } from "./extensions/icon-themes/icon-theme-initializer";
1113
import { initializeThemeSystem } from "./extensions/themes/theme-initializer";
1214
import {
1315
cleanupFileWatcherListener,
1416
initializeFileWatcherListener,
1517
} from "./features/file-system/controllers/file-watcher-store";
16-
import { isMac } from "./features/file-system/controllers/platform";
1718
import { MainLayout } from "./features/layout/components/main-layout";
1819
import { ZoomIndicator } from "./features/layout/components/zoom-indicator";
19-
import { useAppStore } from "./stores/app-store";
20-
import { useFontStore } from "./stores/font-store";
21-
import { useSidebarStore } from "./stores/sidebar-store";
2220
import { useZoomStore } from "./stores/zoom-store";
2321
import { ToastContainer } from "./ui/toast";
2422
import { cn } from "./utils/cn";
@@ -37,150 +35,35 @@ import { initializeExtensionStore } from "./extensions/registry/extension-store"
3735
import { initializeWasmTokenizer } from "./features/editor/lib/wasm-parser";
3836
import { initializeKeymaps } from "./features/keymaps/init";
3937

40-
// Initialize WASM tokenizer (required for parser infrastructure)
4138
initializeWasmTokenizer().catch(console.error);
42-
4339
extensionLoader.initialize().catch(console.error);
44-
45-
// Initialize extension store (load available and installed extensions)
4640
initializeExtensionStore().catch(console.error);
47-
48-
// Initialize keymaps system
4941
initializeKeymaps();
5042

5143
function App() {
5244
enableMapSet();
5345

54-
const { cleanup } = useAppStore.use.actions();
55-
const { loadAvailableFonts } = useFontStore.use.actions();
56-
const setRemoteWindow = useSidebarStore.use.setRemoteWindow();
5746
const zoomLevel = useZoomStore.use.windowZoomLevel();
5847

59-
// Platform-specific setup
60-
useEffect(() => {
61-
if (isMac()) {
62-
document.documentElement.classList.add("platform-macos");
63-
} else {
64-
document.documentElement.classList.add("platform-other");
65-
}
66-
67-
return () => {
68-
document.documentElement.classList.remove("platform-macos", "platform-other");
69-
cleanup(); // Cleanup autosave timeouts
70-
};
71-
}, [cleanup]);
72-
73-
// Initialize fonts on app start (will use cache if available)
74-
useEffect(() => {
75-
loadAvailableFonts();
76-
}, [loadAvailableFonts]);
77-
78-
// Mouse wheel zoom functionality
48+
// App initialization and setup hooks
49+
usePlatformSetup();
50+
useFontLoading();
7951
useScroll();
80-
81-
// Extension installation prompts
8252
useExtensionInstallPrompt();
83-
84-
// Track keymap contexts (editor focus, vim mode, etc.)
8553
useKeymapContext();
86-
87-
// Unified keyboard handler
8854
useKeymaps();
55+
useRemoteConnection();
56+
useRemoteWindowClose();
57+
useContextMenuPrevention();
8958

90-
// Initialize file watcher
59+
// File watcher setup
9160
useEffect(() => {
9261
initializeFileWatcherListener();
9362
return () => {
9463
cleanupFileWatcherListener();
9564
};
9665
}, []);
9766

98-
// Listen for remote connection info and handle remote window setup
99-
useEffect(() => {
100-
// Check if this is a remote window from URL parameter
101-
const urlParams = new URLSearchParams(window.location.search);
102-
const remoteParam = urlParams.get("remote");
103-
if (remoteParam) {
104-
setRemoteWindow(true, undefined, remoteParam);
105-
}
106-
107-
// Set up event listener for remote connection info from Tauri
108-
let unlistenRemoteInfo: (() => void) | null = null;
109-
110-
const setupRemoteListener = async () => {
111-
try {
112-
unlistenRemoteInfo = await listen<{
113-
connectionId: string;
114-
connectionName: string;
115-
isRemoteWindow: boolean;
116-
}>("remote-connection-info", (event) => {
117-
const { isRemoteWindow, connectionName, connectionId } = event.payload;
118-
setRemoteWindow(isRemoteWindow, connectionName, connectionId);
119-
});
120-
} catch (error) {
121-
console.error("Failed to set up remote connection listener:", error);
122-
}
123-
};
124-
125-
setupRemoteListener();
126-
127-
return () => {
128-
if (unlistenRemoteInfo) {
129-
unlistenRemoteInfo();
130-
}
131-
};
132-
}, [setRemoteWindow]);
133-
134-
// Handle window close request for remote connections
135-
useEffect(() => {
136-
const urlParams = new URLSearchParams(window.location.search);
137-
const remoteParam = urlParams.get("remote");
138-
139-
if (!remoteParam) return;
140-
141-
let unlistenCloseRequested: (() => void) | null = null;
142-
143-
const setupCloseListener = async () => {
144-
try {
145-
const currentWindow = getCurrentWebviewWindow();
146-
147-
unlistenCloseRequested = await currentWindow.onCloseRequested(async (event) => {
148-
event.preventDefault();
149-
150-
try {
151-
await invoke("ssh_disconnect_only", { connectionId: remoteParam });
152-
await emit("remote-connection-disconnected", { connectionId: remoteParam });
153-
await currentWindow.destroy();
154-
} catch (error) {
155-
console.error("Failed to cleanup on window close:", error);
156-
await currentWindow.destroy();
157-
}
158-
});
159-
} catch (error) {
160-
console.error("Failed to set up window close listener:", error);
161-
}
162-
};
163-
164-
setupCloseListener();
165-
166-
return () => {
167-
unlistenCloseRequested?.();
168-
};
169-
}, []);
170-
171-
// Hide native context menu
172-
useEffect(() => {
173-
if (import.meta.env.MODE === "production") {
174-
const handleContextMenu = (event: MouseEvent) => {
175-
event.preventDefault();
176-
};
177-
document.addEventListener("contextmenu", handleContextMenu);
178-
return () => {
179-
document.removeEventListener("contextmenu", handleContextMenu);
180-
};
181-
}
182-
}, []);
183-
18467
return (
18568
<div
18669
className={cn("h-screen w-screen overflow-hidden bg-transparent")}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { listen } from "@tauri-apps/api/event";
2+
import { useEffect } from "react";
3+
import { useSidebarStore } from "@/stores/sidebar-store";
4+
5+
export function useRemoteConnection() {
6+
const setRemoteWindow = useSidebarStore.use.setRemoteWindow();
7+
8+
useEffect(() => {
9+
const urlParams = new URLSearchParams(window.location.search);
10+
const remoteParam = urlParams.get("remote");
11+
if (remoteParam) {
12+
setRemoteWindow(true, undefined, remoteParam);
13+
}
14+
15+
let unlistenRemoteInfo: (() => void) | null = null;
16+
17+
const setupRemoteListener = async () => {
18+
try {
19+
unlistenRemoteInfo = await listen<{
20+
connectionId: string;
21+
connectionName: string;
22+
isRemoteWindow: boolean;
23+
}>("remote-connection-info", (event) => {
24+
const { isRemoteWindow, connectionName, connectionId } = event.payload;
25+
setRemoteWindow(isRemoteWindow, connectionName, connectionId);
26+
});
27+
} catch (error) {
28+
console.error("Failed to set up remote connection listener:", error);
29+
}
30+
};
31+
32+
setupRemoteListener();
33+
34+
return () => {
35+
if (unlistenRemoteInfo) {
36+
unlistenRemoteInfo();
37+
}
38+
};
39+
}, [setRemoteWindow]);
40+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { invoke } from "@tauri-apps/api/core";
2+
import { emit } from "@tauri-apps/api/event";
3+
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
4+
import { useEffect } from "react";
5+
6+
export function useRemoteWindowClose() {
7+
useEffect(() => {
8+
const urlParams = new URLSearchParams(window.location.search);
9+
const remoteParam = urlParams.get("remote");
10+
11+
if (!remoteParam) return;
12+
13+
let unlistenCloseRequested: (() => void) | null = null;
14+
15+
const setupCloseListener = async () => {
16+
try {
17+
const currentWindow = getCurrentWebviewWindow();
18+
19+
unlistenCloseRequested = await currentWindow.onCloseRequested(async (event) => {
20+
event.preventDefault();
21+
22+
try {
23+
await invoke("ssh_disconnect_only", { connectionId: remoteParam });
24+
await emit("remote-connection-disconnected", { connectionId: remoteParam });
25+
await currentWindow.destroy();
26+
} catch (error) {
27+
console.error("Failed to cleanup on window close:", error);
28+
await currentWindow.destroy();
29+
}
30+
});
31+
} catch (error) {
32+
console.error("Failed to set up window close listener:", error);
33+
}
34+
};
35+
36+
setupCloseListener();
37+
38+
return () => {
39+
unlistenCloseRequested?.();
40+
};
41+
}, []);
42+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { useEffect } from "react";
2+
3+
export function useContextMenuPrevention() {
4+
useEffect(() => {
5+
if (import.meta.env.MODE === "production") {
6+
const handleContextMenu = (event: MouseEvent) => {
7+
event.preventDefault();
8+
};
9+
10+
document.addEventListener("contextmenu", handleContextMenu);
11+
12+
return () => {
13+
document.removeEventListener("contextmenu", handleContextMenu);
14+
};
15+
}
16+
}, []);
17+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { useEffect } from "react";
2+
import { useFontStore } from "@/stores/font-store";
3+
4+
export function useFontLoading() {
5+
const { loadAvailableFonts } = useFontStore.use.actions();
6+
7+
useEffect(() => {
8+
loadAvailableFonts();
9+
}, [loadAvailableFonts]);
10+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { useEffect } from "react";
2+
import { isMac } from "@/features/file-system/controllers/platform";
3+
import { useAppStore } from "@/stores/app-store";
4+
5+
export function usePlatformSetup() {
6+
const { cleanup } = useAppStore.use.actions();
7+
8+
useEffect(() => {
9+
if (isMac()) {
10+
document.documentElement.classList.add("platform-macos");
11+
} else {
12+
document.documentElement.classList.add("platform-other");
13+
}
14+
15+
return () => {
16+
document.documentElement.classList.remove("platform-macos", "platform-other");
17+
cleanup();
18+
};
19+
}, [cleanup]);
20+
}

0 commit comments

Comments
 (0)