mirror of
https://github.com/docmost/docmost.git
synced 2026-05-06 22:03:06 +08:00
b81c9ee10c
* stripe init git submodules for enterprise modules * * Cloud billing UI - WIP * Proxy websockets in dev mode * Separate workspace login and creation for cloud * Other fixes * feat: billing (cloud) * * add domain service * prepare links from workspace hostname * WIP * Add exchange token generation * Validate JWT token type during verification * domain service * add SkipTransform decorator * * updates (server) * add new packages * new sso migration file * WIP * Fix hostname generation * WIP * WIP * Reduce input error font-size * set max password length * jwt package * license page - WIP * * License management UI * Move license key store to db * add reflector * SSO enforcement * * Add default plan * Add usePlan hook * * Fix auth container margin in mobile * Redirect login and home to select page in cloud * update .gitignore * Default to yearly * * Trial messaging * Handle ended trials * Don't set to readonly on collab disconnect (Cloud) * Refine trial (UI) * Fix bug caused by using jotai optics atom in AppHeader component * configurable database maximum pool * Close SSO form on save * wip * sync * Only show sign-in in cloud * exclude base api part from workspaceId check * close db connection beforeApplicationShutdown * Add health/live endpoint * clear cookie on hostname change * reset currentUser atom * Change text * return 401 if workspace does not match * feat: show user workspace list in cloud login page * sync * Add home path * Prefetch to speed up queries * * Add robots.txt * Disallow login and forgot password routes * wildcard user-agent * Fix space query cache * fix * fix * use space uuid for recent pages * prefetch billing plans * enhance license page * sync
128 lines
3.7 KiB
TypeScript
128 lines
3.7 KiB
TypeScript
import { AppShell, Container } from "@mantine/core";
|
|
import React, { useEffect, useRef, useState } from "react";
|
|
import { useLocation } from "react-router-dom";
|
|
import SettingsSidebar from "@/components/settings/settings-sidebar.tsx";
|
|
import { useAtom } from "jotai";
|
|
import {
|
|
asideStateAtom,
|
|
desktopSidebarAtom,
|
|
mobileSidebarAtom,
|
|
sidebarWidthAtom,
|
|
} from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
|
|
import { SpaceSidebar } from "@/features/space/components/sidebar/space-sidebar.tsx";
|
|
import { AppHeader } from "@/components/layouts/global/app-header.tsx";
|
|
import Aside from "@/components/layouts/global/aside.tsx";
|
|
import classes from "./app-shell.module.css";
|
|
import { useTrialEndAction } from "@/ee/hooks/use-trial-end-action.tsx";
|
|
|
|
export default function GlobalAppShell({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode;
|
|
}) {
|
|
useTrialEndAction();
|
|
const [mobileOpened] = useAtom(mobileSidebarAtom);
|
|
const [desktopOpened] = useAtom(desktopSidebarAtom);
|
|
const [{ isAsideOpen }] = useAtom(asideStateAtom);
|
|
const [sidebarWidth, setSidebarWidth] = useAtom(sidebarWidthAtom);
|
|
const [isResizing, setIsResizing] = useState(false);
|
|
const sidebarRef = useRef(null);
|
|
|
|
const startResizing = React.useCallback((mouseDownEvent) => {
|
|
mouseDownEvent.preventDefault();
|
|
setIsResizing(true);
|
|
}, []);
|
|
|
|
const stopResizing = React.useCallback(() => {
|
|
setIsResizing(false);
|
|
}, []);
|
|
|
|
const resize = React.useCallback(
|
|
(mouseMoveEvent) => {
|
|
if (isResizing) {
|
|
const newWidth =
|
|
mouseMoveEvent.clientX -
|
|
sidebarRef.current.getBoundingClientRect().left;
|
|
if (newWidth < 220) {
|
|
setSidebarWidth(220);
|
|
return;
|
|
}
|
|
if (newWidth > 600) {
|
|
setSidebarWidth(600);
|
|
return;
|
|
}
|
|
setSidebarWidth(newWidth);
|
|
}
|
|
},
|
|
[isResizing],
|
|
);
|
|
|
|
useEffect(() => {
|
|
//https://codesandbox.io/p/sandbox/kz9de
|
|
window.addEventListener("mousemove", resize);
|
|
window.addEventListener("mouseup", stopResizing);
|
|
return () => {
|
|
window.removeEventListener("mousemove", resize);
|
|
window.removeEventListener("mouseup", stopResizing);
|
|
};
|
|
}, [resize, stopResizing]);
|
|
|
|
const location = useLocation();
|
|
const isSettingsRoute = location.pathname.startsWith("/settings");
|
|
const isSpaceRoute = location.pathname.startsWith("/s/");
|
|
const isHomeRoute = location.pathname.startsWith("/home");
|
|
const isPageRoute = location.pathname.includes("/p/");
|
|
|
|
return (
|
|
<AppShell
|
|
header={{ height: 45 }}
|
|
navbar={
|
|
!isHomeRoute && {
|
|
width: isSpaceRoute ? sidebarWidth : 300,
|
|
breakpoint: "sm",
|
|
collapsed: {
|
|
mobile: !mobileOpened,
|
|
desktop: !desktopOpened,
|
|
},
|
|
}
|
|
}
|
|
aside={
|
|
isPageRoute && {
|
|
width: 350,
|
|
breakpoint: "sm",
|
|
collapsed: { mobile: !isAsideOpen, desktop: !isAsideOpen },
|
|
}
|
|
}
|
|
padding="md"
|
|
>
|
|
<AppShell.Header px="md" className={classes.header}>
|
|
<AppHeader />
|
|
</AppShell.Header>
|
|
{!isHomeRoute && (
|
|
<AppShell.Navbar
|
|
className={classes.navbar}
|
|
withBorder={false}
|
|
ref={sidebarRef}
|
|
>
|
|
<div className={classes.resizeHandle} onMouseDown={startResizing} />
|
|
{isSpaceRoute && <SpaceSidebar />}
|
|
{isSettingsRoute && <SettingsSidebar />}
|
|
</AppShell.Navbar>
|
|
)}
|
|
<AppShell.Main>
|
|
{isSettingsRoute ? (
|
|
<Container size={800}>{children}</Container>
|
|
) : (
|
|
children
|
|
)}
|
|
</AppShell.Main>
|
|
|
|
{isPageRoute && (
|
|
<AppShell.Aside className={classes.aside} p="md" withBorder={false}>
|
|
<Aside />
|
|
</AppShell.Aside>
|
|
)}
|
|
</AppShell>
|
|
);
|
|
}
|