diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index be05e6422..e75b7d119 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -84,6 +84,7 @@ async function createWindow() { }), titleBarStyle: "hidden", + frame: process.platform === "win32" || process.platform === "darwin", titleBarOverlay: { height: 37, color: "#00000000", diff --git a/apps/web/src/app.css b/apps/web/src/app.css index cb8527d7f..5370a720e 100644 --- a/apps/web/src/app.css +++ b/apps/web/src/app.css @@ -4,10 +4,12 @@ } .tabsScroll, -.titlebarLogo { +.titlebarLogo, +.theme-scope-titleBar { -webkit-app-region: drag; } +.theme-scope-titleBar button, .tabsScroll .tab { -webkit-app-region: no-drag; } diff --git a/apps/web/src/app.tsx b/apps/web/src/app.tsx index a92d395e7..0920780fe 100644 --- a/apps/web/src/app.tsx +++ b/apps/web/src/app.tsx @@ -34,7 +34,6 @@ import { FlexScrollContainer } from "./components/scroll-container"; import CachedRouter from "./components/cached-router"; import { WebExtensionRelay } from "./utils/web-extension-relay"; import { usePersistentState } from "./hooks/use-persistent-state"; -import { EditorActionBar } from "./components/editor/action-bar"; new WebExtensionRelay(); @@ -136,7 +135,6 @@ function DesktopAppContents({ return ( <> - {IS_DESKTOP_APP ? : null} store.editorMargins); const isFocusMode = useAppStore((store) => store.isFocusMode); - const { isMaximized, isFullscreen, hasNativeWindowControls } = - useWindowControls(); + const { isFullscreen } = useWindowControls(); const activeSession = useEditorStore((store) => store.activeSessionId ? store.getSession(store.activeSessionId) : undefined ); @@ -153,100 +145,42 @@ export function EditorActionBar() { activeSession.type !== "conflicted" && !isFocusMode, onClick: () => useEditorStore.getState().toggleProperties() - }, - - { - title: "Minimize", - icon: WindowMinimize, - hidden: hasNativeWindowControls || isFullscreen, - enabled: true, - onClick: () => desktop?.window.minimze.mutate() - }, - { - title: isMaximized ? "Restore" : "Maximize", - icon: isMaximized ? WindowRestore : WindowMaximize, - enabled: true, - hidden: hasNativeWindowControls || isFullscreen, - onClick: () => - isMaximized - ? desktop?.window.restore.mutate() - : desktop?.window.maximize.mutate() - }, - { - title: "Close", - icon: WindowClose, - hidden: hasNativeWindowControls || isFullscreen, - enabled: true, - onClick: () => window.close() } ]; return ( - - - {IS_DESKTOP_APP && (getPlatform() !== "darwin" || isFullscreen) ? ( - - - - ) : null} - - + + {tools.map((tool) => ( + - ))} - - - + + + ))} + ); } diff --git a/apps/web/src/components/editor/index.tsx b/apps/web/src/components/editor/index.tsx index 65da3aa90..ea84f542e 100644 --- a/apps/web/src/components/editor/index.tsx +++ b/apps/web/src/components/editor/index.tsx @@ -91,7 +91,17 @@ export default function TabsView() { return ( <> - {IS_DESKTOP_APP ? null : } + {IS_DESKTOP_APP ? ( + ReactDOM.createPortal( + , + document.getElementById("titlebar-portal-container")! + ) + ) : ( + + + + )} + - - - Something went wrong - - - {help ? ( - <> - - What went wrong? - - {help.explanation} - - How to fix it? - - {help.action} - - ) : null} - + + + Something went wrong + + {help ? ( - - ) : ( - - )} - <> - - + ) : ( + + )} + <> + + - + ); + window.open(mailto.toString(), "_blank"); + }} + > + Contact support + + + diff --git a/apps/web/src/components/title-bar/index.tsx b/apps/web/src/components/title-bar/index.tsx new file mode 100644 index 000000000..8e26d885a --- /dev/null +++ b/apps/web/src/components/title-bar/index.tsx @@ -0,0 +1,128 @@ +/* +This file is part of the Notesnook project (https://notesnook.com/) + +Copyright (C) 2023 Streetwriters (Private) Limited + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +import { Button } from "@theme-ui/components"; +import { desktop } from "../../common/desktop-bridge"; +import { useWindowControls } from "../../hooks/use-window-controls"; +import { getPlatform } from "../../utils/platform"; +import { + WindowClose, + WindowMaximize, + WindowMinimize, + WindowRestore +} from "../icons"; +import { BaseThemeProvider } from "../theme-provider"; + +export function TitleBar() { + const { isMaximized, isFullscreen, hasNativeWindowControls } = + useWindowControls(); + + const tools = [ + { + title: "Minimize", + icon: WindowMinimize, + hidden: hasNativeWindowControls || isFullscreen, + enabled: true, + onClick: () => desktop?.window.minimze.mutate() + }, + { + title: isMaximized ? "Restore" : "Maximize", + icon: isMaximized ? WindowRestore : WindowMaximize, + enabled: true, + hidden: hasNativeWindowControls || isFullscreen, + onClick: () => + isMaximized + ? desktop?.window.restore.mutate() + : desktop?.window.maximize.mutate() + }, + { + title: "Close", + icon: WindowClose, + hidden: hasNativeWindowControls || isFullscreen, + enabled: true, + onClick: () => window.close() + } + ]; + + return ( + + {getPlatform() !== "darwin" || isFullscreen ? ( + + + + ) : null} +
+ {tools.map((tool) => ( + + ))} + + ); +} diff --git a/apps/web/src/index.html b/apps/web/src/index.html index 689e98d0c..2612c7107 100644 --- a/apps/web/src/index.html +++ b/apps/web/src/index.html @@ -130,6 +130,11 @@ overflow: hidden; } + #root { + display: flex; + flex-direction: column; + } + @keyframes fadeUp { 0% { transform: translateY(500px); diff --git a/apps/web/src/index.tsx b/apps/web/src/index.tsx index 951ab5782..44ea8416c 100644 --- a/apps/web/src/index.tsx +++ b/apps/web/src/index.tsx @@ -25,6 +25,7 @@ import { BaseThemeProvider } from "./components/theme-provider"; import { register } from "./utils/stream-saver/mitm"; import { getServiceWorkerVersion } from "./utils/version"; import { ErrorBoundary, ErrorComponent } from "./components/error-boundary"; +import { TitleBar } from "./components/title-bar"; renderApp(); @@ -36,29 +37,38 @@ async function renderApp() { try { const { component, props, path } = await init(); + const { useKeyStore } = await import("./interfaces/key-store"); + await useKeyStore.getState().init(); + if (serviceWorkerWhitelist.includes(path)) await initializeServiceWorker(); const { default: Component } = await component(); - const { default: AppLock } = await import("./views/app-lock"); + root.render( - - document.getElementById("splash")?.remove()} - sx={{ height: "100%", bg: "background" }} - > - - - - - + <> + {IS_DESKTOP_APP ? : null} + + document.getElementById("splash")?.remove()} + sx={{ bg: "background", flex: 1 }} + > + + + + + + ); } catch (e) { root.render( - window.location.reload()} - /> + <> + {IS_DESKTOP_APP ? : null} + window.location.reload()} + /> + ); } } diff --git a/apps/web/src/views/app-lock.tsx b/apps/web/src/views/app-lock.tsx index 2cd8f2c63..a90def5f7 100644 --- a/apps/web/src/views/app-lock.tsx +++ b/apps/web/src/views/app-lock.tsx @@ -38,7 +38,6 @@ import { getDocumentTitle, setDocumentTitle } from "../utils/dom"; import { CredentialWithoutSecret, useKeyStore } from "../interfaces/key-store"; export default function AppLock(props: PropsWithChildren) { - const init = usePromise(() => useKeyStore.getState().init()); const credentials = useKeyStore((store) => store.activeCredentials()); const isLocked = useKeyStore((store) => store.isLocked); const _lockAfter = useKeyStore((store) => store.secrets.lockAfter); @@ -120,8 +119,6 @@ export default function AppLock(props: PropsWithChildren) { } }, [lockAfter, credentials]); - if (init.status !== "fulfilled") return null; - if (isLocked) return (