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 ? (
-
- help.fix().catch((e) => {
- console.error(e);
- alert(errorToString(e));
- })
- }
- >
- Fix it
-
- ) : (
- window.location.reload()}
- >
- Reload app
-
- )}
- <>
- {
- navigator.clipboard.writeText(errorToString(error));
- }}
- >
- Copy
-
- {
- const { getDeviceInfo } = await import(
- "../../dialogs/issue-dialog"
- );
- const mailto = new URL("mailto:support@streetwriters.co");
- mailto.searchParams.set(
- "body",
- `${errorToString(error)}
+ <>
+
+ What went wrong?
+
+ {help.explanation}
+
+ How to fix it?
+
+ {help.action}
+ >
+ ) : null}
+
+ {help ? (
+
+ help.fix().catch((e) => {
+ console.error(e);
+ alert(errorToString(e));
+ })
+ }
+ >
+ Fix it
+
+ ) : (
+ window.location.reload()}
+ >
+ Reload app
+
+ )}
+ <>
+ {
+ navigator.clipboard.writeText(errorToString(error));
+ }}
+ >
+ Copy
+
+ {
+ const { getDeviceInfo } = await import(
+ "../../dialogs/issue-dialog"
+ );
+ const mailto = new URL("mailto:support@streetwriters.co");
+ mailto.searchParams.set(
+ "body",
+ `${errorToString(error)}
---
Device information:
${getDeviceInfo()}`
- );
- window.open(mailto.toString(), "_blank");
- }}
- >
- Contact support
-
- >
+ );
+ 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 (