import { renameSync, rmSync } from 'fs'; import { ensure, overwrite } from '../utils'; const step = () => { rmSync('src/index.css'); rmSync('src/index.html'); rmSync('src/app.tsx'); rmSync('src/icon.svg'); ensure( 'src/web/settings/index.css', `@import '../../../node_modules/antd/dist/reset.css'; body { padding: 1rem; } `, ); ensure( 'src/web/settings/index.tsx', `import React, { useEffect, useState } from 'react'; import { createRoot } from 'react-dom/client'; import { auto } from 'manate/react'; import { ConfigProvider, Form, Radio, theme } from 'antd'; import { autoRun, manage } from 'manate'; import type { Managed } from 'manate/models'; import { debounce } from 'lodash'; import hyperid from 'hyperid'; import CONSTS from '../../constants'; const uuid = hyperid(); class Store { public appearance: 'auto' | 'dark' | 'light' = 'auto'; public formKey = uuid(); public refreshForm() { this.formKey = uuid(); } } const store = manage(new Store()); const App = auto((props: { store: Store }) => { const { store } = props; const [isDark, setIsDark] = useState(false); useEffect(() => { return global.ipc.on(CONSTS.IS_DARK_MODE, (event, payload) => { document.body.style.backgroundColor = (payload ? theme.darkAlgorithm : theme.defaultAlgorithm)( theme.defaultSeed, ).colorBgContainer; setIsDark(payload); }); }, []); useEffect(() => { const { start, stop } = autoRun( store as Managed, () => { global.ipc.invoke(CONSTS.SAVE_SETTINGS, { appearance: store.appearance }); }, (func: () => void) => debounce(func, 100, { leading: true, trailing: true }), ); const init = async () => { const settings = await global.ipc.invoke(CONSTS.LOAD_SETTINGS); store.appearance = settings.appearance; store.refreshForm(); start(); }; init(); return stop; }, []); return (
{ store.appearance = event.target.value; }} > Light Dark Auto
); }); const container = document.createElement('div'); document.body.appendChild(container); const root = createRoot(container); root.render(); `, ); ensure( 'src/web/settings/settings.html', ` Settings - Untitled App `, ); overwrite( 'src/web/index.html', ` Untitled App `, ); overwrite( 'src/web/index.css', `@import '../../node_modules/antd/dist/reset.css'; body { padding: 1rem; } `, ); overwrite( 'src/web/app.tsx', ` import React, { useEffect, useState } from 'react'; import { Button, ConfigProvider, Space, Typography, theme } from 'antd'; import { auto } from 'manate/react'; import type { Store } from './store'; import CONSTS from '../constants'; const { Text, Title } = Typography; const App = auto((props: { store: Store }) => { const { store } = props; const [isDark, setIsDark] = useState(false); useEffect(() => { const disposer = global.ipc.on(CONSTS.IS_DARK_MODE, (event, isDarkMode) => { document.body.style.backgroundColor = (isDarkMode ? theme.darkAlgorithm : theme.defaultAlgorithm)( theme.defaultSeed, ).colorBgContainer; setIsDark(isDarkMode); }); global.ipc.invoke(CONSTS.IS_DARK_MODE); return disposer; }, []); return ( Untitled App {store.count} ); }); export default App; `, ); ensure( 'src/web/Globals.d.ts', `/* eslint-disable @typescript-eslint/no-explicit-any */ declare namespace ipc { function invoke(channel: string, ...args: any[]): Promise; function on(channel: string, listener: (...args: any[]) => void): () => void; } `, ); renameSync('src/store.ts', 'src/web/store.ts'); renameSync('src/index.tsx', 'src/web/index.tsx'); }; export default step;