Skip to content

Commit 1f61304

Browse files
committed
fix bugs, use context to manage mode, add mode button
1 parent b9c4c16 commit 1f61304

17 files changed

Lines changed: 314 additions & 165 deletions

File tree

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"description": "An Electron application with React and TypeScript",
55
"main": "./out/main/index.js",
66
"author": "example.com",
7-
"type": "module",
87
"homepage": "https://electron-vite.org",
98
"scripts": {
109
"format": "prettier --write .",

src/main/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ function setupIPC(): void {
1818
}
1919
});
2020

21+
ipcMain.on("get-current-mode", (event) => {
22+
event.returnValue = windowManager.getCurrentMode();
23+
});
24+
25+
ipcMain.on("pre-mode-changed", (_event, newMode) => {
26+
if (newMode === 'window' || newMode === 'pet') {
27+
menuManager.setMode(newMode);
28+
}
29+
});
30+
2131
ipcMain.on("window-minimize", () => {
2232
windowManager.getWindow()?.minimize();
2333
});

src/main/window-manager.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export class WindowManager {
6767
: join(__dirname, '../../resources/icon.png'),
6868
...(isMac ? { titleBarStyle: 'hiddenInset' } : {}),
6969
webPreferences: {
70-
preload: join(__dirname, '../preload/index.mjs'),
70+
preload: join(__dirname, '../preload/index.js'),
7171
sandbox: false,
7272
contextIsolation: true,
7373
nodeIntegration: true,
@@ -320,4 +320,9 @@ export class WindowManager {
320320
isForceIgnoreMouse(): boolean {
321321
return this.forceIgnoreMouse;
322322
}
323+
324+
// Get current mode
325+
getCurrentMode(): 'window' | 'pet' {
326+
return this.currentMode;
327+
}
323328
}

src/preload/index.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ declare global {
1515
onToggleInputSubtitle: (callback: () => void) => void
1616
onToggleScrollToResize: (callback: () => void) => void
1717
onSwitchCharacter: (callback: (filename: string) => void) => void
18+
setMode: (mode: 'window' | 'pet') => void
19+
getConfigFiles: () => Promise<any>
20+
updateConfigFiles: (files: any[]) => void
1821
}
1922
}
2023
}

src/preload/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { ConfigFile } from '../main/menu-manager';
77
declare global {
88
interface Window {
99
electron: typeof electronAPI;
10+
// @ts-ignore
1011
api: typeof api;
1112
}
1213
}
@@ -58,6 +59,9 @@ const api = {
5859
ipcRenderer.on('switch-character', handler);
5960
return () => ipcRenderer.removeListener('switch-character', handler);
6061
},
62+
setMode: (mode: 'window' | 'pet') => {
63+
ipcRenderer.send('pre-mode-changed', mode);
64+
},
6165
getConfigFiles: () => ipcRenderer.invoke('get-config-files'),
6266
updateConfigFiles: (files: ConfigFile[]) => {
6367
ipcRenderer.send('update-config-files', files);
@@ -89,5 +93,5 @@ if (process.contextIsolated) {
8993
}
9094
} else {
9195
window.electron = electronAPI;
92-
window.api = api;
96+
(window as any).api = api;
9397
}

src/renderer/src/App.tsx

Lines changed: 111 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -28,58 +28,15 @@ import "@chatscope/chat-ui-kit-styles/dist/default/styles.min.css";
2828
import Background from "./components/canvas/background";
2929
import WebSocketStatus from "./components/canvas/ws-status";
3030
import Subtitle from "./components/canvas/subtitle";
31+
import { ModeProvider, useMode } from "./context/mode-context";
3132

