UNPKG

alinea

Version:
140 lines (138 loc) 6.51 kB
import { useAtom, useAtomValue } from "../chunks/chunk-TOJF2G3X.js"; import { atom } from "../chunks/chunk-WJ67RR7S.js"; import "../chunks/chunk-NZLE2WMY.js"; // src/dashboard/App.tsx import { Config } from "alinea/core/Config"; import { Root } from "alinea/core/Root"; import { Icon, Loader, px } from "alinea/ui"; import { FavIcon } from "alinea/ui/branding/FavIcon"; import { IcRoundCheck } from "alinea/ui/icons/IcRoundCheck"; import { IcRoundDescription } from "alinea/ui/icons/IcRoundDescription"; import { IcRoundSync } from "alinea/ui/icons/IcRoundSync"; import { MaterialSymbolsDatabase } from "alinea/ui/icons/MaterialSymbolsDatabase"; import { Statusbar } from "alinea/ui/Statusbar"; import { useEffect } from "react"; import { sessionAtom } from "./atoms/DashboardAtoms.js"; import { dbMetaAtom, pendingAtom, useDbUpdater } from "./atoms/DbAtoms.js"; import { errorAtom } from "./atoms/ErrorAtoms.js"; import { locationAtom, matchAtoms } from "./atoms/LocationAtoms.js"; import { usePreferredLanguage } from "./atoms/NavigationAtoms.js"; import { RouterProvider, RouteView } from "./atoms/RouterAtoms.js"; import { navMatchers } from "./DashboardNav.js"; import { DashboardProvider } from "./DashboardProvider.js"; import { useDashboard } from "./hook/UseDashboard.js"; import { useEntryLocation } from "./hook/UseEntryLocation.js"; import { useLocale } from "./hook/UseLocale.js"; import { useNav } from "./hook/UseNav.js"; import { useRoot } from "./hook/UseRoot.js"; import { useWorkspace } from "./hook/UseWorkspace.js"; import { router } from "./Routes.js"; import { Head } from "./util/Head.js"; import { SuspenseBoundary } from "./util/SuspenseBoundary.js"; import { ErrorBoundary } from "./view/ErrorBoundary.js"; import { Modal } from "./view/Modal.js"; import { Sidebar } from "./view/Sidebar.js"; import { SidebarSettings } from "./view/sidebar/SidebarSettings.js"; import { Toolbar } from "./view/Toolbar.js"; import { Viewport } from "./view/Viewport.js"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; var isEntryAtom = atom((get) => { const location = get(locationAtom); const match = get(matchAtoms({ route: navMatchers.matchEntry })); return Boolean(match) || location.pathname === "/"; }); function AppAuthenticated() { useDbUpdater(); const { alineaDev, fullPage } = useDashboard(); const nav = useNav(); const isEntry = useAtomValue(isEntryAtom); const { name: workspace, color, roots } = useWorkspace(); const { name: currentRoot } = useRoot(); const entryLocation = useEntryLocation(); const locale = useLocale(); const [preferredLanguage, setPreferredLanguage] = usePreferredLanguage(); const [errorMessage, setErrorMessage] = useAtom(errorAtom); const sha = useAtomValue(dbMetaAtom); const pending = useAtomValue(pendingAtom); useEffect(() => { setPreferredLanguage(locale); }, [locale]); return /* @__PURE__ */ jsxs(Fragment, { children: [ errorMessage && /* @__PURE__ */ jsx(Modal, { open: true, onClose: () => setErrorMessage(null), children: /* @__PURE__ */ jsx("div", { style: { padding: px(16) }, children: errorMessage }) }), /* @__PURE__ */ jsx(Statusbar.Provider, { children: /* @__PURE__ */ jsx(Toolbar.Provider, { children: /* @__PURE__ */ jsxs(Sidebar.Provider, { children: [ /* @__PURE__ */ jsx(Head, { children: /* @__PURE__ */ jsx(FavIcon, { color }) }), /* @__PURE__ */ jsxs( "div", { style: { flex: "1", display: "flex", minHeight: 0, position: "relative" }, children: [ /* @__PURE__ */ jsxs(Sidebar.Nav, { children: [ Object.entries(roots).map(([key, root], i) => { const isSelected = key === currentRoot; const { id, ...location } = entryLocation; const link = location.root === key ? nav.entry(location) : nav.root({ workspace, root: key, locale: preferredLanguage }); const { label, icon } = Root.data(root); return /* @__PURE__ */ jsx( Sidebar.Nav.Item, { selected: isEntry && isSelected, href: link, "aria-label": label, children: /* @__PURE__ */ jsx(Icon, { icon: icon ?? IcRoundDescription }) }, key ); }), /* @__PURE__ */ jsx(SidebarSettings, {}) ] }), /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(SuspenseBoundary, { name: "main", fallback: /* @__PURE__ */ jsx(Loader, { absolute: true }), children: /* @__PURE__ */ jsx(RouteView, { fallback: null }) }) }) ] } ), alineaDev && /* @__PURE__ */ jsxs(Statusbar.Root, { children: [ /* @__PURE__ */ jsx( Statusbar.Status, { icon: pending === 0 ? IcRoundCheck : IcRoundSync, children: pending === 0 ? "Synced" : "Saving\u2026" } ), sha ? /* @__PURE__ */ jsx(Statusbar.Status, { icon: MaterialSymbolsDatabase, children: sha.slice(0, 7) }) : /* @__PURE__ */ jsx(Statusbar.Status, { icon: MaterialSymbolsDatabase, children: "Syncing" }) ] }) ] }) }) }) ] }); } function AppRoot() { const [session, setSession] = useAtom(sessionAtom); const { fullPage, config } = useDashboard(); const { color } = Config.mainWorkspace(config); const Auth = config.auth; if (!session) return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx(Head, { children: /* @__PURE__ */ jsx(FavIcon, { color }) }), Auth && /* @__PURE__ */ jsx(SuspenseBoundary, { name: "auth", fallback: /* @__PURE__ */ jsx(Loader, { absolute: true }), children: /* @__PURE__ */ jsx(Auth, { setSession }) }) ] }); return /* @__PURE__ */ jsx(SuspenseBoundary, { name: "router", fallback: /* @__PURE__ */ jsx(Loader, { absolute: true }), children: /* @__PURE__ */ jsx(RouterProvider, { router, children: /* @__PURE__ */ jsx(AppAuthenticated, {}) }) }); } function App(props) { const fullPage = props.fullPage !== false; const { color } = Config.mainWorkspace(props.config); return /* @__PURE__ */ jsx(DashboardProvider, { ...props, children: /* @__PURE__ */ jsx(Viewport, { attachToBody: fullPage, contain: true, color, children: /* @__PURE__ */ jsx(AppRoot, {}) }) }); } export { App };