diff --git a/apps/client/src/components/layouts/global/app-shell.module.css b/apps/client/src/components/layouts/global/app-shell.module.css
index b6e88d9..ed36961 100644
--- a/apps/client/src/components/layouts/global/app-shell.module.css
+++ b/apps/client/src/components/layouts/global/app-shell.module.css
@@ -14,3 +14,18 @@
}
}
+.resizeHandle {
+ width: 3px;
+ cursor: col-resize;
+ position: absolute;
+ right: 0;
+ top: 0;
+ bottom: 0;
+
+ &:hover, &:active {
+ width: 5px;
+ background: light-dark(var(--mantine-color-gray-4), var(--mantine-color-dark-5))
+ }
+}
+
+
diff --git a/apps/client/src/components/layouts/global/global-app-shell.tsx b/apps/client/src/components/layouts/global/global-app-shell.tsx
index 663ed44..ae26c98 100644
--- a/apps/client/src/components/layouts/global/global-app-shell.tsx
+++ b/apps/client/src/components/layouts/global/global-app-shell.tsx
@@ -1,12 +1,12 @@
import { AppShell, Container } from "@mantine/core";
-import React from "react";
+import React, { useCallback, 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,
+ 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";
@@ -21,6 +21,45 @@ export default function GlobalAppShell({
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) => {
+ 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");
@@ -33,7 +72,7 @@ export default function GlobalAppShell({
header={{ height: 45 }}
navbar={
!isHomeRoute && {
- width: 300,
+ width: isSpaceRoute ? sidebarWidth : 300,
breakpoint: "sm",
collapsed: {
mobile: !mobileOpened,
@@ -54,7 +93,10 @@ export default function GlobalAppShell({
{!isHomeRoute && (
-
+ e.preventDefault()}
+ >
+
{isSpaceRoute && }
{isSettingsRoute && }
diff --git a/apps/client/src/components/layouts/global/hooks/atoms/sidebar-atom.ts b/apps/client/src/components/layouts/global/hooks/atoms/sidebar-atom.ts
index fed366e..f71fc6f 100644
--- a/apps/client/src/components/layouts/global/hooks/atoms/sidebar-atom.ts
+++ b/apps/client/src/components/layouts/global/hooks/atoms/sidebar-atom.ts
@@ -19,3 +19,5 @@ export const asideStateAtom = atom({
tab: "",
isAsideOpen: false,
});
+
+export const sidebarWidthAtom = atomWithWebStorage('sidebarWidth', 300);
diff --git a/apps/client/src/lib/jotai-helper.ts b/apps/client/src/lib/jotai-helper.ts
index 06d2525..252a3bf 100644
--- a/apps/client/src/lib/jotai-helper.ts
+++ b/apps/client/src/lib/jotai-helper.ts
@@ -2,9 +2,9 @@ import { atom } from "jotai";
export function atomWithWebStorage(key: string, initialValue: Value, storage = localStorage) {
const storedValue = localStorage.getItem(key);
- const isString = typeof initialValue === "string";
+ const isStringOrInt = typeof initialValue === "string" || typeof initialValue === "number";
- const storageValue = storedValue ? isString ? storedValue : storedValue === "true" : undefined;
+ const storageValue = storedValue ? isStringOrInt ? storedValue : storedValue === "true" : undefined;
const baseAtom = atom(storageValue ?? initialValue);
return atom(