web: replace allotment with react-resizable-panels

This commit is contained in:
Abdullah Atta
2024-04-17 14:23:19 +05:00
parent d5cf65e568
commit a65ebec7ae
12 changed files with 1269 additions and 358 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -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",

View File

@@ -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() {

View File

@@ -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";

View File

@@ -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 />
</>
);

View File

@@ -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;

View File

@@ -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} />

View File

@@ -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";

View File

@@ -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);

View File

@@ -65,6 +65,7 @@ const routes = defineRoutes({
return defineRoute({
key: "notebook",
type: "notes",
noCache: true,
component: Notebook,
props: {
rootId,

View File

@@ -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 {

View File

@@ -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;