import "./setup.css"; import { LOCALES, SetupSyncFromServerResponse } from "@triliumnext/commons"; import clsx from "clsx"; import { ComponentChildren, render } from "preact"; import { useEffect, useMemo, useRef, useState } from "preact/hooks"; import { useTranslation } from "react-i18next"; import logo from "./assets/icon-color.svg?url"; import { initLocale, t } from "./services/i18n"; import server from "./services/server"; import { isElectron, replaceHtmlEscapedSlashes } from "./services/utils"; import ActionButton from "./widgets/react/ActionButton"; import Admonition from "./widgets/react/Admonition"; import Button from "./widgets/react/Button"; import { Card, CardFrame, CardSection } from "./widgets/react/Card"; import FormGroup from "./widgets/react/FormGroup"; import { FormListItem } from "./widgets/react/FormList"; import FormTextBox from "./widgets/react/FormTextBox"; import Icon from "./widgets/react/Icon"; async function main() { await initLocale(); const bodyWrapper = document.createElement("div"); bodyWrapper.classList.add("setup-outer-wrapper"); document.body.classList.add("setup", window.glob.device || "desktop"); if (isElectron()) { document.body.classList.add("electron", `platform-${window.process.platform}`, "background-effects"); } render(, bodyWrapper); document.body.replaceChildren(bodyWrapper); } type State = "selectLanguage" | "firstOptions" | "createNewDocumentOptions" | "createNewDocumentWithDemo" | "createNewDocumentEmpty" | "syncFromDesktop" | "syncFromServer" | "syncFromServerInProgress" | "syncFromDesktopInProgress" | "syncFailed"; const STATE_ORDER: State[] = ["selectLanguage", "firstOptions", "createNewDocumentOptions", "createNewDocumentWithDemo", "createNewDocumentEmpty", "syncFromDesktop", "syncFromServer", "syncFromServerInProgress", "syncFromDesktopInProgress", "syncFailed"]; function renderState(state: State, setState: (state: State) => void) { switch (state) { case "selectLanguage": return ; case "firstOptions": return ; case "createNewDocumentOptions": return ; case "createNewDocumentWithDemo": return ; case "createNewDocumentEmpty": return ; case "syncFromServer": return ; case "syncFromDesktop": return ; case "syncFromServerInProgress": return ; case "syncFromDesktopInProgress": return ; default: return null; } } function App() { const [state, setState] = useState("selectLanguage"); const [prevState, setPrevState] = useState(null); const [transitioning, setTransitioning] = useState(false); const prevStateRef = useRef(state); function handleSetState(newState: State) { setPrevState(prevStateRef.current); prevStateRef.current = newState; setTransitioning(true); setState(newState); } const direction = prevState !== null ? STATE_ORDER.indexOf(state) > STATE_ORDER.indexOf(prevState) ? "forward" : "backward" : "forward"; return (
{transitioning && prevState !== null && (
{ setTransitioning(false); setPrevState(null); }} > {renderState(prevState, handleSetState)}
)}
{renderState(state, handleSetState)}
); } function SelectLanguage({ setState }: { setState: (state: State) => void }) { const { t, i18n } = useTranslation(); const [ currentLocale, setCurrentLocale ] = useState(i18n.language); const filteredLocales = useMemo(() => LOCALES.filter(l => !l.contentOnly), []); return ( } footer={
); } function getNetworkAddresses(): string[] { if (!isElectron()) { return [`${location.protocol}//${location.host}`]; } // eslint-disable-next-line @typescript-eslint/no-require-imports const os = require("os") as typeof import("os"); const interfaces = os.networkInterfaces(); const addresses: string[] = []; for (const nets of Object.values(interfaces)) { if (!nets) continue; for (const net of nets) { if (net.internal) continue; if (net.family === "IPv6" && net.scopeid !== 0) continue; addresses.push(net.address); } } // Sort by likelihood of being the local network address. addresses.sort((a, b) => networkScore(a) - networkScore(b)); return addresses.map((addr) => `${location.protocol}//${addr}:${location.port}`); } function networkScore(addr: string): number { if (addr.startsWith("192.168.")) return 0; if (addr.startsWith("10.")) return 1; if (/^172\.(1[6-9]|2\d|3[01])\./.test(addr)) return 2; if (addr.includes(":")) return 4; // IPv6 return 3; } function onSetupFinished() { if (isElectron()) { // On Electron we need to use the setup route because it handles the closing of the setup window and opening the main app window. location.href = "setup"; } else { location.reload(); } } main();