32-
function App(): JSX.Element {
33+
function AppContent(): JSX.Element {
3334
const [showSidebar, setShowSidebar] = useState(true);
3435
const [isFooterCollapsed, setIsFooterCollapsed] = useState(false);
35-
const [mode, setMode] = useState("window");
36+
const { mode } = useMode();
3637
const isElectron = window.api !== undefined;
3738
const live2dContainerRef = useRef<HTMLDivElement>(null);
3839

39-
useEffect(() => {
40-
if (isElectron && window.electron) {
41-
// Added check for window.electron
42-
const handlePreModeChange = (_event: any, newMode: any) => {
43-
// Added types
44-
requestAnimationFrame(() => {
45-
requestAnimationFrame(() => {
46-
window.electron?.ipcRenderer.send(
47-
"renderer-ready-for-mode-change",
48-
newMode
49-
);
50-
});
51-
});
52-
};
53-
const handleModeChanged = (_event: any, newMode: any) => {
54-
// Added types
55-
setMode(newMode);
56-
requestAnimationFrame(() => {
57-
requestAnimationFrame(() => {
58-
window.electron?.ipcRenderer.send("mode-change-rendered");
59-
});
60-
});
61-
};
62-
63-
window.electron.ipcRenderer.on("pre-mode-changed", handlePreModeChange);
64-
window.electron.ipcRenderer.on("mode-changed", handleModeChanged);
65-
66-
return () => {
67-
// Check again before removing listeners
68-
if (window.electron) {
69-
window.electron.ipcRenderer.removeListener(
70-
"pre-mode-changed",
71-
handlePreModeChange
72-
);
73-
window.electron.ipcRenderer.removeListener(
74-
"mode-changed",
75-
handleModeChanged
76-
);
77-
}
78-
};
79-
}
80-
return undefined;
81-
}, [isElectron]);
82-
8340
useEffect(() => {
8441
const handleResize = () => {
8542
const vh = window.innerHeight * 0.01;
@@ -90,34 +47,129 @@ function App(): JSX.Element {
9047
return () => window.removeEventListener("resize", handleResize);
9148
}, []);
9249

50+
51+
document.documentElement.style.overflow = 'hidden';
52+
document.body.style.overflow = 'hidden';
53+
document.documentElement.style.height = '100%';
54+
document.body.style.height = '100%';
55+
document.documentElement.style.position = 'fixed';
56+
document.body.style.position = 'fixed';
57+
document.documentElement.style.width = '100%';
58+
document.body.style.width = '100%';
59+
60+
// Define base style properties shared across modes/breakpoints
9361
const live2dBaseStyle = {
9462
position: "absolute" as const,
9563
overflow: "hidden",
9664
transition: "all 0.3s ease-in-out", // Optional transition
65+
pointerEvents: "auto" as const,
9766
};
9867

99-
const live2dWindowStyle = {
68+
// Define styles specifically for the "window" mode, using responsive syntax
69+
const getResponsiveLive2DWindowStyle = (sidebarVisible: boolean) => ({
10070
...live2dBaseStyle,
10171
top: isElectron ? "30px" : "0px",
102-
left: showSidebar ? "440px" : "24px",
103-
width: `calc(100% - ${showSidebar ? "440px" : "24px"})`,
10472
height: `calc(100% - ${isElectron ? "30px" : "0px"})`,
105-
zIndex: 5,
106-
pointerEvents: "auto" as const,
107-
};
73+
zIndex: 5, // Ensure it's layered correctly below UI but above background
74+
left: {
75+
base: "0px", // Column layout (base): Start from left edge
76+
md: sidebarVisible ? "440px" : "24px", // Row layout (md+): Offset by sidebar width
77+
},
78+
width: {
79+
base: "100%", // Column layout (base): Full width
80+
md: `calc(100% - ${sidebarVisible ? "440px" : "24px"})`, // Row layout (md+): Adjust width based on sidebar
81+
},
82+
});
10883

84+
// Define styles specifically for the "pet" mode
10985
const live2dPetStyle = {
11086
...live2dBaseStyle,
111-
top: 0,
87+
top: 0, // Override position for pet mode
11288
left: 0,
113-
width: "100vw",
89+
width: "100vw", // Full viewport
11490
height: "100vh",
115-
zIndex: 15,
116-
pointerEvents: "auto" as const,
91+
zIndex: 15, // Higher zIndex for pet mode overlay
11792
};
11893

94+
return (
95+
<>
96+
<Box
97+
ref={live2dContainerRef}
98+
// Apply styles conditionally based on mode
99+
// Use the function to get dynamic responsive styles for window mode
100+
{...(mode === "window"
101+
? getResponsiveLive2DWindowStyle(showSidebar)
102+
: live2dPetStyle)}
103+
>
104+
<Live2D />
105+
</Box>
106+
107+
{/* Conditional Rendering of Window UI */}
108+
{mode === "window" && (
109+
<>
110+
{isElectron && <TitleBar />}
111+
{/* Apply styles by spreading */}
112+
<Flex {...layoutStyles.appContainer}>
113+
<Box
114+
{...layoutStyles.sidebar}
115+
{...(!showSidebar && { width: "24px" })}
116+
>
117+
<Sidebar
118+
isCollapsed={!showSidebar}
119+
onToggle={() => setShowSidebar(!showSidebar)}
120+
/>
121+
</Box>
122+
<Box {...layoutStyles.mainContent}>
123+
<Background />
124+
<Box position="absolute" top="20px" left="20px" zIndex={10}>
125+
<WebSocketStatus />
126+
</Box>
127+
<Box
128+
position="absolute"
129+
bottom={isFooterCollapsed ? "39px" : "135px"}
130+
left="50%"
131+
transform="translateX(-50%)"
132+
zIndex={10}
133+
width="60%"
134+
>
135+
<Subtitle />
136+
</Box>
137+
<Box
138+
{...layoutStyles.footer}
139+
zIndex={10}
140+
{...(isFooterCollapsed && layoutStyles.collapsedFooter)}
141+
>
142+
<Footer
143+
isCollapsed={isFooterCollapsed}
144+
onToggle={() => setIsFooterCollapsed(!isFooterCollapsed)}
145+
/>
146+
</Box>
147+
</Box>
148+
</Flex>
149+
</>
150+
)}
151+
152+
{/* Conditional Rendering of Pet Mode UI */}
153+
{mode === "pet" && <InputSubtitle />}
154+
</>
155+
);
156+
}
157+
158+
function App(): JSX.Element {
119159
return (
120160
<ChakraProvider value={defaultSystem}>
161+
{/* ModeProvider needs to wrap AppContent to provide mode to getGlobalStyles */}
162+
<ModeProvider>
163+
<AppWithGlobalStyles />
164+
</ModeProvider>
165+
</ChakraProvider>
166+
);
167+
}
168+
169+
// New component to access mode for global styles
170+
function AppWithGlobalStyles(): JSX.Element {
171+
return (
172+
<>
121173
<CameraProvider>
122174
<ScreenCaptureProvider>
123175
<CharacterConfigProvider>
@@ -132,83 +184,7 @@ function App(): JSX.Element {
132184
<BrowserProvider>
133185
<WebSocketHandler>
134186
<Toaster />
135-
136-
{/* Render Live2D Persistently with correct style props */}
137-
<Box
138-
ref={live2dContainerRef}
139-
{...(mode === "window"
140-
? live2dWindowStyle
141-
: live2dPetStyle)}
142-
>
143-
<Live2D
144-
isPet={mode === "pet"}
145-
showSidebar={showSidebar}
146-
/>
147-
</Box>
148-
149-
{/* Conditional Rendering of Window UI */}
150-
{mode === "window" && (
151-
<>
152-
{isElectron && <TitleBar />}
153-
{/* Apply styles by spreading */}
154-
<Flex {...layoutStyles.appContainer}>
155-
<Box
156-
{...layoutStyles.sidebar}
157-
{...(!showSidebar && { width: "24px" })}
158-
>
159-
<Sidebar
160-
isCollapsed={!showSidebar}
161-
onToggle={() =>
162-
setShowSidebar(!showSidebar)
163-
}
164-
/>
165-
</Box>
166-
<Box {...layoutStyles.mainContent}>
167-
<Background />
168-
<Box
169-
position="absolute"
170-
top="20px"
171-
left="20px"
172-
zIndex={10}
173-
>
174-
<WebSocketStatus />
175-
</Box>
176-
<Box
177-
position="absolute"
178-
bottom={
179-
isFooterCollapsed ? "39px" : "135px"
180-
}
181-
left="50%"
182-
transform="translateX(-50%)"
183-
zIndex={10}
184-
width="60%"
185-
>
186-
<Subtitle />
187-
</Box>
188-
<Box
189-
{...layoutStyles.footer}
190-
zIndex={10}
191-
{...(isFooterCollapsed &&
192-
layoutStyles.collapsedFooter)}
193-
>
194-
<Footer
195-
isCollapsed={isFooterCollapsed}
196-
onToggle={() =>
197-
setIsFooterCollapsed(
198-
!isFooterCollapsed
199-
)
200-
}
201-
/>
202-
</Box>
203-
</Box>
204-
</Flex>
205-
</>
206-
)}
207-
208-
{/* Conditional Rendering of Pet Mode UI */}
209-
{mode === "pet" && (
210-
<InputSubtitle isPet={mode === "pet"} />
211-
)}
187+
<AppContent />
212188
</WebSocketHandler>
213189
</BrowserProvider>
214190
</GroupProvider>
@@ -222,8 +198,8 @@ function App(): JSX.Element {
222198
</CharacterConfigProvider>
223199
</ScreenCaptureProvider>
224200
</CameraProvider>
225-
x{" "}
226-
</ChakraProvider>
201+
</>
227202
);
228203
}
204+
229205
export default App;

0 commit comments

Comments
 (0)