Files
goldenChart/desktop/src/picker-main.tsx
T
2026-06-15 17:17:06 +09:00

102 lines
3.0 KiB
TypeScript

import './forceServerApi';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import ReactDOM from 'react-dom/client';
import { emit } from '@tauri-apps/api/event';
import { getCurrentWindow } from '@tauri-apps/api/window';
import { initStorage, refreshApiBaseFromStorage } from '@goldenchart/shared';
import { ensureDesktopApiBase } from './ensureDesktopApiBase';
import { fitPickerWindowToScreen } from './bridge/pickerWindow';
import WidgetPickerModal from '@frontend/components/widgetDashboard/WidgetPickerModal';
import {
WIDGET_PICKER_SELECT_EVENT,
type WidgetPickerSelectPayload,
} from './widgetPickerEvents';
import { readDesktopSync, subscribeDesktopSync } from '@frontend/utils/desktopSync';
import { syncDocumentTheme } from '@frontend/utils/documentTheme';
import type { Theme } from '@frontend/types';
import '@frontend/App.css';
import '@frontend/styles/appPopup.css';
import '@frontend/styles/widgetDashboard.css';
document.documentElement.classList.add('fw-native-picker-window');
function parseParams(): { instanceId: string; slotId: string } {
const params = new URLSearchParams(window.location.search);
return {
instanceId: params.get('instanceId') ?? '',
slotId: params.get('slotId') ?? '',
};
}
const PickerApp: React.FC = () => {
const { instanceId, slotId } = useMemo(() => parseParams(), []);
const sync = readDesktopSync();
const [theme, setTheme] = useState<Theme>((sync?.theme as Theme | undefined) ?? 'dark');
const [ready, setReady] = useState(false);
useEffect(() => {
syncDocumentTheme(theme);
}, [theme]);
useEffect(() => {
return subscribeDesktopSync(state => {
if (state.theme) setTheme(state.theme as Theme);
});
}, []);
useEffect(() => {
void fitPickerWindowToScreen()
.catch(err => console.warn('[picker-main] window fit failed', err))
.finally(() => setReady(true));
}, []);
const handleClose = useCallback(() => {
void getCurrentWindow().close();
}, []);
const handleSelect = useCallback(async (widgetType: string) => {
if (!instanceId || !slotId) {
await getCurrentWindow().close();
return;
}
const payload: WidgetPickerSelectPayload = { instanceId, slotId, widgetType };
await emit(WIDGET_PICKER_SELECT_EVENT, payload);
await getCurrentWindow().close();
}, [instanceId, slotId]);
if (!instanceId || !slotId) {
return <p className="wd-widget-empty">위젯 선택 정보가 없습니다.</p>;
}
if (!ready) {
return (
<div className="wd-picker-native-loading" aria-live="polite">
위젯 목록 준비 중…
</div>
);
}
return (
<WidgetPickerModal
open
category="all"
onClose={handleClose}
onSelect={widgetType => { void handleSelect(widgetType); }}
/>
);
};
async function bootstrap() {
await initStorage();
ensureDesktopApiBase();
refreshApiBaseFromStorage();
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<PickerApp />
</React.StrictMode>,
);
}
void bootstrap();