mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 06:59:31 +01:00
web: replace allotment with react-resizable-panels
This commit is contained in:
1283
apps/web/package-lock.json
generated
1283
apps/web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -39,7 +39,6 @@
|
||||
"@trpc/client": "10.38.3",
|
||||
"@trpc/react-query": "10.38.3",
|
||||
"@zip.js/zip.js": "^2.7.32",
|
||||
"allotment": "^1.19.3",
|
||||
"async-mutex": "^0.4.0",
|
||||
"axios": "^1.3.4",
|
||||
"clipboard-polyfill": "4.0.0",
|
||||
@@ -77,6 +76,7 @@
|
||||
"react-loading-skeleton": "^3.3.1",
|
||||
"react-modal": "3.16.1",
|
||||
"react-qrcode-logo": "^2.9.0",
|
||||
"react-resizable-panels": "^2.0.17",
|
||||
"react-scroll-sync": "^0.11.2",
|
||||
"react-virtuoso": "^4.6.2",
|
||||
"timeago.js": "4.0.2",
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
diff --git a/node_modules/allotment/dist/modern.mjs b/node_modules/allotment/dist/modern.mjs
|
||||
index d5dbdc6..e2d9d2e 100644
|
||||
--- a/node_modules/allotment/dist/modern.mjs
|
||||
+++ b/node_modules/allotment/dist/modern.mjs
|
||||
@@ -1156,11 +1156,11 @@ class Ne extends W {
|
||||
return e < 0 || e >= this.viewItems.length ? -1 : this.viewItems[e].size;
|
||||
}
|
||||
isViewVisible(e) {
|
||||
- if (e < 0 || e >= this.viewItems.length) throw new Error("Index out of bounds");
|
||||
+ if (e < 0 || e >= this.viewItems.length) return false;
|
||||
return this.viewItems[e].visible;
|
||||
}
|
||||
setViewVisible(e, t) {
|
||||
- if (e < 0 || e >= this.viewItems.length) throw new Error("Index out of bounds");
|
||||
+ if (e < 0 || e >= this.viewItems.length) return;
|
||||
this.viewItems[e].setVisible(t), this.distributeEmptySpace(e), this.layoutViews(), this.saveProportions();
|
||||
}
|
||||
distributeViewSizes() {
|
||||
diff --git a/node_modules/allotment/dist/module.js b/node_modules/allotment/dist/module.js
|
||||
index 0de655f..f296aff 100644
|
||||
--- a/node_modules/allotment/dist/module.js
|
||||
+++ b/node_modules/allotment/dist/module.js
|
||||
@@ -1168,11 +1168,11 @@ class Ne extends W {
|
||||
return e < 0 || e >= this.viewItems.length ? -1 : this.viewItems[e].size;
|
||||
}
|
||||
isViewVisible(e) {
|
||||
- if (e < 0 || e >= this.viewItems.length) throw new Error("Index out of bounds");
|
||||
+ if (e < 0 || e >= this.viewItems.length) return false;
|
||||
return this.viewItems[e].visible;
|
||||
}
|
||||
setViewVisible(e, t) {
|
||||
- if (e < 0 || e >= this.viewItems.length) throw new Error("Index out of bounds");
|
||||
+ if (e < 0 || e >= this.viewItems.length) return;
|
||||
this.viewItems[e].setVisible(t), this.distributeEmptySpace(e), this.layoutViews(), this.saveProportions();
|
||||
}
|
||||
distributeViewSizes() {
|
||||
@@ -14,16 +14,31 @@
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.sash-module_sash__K-9lB.sash-module_hover__80W6I:before,
|
||||
.sash-module_sash__K-9lB.sash-module_active__bJspD:before {
|
||||
background: var(--accent);
|
||||
.panel-resize-handle {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.allotment-module_splitView__L-yRc.allotment-module_separatorBorder__x-rDS
|
||||
> .allotment-module_splitViewContainer__rQnVa
|
||||
> .allotment-module_splitViewView__MGZ6O:not(:first-child)::before {
|
||||
background-color: transparent;
|
||||
.panel-resize-handle::before {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
transition: background-color 300ms ease-out;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.panel-resize-handle[data-panel-group-direction="horizontal"]::before {
|
||||
width: 5px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.panel-resize-handle[data-panel-group-direction="vertical"]::before {
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
.panel-resize-handle[data-resize-handle-state="hover"]::before {
|
||||
background-color: var(--accent);
|
||||
}
|
||||
|
||||
/* open-sans-regular - vietnamese_latin-ext_latin_hebrew_greek-ext_greek_cyrillic-ext_cyrillic */
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
|
||||
@@ -17,13 +17,12 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React, { useState, Suspense, useRef } from "react";
|
||||
import React, { useState, Suspense, useRef, useEffect } from "react";
|
||||
import { Box, Flex } from "@theme-ui/components";
|
||||
import { ScopedThemeProvider } from "./components/theme-provider";
|
||||
import useMobile from "./hooks/use-mobile";
|
||||
import useTablet from "./hooks/use-tablet";
|
||||
import useDatabase from "./hooks/use-database";
|
||||
import { Allotment, AllotmentHandle, LayoutPriority } from "allotment";
|
||||
import { useStore } from "./stores/app-store";
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import { ViewLoader } from "./components/loaders/view-loader";
|
||||
@@ -33,7 +32,12 @@ import { EditorLoader } from "./components/loaders/editor-loader";
|
||||
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 {
|
||||
PanelGroup,
|
||||
Panel,
|
||||
PanelResizeHandle,
|
||||
ImperativePanelHandle
|
||||
} from "react-resizable-panels";
|
||||
|
||||
new WebExtensionRelay();
|
||||
|
||||
@@ -128,12 +132,19 @@ function DesktopAppContents({
|
||||
}: DesktopAppContentsProps) {
|
||||
const isFocusMode = useStore((store) => store.isFocusMode);
|
||||
const isTablet = useTablet();
|
||||
const [paneSizes, setPaneSizes] = usePersistentState("paneSizes", [
|
||||
isTablet ? 60 : 180,
|
||||
isTablet ? 240 : 380
|
||||
]);
|
||||
const panesRef = useRef<AllotmentHandle>(null);
|
||||
const [isNarrow, setIsNarrow] = useState(paneSizes[0] <= 55);
|
||||
const [isNarrow, setIsNarrow] = useState(isTablet || false);
|
||||
const navPane = useRef<ImperativePanelHandle>(null);
|
||||
const middlePane = useRef<ImperativePanelHandle>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (show) middlePane.current?.expand();
|
||||
else middlePane.current?.collapse();
|
||||
}, [show]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isFocusMode) navPane.current?.collapse();
|
||||
else navPane.current?.expand();
|
||||
}, [isFocusMode]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -143,20 +154,14 @@ function DesktopAppContents({
|
||||
overflow: "hidden"
|
||||
}}
|
||||
>
|
||||
<Allotment
|
||||
ref={panesRef}
|
||||
proportionalLayout={false}
|
||||
onDragEnd={(sizes) => {
|
||||
setPaneSizes(sizes);
|
||||
setIsNarrow(sizes[0] <= 55);
|
||||
}}
|
||||
>
|
||||
<Allotment.Pane
|
||||
className="pane nav-pane"
|
||||
minSize={50}
|
||||
preferredSize={isTablet ? 50 : paneSizes[0]}
|
||||
visible={!isFocusMode}
|
||||
priority={LayoutPriority.Low}
|
||||
<PanelGroup autoSaveId="global-panel-group" direction="horizontal">
|
||||
<Panel
|
||||
ref={navPane}
|
||||
className="nav-pane"
|
||||
defaultSize={10}
|
||||
minSize={3}
|
||||
onResize={(size) => setIsNarrow(size <= 3)}
|
||||
collapsible
|
||||
>
|
||||
<NavigationMenu
|
||||
toggleNavigationContainer={(state) => {
|
||||
@@ -164,13 +169,13 @@ function DesktopAppContents({
|
||||
}}
|
||||
isTablet={isNarrow}
|
||||
/>
|
||||
</Allotment.Pane>
|
||||
<Allotment.Pane
|
||||
className="pane middle-pane"
|
||||
minSize={2}
|
||||
preferredSize={paneSizes[1]}
|
||||
visible={show}
|
||||
priority={LayoutPriority.Normal}
|
||||
</Panel>
|
||||
<PanelResizeHandle className="panel-resize-handle" />
|
||||
<Panel
|
||||
ref={middlePane}
|
||||
className="middle-pane"
|
||||
collapsible
|
||||
defaultSize={20}
|
||||
>
|
||||
<ScopedThemeProvider
|
||||
className="listMenu"
|
||||
@@ -185,11 +190,9 @@ function DesktopAppContents({
|
||||
>
|
||||
{isAppLoaded && <CachedRouter />}
|
||||
</ScopedThemeProvider>
|
||||
</Allotment.Pane>
|
||||
<Allotment.Pane
|
||||
className="pane editor-pane"
|
||||
priority={LayoutPriority.High}
|
||||
>
|
||||
</Panel>
|
||||
<PanelResizeHandle className="panel-resize-handle" />
|
||||
<Panel className="editor-pane">
|
||||
<Flex
|
||||
sx={{
|
||||
display: "flex",
|
||||
@@ -201,10 +204,9 @@ function DesktopAppContents({
|
||||
>
|
||||
{isAppLoaded && <HashRouter />}
|
||||
</Flex>
|
||||
</Allotment.Pane>
|
||||
</Allotment>
|
||||
</Panel>
|
||||
</PanelGroup>
|
||||
</Flex>
|
||||
|
||||
<StatusBar />
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -67,6 +67,7 @@ export async function downloadAttachment<
|
||||
type: TType,
|
||||
groupId?: string
|
||||
): Promise<TOutputType | undefined> {
|
||||
console.log("DOWNLOADING FILE", hash);
|
||||
const response = await download(hash, groupId);
|
||||
if (!response) return;
|
||||
const { attachment, key } = response;
|
||||
|
||||
@@ -56,7 +56,6 @@ import Titlebox from "./title-box";
|
||||
import Config from "../../utils/config";
|
||||
import { ScopedThemeProvider } from "../theme-provider";
|
||||
import { Lightbox } from "../lightbox";
|
||||
import { Allotment } from "allotment";
|
||||
import { showToast } from "../../utils/toast";
|
||||
import { Item, MaybeDeletedItem, isDeleted } from "@notesnook/core/dist/types";
|
||||
import { debounce, debounceWithId } from "@notesnook/common";
|
||||
@@ -69,6 +68,7 @@ import { scrollIntoViewById } from "@notesnook/editor";
|
||||
import { IEditor } from "./types";
|
||||
import { EditorActionBar } from "./action-bar";
|
||||
import { logger } from "../../utils/logger";
|
||||
import { PanelGroup, Panel, PanelResizeHandle } from "react-resizable-panels";
|
||||
|
||||
const PDFPreview = React.lazy(() => import("../pdf-preview"));
|
||||
|
||||
@@ -120,13 +120,8 @@ export default function TabsView() {
|
||||
flexDirection: "column"
|
||||
}}
|
||||
>
|
||||
<Allotment
|
||||
proportionalLayout={true}
|
||||
onDragEnd={(sizes) => {
|
||||
Config.set("editor:panesize", sizes[1]);
|
||||
}}
|
||||
>
|
||||
<Allotment.Pane className="editor-pane">
|
||||
<PanelGroup direction="horizontal" autoSaveId={"editor-panels"}>
|
||||
<Panel id="editor-panel" className="editor-pane" order={1}>
|
||||
{sessions.map((session) => (
|
||||
<Freeze
|
||||
key={session.id}
|
||||
@@ -164,12 +159,16 @@ export default function TabsView() {
|
||||
)}
|
||||
</Freeze>
|
||||
))}
|
||||
</Allotment.Pane>
|
||||
</Panel>
|
||||
|
||||
{documentPreview && (
|
||||
<Allotment.Pane
|
||||
minSize={450}
|
||||
preferredSize={Config.get("editor:panesize", 500)}
|
||||
<>
|
||||
<PanelResizeHandle className="panel-resize-handle" />
|
||||
<Panel
|
||||
id="pdf-preview-panel"
|
||||
order={2}
|
||||
minSize={35}
|
||||
defaultSize={35}
|
||||
>
|
||||
<ScopedThemeProvider
|
||||
scope="editorSidebar"
|
||||
@@ -186,14 +185,18 @@ export default function TabsView() {
|
||||
{documentPreview.url ? (
|
||||
<Suspense
|
||||
fallback={
|
||||
<DownloadAttachmentProgress hash={documentPreview.hash} />
|
||||
<DownloadAttachmentProgress
|
||||
hash={documentPreview.hash}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<PDFPreview
|
||||
fileUrl={documentPreview.url}
|
||||
hash={documentPreview.hash}
|
||||
onClose={() =>
|
||||
useEditorStore.setState({ documentPreview: undefined })
|
||||
useEditorStore.setState({
|
||||
documentPreview: undefined
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Suspense>
|
||||
@@ -201,9 +204,10 @@ export default function TabsView() {
|
||||
<DownloadAttachmentProgress hash={documentPreview.hash} />
|
||||
)}
|
||||
</ScopedThemeProvider>
|
||||
</Allotment.Pane>
|
||||
</Panel>
|
||||
</>
|
||||
)}
|
||||
</Allotment>
|
||||
</PanelGroup>
|
||||
<DropZone overlayRef={overlayRef} />
|
||||
{arePropertiesVisible && activeSessionId && (
|
||||
<Properties sessionId={activeSessionId} />
|
||||
|
||||
@@ -20,7 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import { useEffect, useState } from "react";
|
||||
import { initializeDatabase } from "../common/db";
|
||||
import { useErrorBoundary } from "react-error-boundary";
|
||||
import "allotment/dist/style.css";
|
||||
import "../utils/analytics";
|
||||
import "../app.css";
|
||||
|
||||
|
||||
@@ -458,6 +458,7 @@ async function downloadFile(
|
||||
requestOptions: RequestOptionsWithSignal
|
||||
) {
|
||||
try {
|
||||
console.log("DOWNLOADING FILE", filename);
|
||||
const { url, headers, chunkSize, signal } = requestOptions;
|
||||
const handle = await streamablefs.readFile(filename);
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ const routes = defineRoutes({
|
||||
return defineRoute({
|
||||
key: "notebook",
|
||||
type: "notes",
|
||||
noCache: true,
|
||||
component: Notebook,
|
||||
props: {
|
||||
rootId,
|
||||
|
||||
@@ -29,6 +29,7 @@ export type RouteResult = {
|
||||
| React.MemoExoticComponent<React.FunctionComponent>;
|
||||
props?: any;
|
||||
buttons?: RouteContainerButtons;
|
||||
noCache?: boolean;
|
||||
};
|
||||
|
||||
export function isRouteResult(obj: any): obj is RouteResult {
|
||||
|
||||
@@ -37,7 +37,6 @@ import {
|
||||
ShortcutLink
|
||||
} from "../components/icons";
|
||||
import { pluralize } from "@notesnook/common";
|
||||
import { Allotment, AllotmentHandle } from "allotment";
|
||||
import { Plus } from "../components/icons";
|
||||
import { useStore as useNotesStore } from "../stores/note-store";
|
||||
import { useStore as useNotebookStore } from "../stores/notebook-store";
|
||||
@@ -58,6 +57,12 @@ import { FlexScrollContainer } from "../components/scroll-container";
|
||||
import { Menu } from "../hooks/use-menu";
|
||||
import Config from "../utils/config";
|
||||
import Notes from "./notes";
|
||||
import {
|
||||
PanelGroup,
|
||||
Panel,
|
||||
PanelResizeHandle,
|
||||
ImperativePanelHandle
|
||||
} from "react-resizable-panels";
|
||||
|
||||
type NotebookProps = {
|
||||
rootId: string;
|
||||
@@ -67,8 +72,7 @@ function Notebook(props: NotebookProps) {
|
||||
const { rootId, notebookId } = props;
|
||||
const [isCollapsed, setIsCollapsed] = useState(false);
|
||||
|
||||
const paneRef = useRef<AllotmentHandle>(null);
|
||||
const sizes = useRef<number[]>([]);
|
||||
const subNotebooksPane = useRef<ImperativePanelHandle>(null);
|
||||
|
||||
const context = useNotesStore((store) => store.context);
|
||||
const notes = useNotesStore((store) => store.contextNotes);
|
||||
@@ -96,40 +100,13 @@ function Notebook(props: NotebookProps) {
|
||||
});
|
||||
}, [rootId, notebookId]);
|
||||
|
||||
const toggleCollapse = useCallback((isCollapsed: boolean) => {
|
||||
if (!paneRef.current || !sizes.current) return;
|
||||
|
||||
if (!isCollapsed) {
|
||||
if (sizes.current[1] < 60) {
|
||||
paneRef.current.reset();
|
||||
} else {
|
||||
paneRef.current.resize(sizes.current);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
toggleCollapse(isCollapsed);
|
||||
}, [isCollapsed, toggleCollapse]);
|
||||
|
||||
if (!context || !notes || context.type !== "notebook") return null;
|
||||
return (
|
||||
<>
|
||||
<Allotment
|
||||
ref={paneRef}
|
||||
vertical
|
||||
onChange={(paneSizes) => {
|
||||
const [_, topicsPane] = paneSizes;
|
||||
if (topicsPane > 30 && !isCollapsed) sizes.current = paneSizes;
|
||||
}}
|
||||
onDragEnd={([_, topicsPane]) => {
|
||||
if (topicsPane < 35 && !isCollapsed) {
|
||||
setIsCollapsed(true);
|
||||
}
|
||||
}}
|
||||
<PanelGroup
|
||||
direction="vertical"
|
||||
autoSaveId={`notebook-panel-sizes:${rootId}`}
|
||||
>
|
||||
<Allotment.Pane>
|
||||
<Flex variant="columnFill" sx={{ height: "100%" }}>
|
||||
<Panel>
|
||||
<Notes
|
||||
header={
|
||||
<NotebookHeader
|
||||
@@ -139,12 +116,15 @@ function Notebook(props: NotebookProps) {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
</Allotment.Pane>
|
||||
<Allotment.Pane
|
||||
preferredSize={250}
|
||||
visible
|
||||
maxSize={isCollapsed ? 30 : Infinity}
|
||||
</Panel>
|
||||
<PanelResizeHandle className="panel-resize-handle" />
|
||||
<Panel
|
||||
ref={subNotebooksPane}
|
||||
defaultSize={25}
|
||||
collapsedSize={7}
|
||||
collapsible
|
||||
minSize={7}
|
||||
onResize={(size) => setIsCollapsed(size <= 7)}
|
||||
>
|
||||
<SubNotebooks
|
||||
key={rootId}
|
||||
@@ -152,12 +132,12 @@ function Notebook(props: NotebookProps) {
|
||||
isCollapsed={isCollapsed}
|
||||
rootId={rootId}
|
||||
onClick={() => {
|
||||
setIsCollapsed((isCollapsed) => !isCollapsed);
|
||||
if (isCollapsed) subNotebooksPane.current?.expand();
|
||||
else subNotebooksPane.current?.collapse();
|
||||
}}
|
||||
/>
|
||||
</Allotment.Pane>
|
||||
</Allotment>
|
||||
</>
|
||||
</Panel>
|
||||
</PanelGroup>
|
||||
);
|
||||
}
|
||||
export default Notebook;
|
||||
|
||||
Reference in New Issue
Block a user