Files
margin/src/App.tsx
T
2026-08-24 09:17:26 +05:30

113 lines
3.7 KiB
TypeScript

import { useEffect } from "react";
import { listen } from "@tauri-apps/api/event";
import { openUrl } from "@tauri-apps/plugin-opener";
import { getCurrentWindow } from "@tauri-apps/api/window";
import { Library } from "./components/Library";
import { EditorView } from "./components/EditorView";
import { BackupSettings } from "./components/BackupSettings";
import { ExportPreview } from "./components/ExportPreview";
import { UpdateDialog } from "./components/UpdateDialog";
import { useBook } from "./store/useBook";
import { useBackup } from "./store/useBackup";
import { useExportPreview } from "./store/useExportPreview";
import { isDesktop } from "./ipc";
import { createAndOpenBook, lastBookId, loadBook, saveBook } from "./library";
import { runExport } from "./export/run";
import { checkForUpdates } from "./updater";
function App() {
const book = useBook((s) => s.book);
const openBook = useBook((s) => s.openBook);
useEffect(() => {
if (!isDesktop) return;
checkForUpdates(true);
const unlisten = listen<string>("menu-action", (event) => {
const state = useBook.getState();
if (event.payload === "new-book") createAndOpenBook(state.openBook, state.setNotice);
else if (event.payload === "export-pdf") {
if (useBook.getState().book) useExportPreview.getState().openPreview();
}
else if (event.payload === "export-epub") runExport("epub");
else if (event.payload === "check-updates") checkForUpdates(false);
else if (event.payload === "report-issue")
openUrl("https://github.com/priyanshujain/margin/issues").catch(() => {});
});
const unlistenWarn = listen<string>("pdf-warnings", (event) => {
useBook.getState().setNotice(`PDF exported with warnings:\n${event.payload}`);
});
return () => {
unlisten.then((stop) => stop());
unlistenWarn.then((stop) => stop());
};
}, []);
useEffect(() => {
if (!isDesktop) return;
const win = getCurrentWindow();
const unlisten = win.onCloseRequested(async (event) => {
const { book, dirty } = useBook.getState();
const { connected } = useBackup.getState();
if ((!book || !dirty) && !connected) return;
event.preventDefault();
if (book && dirty) await saveBook(book).catch(() => {});
if (connected) useBackup.getState().backup(true);
win.destroy();
});
return () => {
unlisten.then((stop) => stop());
};
}, []);
useEffect(() => {
if (!isDesktop) return;
const unlisten = listen<{ ok: boolean; error: string | null }>("gdrive-auth", (event) => {
useBackup.getState().handleAuthEvent(event.payload.ok, event.payload.error);
});
return () => {
unlisten.then((stop) => stop());
};
}, []);
useEffect(() => {
if (!isDesktop) return;
let first = true;
const tick = async () => {
await useBackup.getState().refresh();
const state = useBackup.getState();
if (!state.connected || state.needsReauth) return;
if (first) {
first = false;
state.sync(true);
} else if (state.pending) {
state.backup(true);
}
};
tick();
const id = setInterval(tick, 15 * 60 * 1000);
return () => clearInterval(id);
}, []);
useEffect(() => {
if (!isDesktop) return;
const id = lastBookId();
if (!id || useBook.getState().book) return;
loadBook(id)
.then((last) => {
if (!useBook.getState().book) useBook.getState().openBook(last);
})
.catch(() => {});
}, []);
return (
<>
{book ? <EditorView /> : <Library onOpen={openBook} />}
{isDesktop && <BackupSettings />}
{isDesktop && <ExportPreview />}
{isDesktop && <UpdateDialog />}
</>
);
}
export default App;