Add support for hiding sidebar (#2809)
* Add support for hiding sidebar Support cmd/ctrl + shift +s for quick hide/show * patch sidebar padding on collapse * update Key for sidebar setting
This commit is contained in:
parent
426e2360b3
commit
e4a556d551
@ -41,8 +41,8 @@ export default function ThreadItem({
|
|||||||
style={{ width: THREAD_CALLOUT_DETAIL_WIDTH / 2 }}
|
style={{ width: THREAD_CALLOUT_DETAIL_WIDTH / 2 }}
|
||||||
className={`${
|
className={`${
|
||||||
isActive
|
isActive
|
||||||
? "border-l-2 border-b-2 border-white light:border-theme-sidebar-border z-30"
|
? "border-l-2 border-b-2 border-white light:border-theme-sidebar-border z-[2]"
|
||||||
: "border-l border-b border-[#6F6F71] light:border-theme-sidebar-border z-10"
|
: "border-l border-b border-[#6F6F71] light:border-theme-sidebar-border z-[1]"
|
||||||
} h-[50%] absolute top-0 left-2 rounded-bl-lg`}
|
} h-[50%] absolute top-0 left-2 rounded-bl-lg`}
|
||||||
></div>
|
></div>
|
||||||
{/* Downstroke border for next item */}
|
{/* Downstroke border for next item */}
|
||||||
@ -51,8 +51,8 @@ export default function ThreadItem({
|
|||||||
style={{ width: THREAD_CALLOUT_DETAIL_WIDTH / 2 }}
|
style={{ width: THREAD_CALLOUT_DETAIL_WIDTH / 2 }}
|
||||||
className={`${
|
className={`${
|
||||||
idx <= activeIdx && !isActive
|
idx <= activeIdx && !isActive
|
||||||
? "border-l-2 border-white light:border-theme-sidebar-border z-20"
|
? "border-l-2 border-white light:border-theme-sidebar-border z-[2]"
|
||||||
: "border-l border-[#6F6F71] light:border-theme-sidebar-border z-10"
|
: "border-l border-[#6F6F71] light:border-theme-sidebar-border z-[1]"
|
||||||
} h-[100%] absolute top-0 left-2`}
|
} h-[100%] absolute top-0 left-2`}
|
||||||
></div>
|
></div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
105
frontend/src/components/Sidebar/SidebarToggle/index.jsx
Normal file
105
frontend/src/components/Sidebar/SidebarToggle/index.jsx
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { SidebarSimple } from "@phosphor-icons/react";
|
||||||
|
import paths from "@/utils/paths";
|
||||||
|
import { Tooltip } from "react-tooltip";
|
||||||
|
const SIDEBAR_TOGGLE_STORAGE_KEY = "anythingllm_sidebar_toggle";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the previous state of the sidebar from localStorage.
|
||||||
|
* If the sidebar was closed, returns false.
|
||||||
|
* If the sidebar was open, returns true.
|
||||||
|
* If the sidebar state is not set, returns true.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function previousSidebarState() {
|
||||||
|
const previousState = window.localStorage.getItem(SIDEBAR_TOGGLE_STORAGE_KEY);
|
||||||
|
if (previousState === "closed") return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useSidebarToggle() {
|
||||||
|
const [showSidebar, setShowSidebar] = useState(previousSidebarState());
|
||||||
|
const [canToggleSidebar, setCanToggleSidebar] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function checkPath() {
|
||||||
|
const currentPath = window.location.pathname;
|
||||||
|
const isVisible =
|
||||||
|
currentPath === paths.home() ||
|
||||||
|
/^\/workspace\/[^\/]+$/.test(currentPath) ||
|
||||||
|
/^\/workspace\/[^\/]+\/t\/[^\/]+$/.test(currentPath);
|
||||||
|
setCanToggleSidebar(isVisible);
|
||||||
|
}
|
||||||
|
checkPath();
|
||||||
|
}, [window.location.pathname]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function toggleSidebar(e) {
|
||||||
|
if (!canToggleSidebar) return;
|
||||||
|
if (
|
||||||
|
(e.ctrlKey || e.metaKey) &&
|
||||||
|
e.shiftKey &&
|
||||||
|
e.key.toLowerCase() === "s"
|
||||||
|
) {
|
||||||
|
setShowSidebar((prev) => {
|
||||||
|
const newState = !prev;
|
||||||
|
window.localStorage.setItem(
|
||||||
|
SIDEBAR_TOGGLE_STORAGE_KEY,
|
||||||
|
newState ? "open" : "closed"
|
||||||
|
);
|
||||||
|
return newState;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.addEventListener("keydown", toggleSidebar);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("keydown", toggleSidebar);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.localStorage.setItem(
|
||||||
|
SIDEBAR_TOGGLE_STORAGE_KEY,
|
||||||
|
showSidebar ? "open" : "closed"
|
||||||
|
);
|
||||||
|
}, [showSidebar]);
|
||||||
|
|
||||||
|
return { showSidebar, setShowSidebar, canToggleSidebar };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ToggleSidebarButton({ showSidebar, setShowSidebar }) {
|
||||||
|
const isMac = navigator.userAgent.includes("Mac");
|
||||||
|
const shortcut = isMac ? "⌘ + Shift + S" : "Ctrl + Shift + S";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`hidden md:block border-none bg-transparent outline-none ring-0 transition-left duration-500 ${showSidebar ? "left-[247px]" : "absolute top-[20px] left-[30px] z-10"}`}
|
||||||
|
onClick={() => setShowSidebar((prev) => !prev)}
|
||||||
|
data-tooltip-id="sidebar-toggle"
|
||||||
|
data-tooltip-content={
|
||||||
|
showSidebar
|
||||||
|
? `Hide Sidebar (${shortcut})`
|
||||||
|
: `Show Sidebar (${shortcut})`
|
||||||
|
}
|
||||||
|
aria-label={
|
||||||
|
showSidebar
|
||||||
|
? `Hide Sidebar (${shortcut})`
|
||||||
|
: `Show Sidebar (${shortcut})`
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SidebarSimple
|
||||||
|
className="text-theme-text-secondary hover:text-theme-text-primary"
|
||||||
|
size={24}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<Tooltip
|
||||||
|
id="sidebar-toggle"
|
||||||
|
place="top"
|
||||||
|
delayShow={300}
|
||||||
|
className="tooltip !text-xs z-99"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -11,11 +11,13 @@ import SettingsButton from "../SettingsButton";
|
|||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import paths from "@/utils/paths";
|
import paths from "@/utils/paths";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useSidebarToggle, ToggleSidebarButton } from "./SidebarToggle";
|
||||||
|
|
||||||
export default function Sidebar() {
|
export default function Sidebar() {
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
const { logo } = useLogo();
|
const { logo } = useLogo();
|
||||||
const sidebarRef = useRef(null);
|
const sidebarRef = useRef(null);
|
||||||
|
const { showSidebar, setShowSidebar, canToggleSidebar } = useSidebarToggle();
|
||||||
const {
|
const {
|
||||||
showing: showingNewWsModal,
|
showing: showingNewWsModal,
|
||||||
showModal: showNewWsModal,
|
showModal: showNewWsModal,
|
||||||
@ -24,50 +26,64 @@ export default function Sidebar() {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
<Link
|
|
||||||
to={paths.home()}
|
|
||||||
className="flex shrink-0 max-w-[55%] items-center justify-start mx-[38px] my-[18px]"
|
|
||||||
aria-label="Home"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src={logo}
|
|
||||||
alt="Logo"
|
|
||||||
className="rounded max-h-[24px] object-contain"
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
<div
|
<div
|
||||||
ref={sidebarRef}
|
style={{
|
||||||
className="relative m-[16px] rounded-[16px] bg-theme-bg-sidebar border-[2px] border-theme-sidebar-border light:border-none min-w-[250px] p-[10px] h-[calc(100%-76px)]"
|
width: showSidebar ? "292px" : "0px",
|
||||||
|
paddingLeft: showSidebar ? "0px" : "16px",
|
||||||
|
}}
|
||||||
|
className="transition-all duration-500"
|
||||||
>
|
>
|
||||||
<div className="flex flex-col h-full overflow-x-hidden">
|
<div className="flex shrink-0 w-full justify-center my-[18px]">
|
||||||
<div className="flex-grow flex flex-col min-w-[235px]">
|
<div className="flex justify-between w-[250px] min-w-[250px]">
|
||||||
<div className="relative h-[calc(100%-60px)] flex flex-col w-full justify-between pt-[10px] overflow-y-scroll no-scroll">
|
<Link to={paths.home()} aria-label="Home">
|
||||||
<div className="flex flex-col gap-y-2 pb-[60px] overflow-y-scroll no-scroll">
|
<img
|
||||||
<div className="flex gap-x-2 items-center justify-between">
|
src={logo}
|
||||||
{(!user || user?.role !== "default") && (
|
alt="Logo"
|
||||||
<button
|
className={`rounded max-h-[24px] object-contain transition-opacity duration-500 ${showSidebar ? "opacity-100" : "opacity-0"}`}
|
||||||
onClick={showNewWsModal}
|
/>
|
||||||
className="light:bg-[#C2E7FE] light:hover:bg-[#7CD4FD] flex flex-grow w-[75%] h-[44px] gap-x-2 py-[5px] px-2.5 mb-2 bg-white rounded-[8px] text-sidebar justify-center items-center hover:bg-opacity-80 transition-all duration-300"
|
</Link>
|
||||||
>
|
{canToggleSidebar && (
|
||||||
<Plus size={18} weight="bold" />
|
<ToggleSidebarButton
|
||||||
<p className="text-sidebar text-sm font-semibold">
|
showSidebar={showSidebar}
|
||||||
{t("new-workspace.title")}
|
setShowSidebar={setShowSidebar}
|
||||||
</p>
|
/>
|
||||||
</button>
|
)}
|
||||||
)}
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
ref={sidebarRef}
|
||||||
|
className="relative m-[16px] rounded-[16px] bg-theme-bg-sidebar border-[2px] border-theme-sidebar-border light:border-none min-w-[250px] p-[10px] h-[calc(100%-76px)]"
|
||||||
|
>
|
||||||
|
<div className="flex flex-col h-full overflow-x-hidden">
|
||||||
|
<div className="flex-grow flex flex-col min-w-[235px]">
|
||||||
|
<div className="relative h-[calc(100%-60px)] flex flex-col w-full justify-between pt-[10px] overflow-y-scroll no-scroll">
|
||||||
|
<div className="flex flex-col gap-y-2 pb-[60px] overflow-y-scroll no-scroll">
|
||||||
|
<div className="flex gap-x-2 items-center justify-between">
|
||||||
|
{(!user || user?.role !== "default") && (
|
||||||
|
<button
|
||||||
|
onClick={showNewWsModal}
|
||||||
|
className="light:bg-[#C2E7FE] light:hover:bg-[#7CD4FD] flex flex-grow w-[75%] h-[44px] gap-x-2 py-[5px] px-2.5 mb-2 bg-white rounded-[8px] text-sidebar justify-center items-center hover:bg-opacity-80 transition-all duration-300"
|
||||||
|
>
|
||||||
|
<Plus size={18} weight="bold" />
|
||||||
|
<p className="text-sidebar text-sm font-semibold">
|
||||||
|
{t("new-workspace.title")}
|
||||||
|
</p>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<ActiveWorkspaces />
|
||||||
</div>
|
</div>
|
||||||
<ActiveWorkspaces />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="absolute bottom-0 left-0 right-0 pt-4 pb-3 rounded-b-[16px] bg-theme-bg-sidebar bg-opacity-80 backdrop-filter backdrop-blur-md z-1">
|
||||||
<div className="absolute bottom-0 left-0 right-0 pt-4 pb-3 rounded-b-[16px] bg-theme-bg-sidebar bg-opacity-80 backdrop-filter backdrop-blur-md z-10">
|
<Footer />
|
||||||
<Footer />
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{showingNewWsModal && <NewWorkspaceModal hideModal={hideNewWsModal} />}
|
||||||
</div>
|
</div>
|
||||||
{showingNewWsModal && <NewWorkspaceModal hideModal={hideNewWsModal} />}
|
</>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -264,7 +264,7 @@ export default function ChatContainer({ workspace, knownHistory = [] }) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||||
className="transition-all duration-500 relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-theme-bg-secondary w-full h-full overflow-y-scroll no-scroll"
|
className="transition-all duration-500 relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[16px] bg-theme-bg-secondary w-full h-full overflow-y-scroll no-scroll z-[2]"
|
||||||
>
|
>
|
||||||
{isMobile && <SidebarMobileHeader />}
|
{isMobile && <SidebarMobileHeader />}
|
||||||
<DnDFileUploaderWrapper>
|
<DnDFileUploaderWrapper>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user