mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2024-11-18 20:20:11 +01:00
improve UX and useability for Settings and prefernces for mobile and desktop (#200)
* improve UX and useability for Settings and prefernces for mobile and desktop * linting
This commit is contained in:
parent
1b4e29a3b9
commit
7ae0d28ef0
@ -12,7 +12,6 @@ const AdminWorkspaces = lazy(() => import("./pages/Admin/Workspaces"));
|
|||||||
const AdminChats = lazy(() => import("./pages/Admin/Chats"));
|
const AdminChats = lazy(() => import("./pages/Admin/Chats"));
|
||||||
const AdminSystem = lazy(() => import("./pages/Admin/System"));
|
const AdminSystem = lazy(() => import("./pages/Admin/System"));
|
||||||
const AdminAppearance = lazy(() => import("./pages/Admin/Appearance"));
|
const AdminAppearance = lazy(() => import("./pages/Admin/Appearance"));
|
||||||
const Appearance = lazy(() => import("./pages/System/Appearance"));
|
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
@ -20,7 +19,6 @@ export default function App() {
|
|||||||
<ContextWrapper>
|
<ContextWrapper>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Main />} />
|
<Route path="/" element={<Main />} />
|
||||||
<Route path="/system/appearance" element={<Appearance />} />
|
|
||||||
<Route
|
<Route
|
||||||
path="/workspace/:slug"
|
path="/workspace/:slug"
|
||||||
element={<PrivateRoute Component={WorkspaceChat} />}
|
element={<PrivateRoute Component={WorkspaceChat} />}
|
||||||
|
@ -182,12 +182,12 @@ export function SidebarMobileHeader() {
|
|||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
ref={sidebarRef}
|
ref={sidebarRef}
|
||||||
className="h-[100vh] fixed top-0 left-0 rounded-r-[26px] bg-white dark:bg-black-900 w-[70%] p-[18px] "
|
className="h-[100vh] fixed top-0 left-0 rounded-r-[26px] bg-white dark:bg-black-900 w-[80%] p-[18px] "
|
||||||
>
|
>
|
||||||
<div className="w-full h-full flex flex-col overflow-x-hidden items-between">
|
<div className="w-full h-full flex flex-col overflow-x-hidden items-between">
|
||||||
{/* Header Information */}
|
{/* Header Information */}
|
||||||
<div className="flex w-full items-center justify-between">
|
<div className="flex w-full items-center justify-between gap-x-4">
|
||||||
<div className="flex shrink-0 w-fit items-center justify-start">
|
<div className="flex shrink-1 w-fit items-center justify-start">
|
||||||
<img
|
<img
|
||||||
src={logo}
|
src={logo}
|
||||||
alt="Logo"
|
alt="Logo"
|
||||||
@ -195,7 +195,7 @@ export function SidebarMobileHeader() {
|
|||||||
style={{ objectFit: "contain" }}
|
style={{ objectFit: "contain" }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-x-2 items-center text-slate-500">
|
<div className="flex gap-x-2 items-center text-slate-500 shrink-0">
|
||||||
<a
|
<a
|
||||||
href={paths.home()}
|
href={paths.home()}
|
||||||
className="transition-all duration-300 p-2 rounded-full bg-slate-200 text-slate-400 dark:bg-stone-800 hover:bg-slate-800 hover:text-slate-200 dark:hover:text-slate-200"
|
className="transition-all duration-300 p-2 rounded-full bg-slate-200 text-slate-400 dark:bg-stone-800 hover:bg-slate-800 hover:text-slate-200 dark:hover:text-slate-200"
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import AnythingLLMLight from "../../media/logo/anything-llm-light.png";
|
import useLogo from "../../../../hooks/useLogo";
|
||||||
import AnythingLLMDark from "../../media/logo/anything-llm-dark.png";
|
import usePrefersDarkMode from "../../../../hooks/usePrefersDarkMode";
|
||||||
import System from "../../models/system";
|
import System from "../../../../models/system";
|
||||||
import usePrefersDarkMode from "../../hooks/usePrefersDarkMode";
|
import EditingChatBubble from "../../../EditingChatBubble";
|
||||||
import useLogo from "../../hooks/useLogo";
|
import AnythingLLMLight from "../../../../media/logo/anything-llm-light.png";
|
||||||
import EditingChatBubble from "../../components/EditingChatBubble";
|
import AnythingLLMDark from "../../../../media/logo/anything-llm-dark.png";
|
||||||
import { isMobile } from "react-device-detect";
|
|
||||||
import { ArrowLeft } from "react-feather";
|
|
||||||
import paths from "../../utils/paths";
|
|
||||||
|
|
||||||
export default function Appearance() {
|
export default function Appearance() {
|
||||||
const { logo: _initLogo } = useLogo();
|
const { logo: _initLogo } = useLogo();
|
||||||
@ -118,32 +115,16 @@ export default function Appearance() {
|
|||||||
setHasChanges(false);
|
setHasChanges(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBackNavigation = () => {
|
|
||||||
window.location = paths.home();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-screen h-screen overflow-hidden bg-orange-100 dark:bg-stone-700 flex justify-center py-6">
|
<div className="relative w-full w-full max-h-full">
|
||||||
<div
|
<div className="relative bg-white rounded-lg shadow dark:bg-stone-700">
|
||||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
<div className="flex items-start justify-between px-6 py-4">
|
||||||
className="transition-all duration-500 relative md:ml-[2px] md:mr-[8px] md:my-[16px] md:rounded-[26px] bg-white dark:bg-black-900 md:min-w-[82%] p-[18px] h-full overflow-y-scroll"
|
<p className="text-gray-800 dark:text-stone-200 text-base ">
|
||||||
>
|
Customize the appearance settings of AnythingLLM instance.
|
||||||
<div className="px-1 md:px-8">
|
|
||||||
<div className="mb-6">
|
|
||||||
<div
|
|
||||||
className="cursor-pointer inline-flex items-center gap-3 mb-5 py-2 pl-2 pr-4 text-white rounded-md hover:bg-gray-300 dark:hover:bg-gray-800 transition-all"
|
|
||||||
onClick={handleBackNavigation}
|
|
||||||
>
|
|
||||||
<ArrowLeft />
|
|
||||||
<span>Back</span>
|
|
||||||
</div>
|
|
||||||
<p className="text-3xl font-semibold text-slate-600 dark:text-slate-200">
|
|
||||||
Appearance Settings
|
|
||||||
</p>
|
|
||||||
<p className="mt-2 text-sm font-base text-slate-600 dark:text-slate-200">
|
|
||||||
Customize the appearance settings of your platform.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="px-1 md:px-8 pb-10">
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<div className="flex flex-col gap-y-2">
|
<div className="flex flex-col gap-y-2">
|
||||||
<h2 className="leading-tight font-medium text-black dark:text-white">
|
<h2 className="leading-tight font-medium text-black dark:text-white">
|
||||||
@ -153,7 +134,7 @@ export default function Appearance() {
|
|||||||
Change the logo that appears in the sidebar.
|
Change the logo that appears in the sidebar.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center">
|
<div className="flex flex-col md:flex-row items-center">
|
||||||
<img
|
<img
|
||||||
src={logo}
|
src={logo}
|
||||||
alt="Uploaded Logo"
|
alt="Uploaded Logo"
|
||||||
@ -197,7 +178,7 @@ export default function Appearance() {
|
|||||||
Change the default messages that are displayed to the users.
|
Change the default messages that are displayed to the users.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-6 flex flex-col gap-y-6">
|
<div className="mt-6 flex flex-col gap-y-6 bg-white dark:bg-black-900 p-4 rounded-lg">
|
||||||
{messages.map((message, index) => (
|
{messages.map((message, index) => (
|
||||||
<div key={index} className="flex flex-col gap-y-2">
|
<div key={index} className="flex flex-col gap-y-2">
|
||||||
{message.user && (
|
{message.user && (
|
@ -61,7 +61,7 @@ export default function VectorDBSelection({
|
|||||||
<p className="block text-sm font-medium text-gray-800 dark:text-slate-200">
|
<p className="block text-sm font-medium text-gray-800 dark:text-slate-200">
|
||||||
Vector database providers
|
Vector database providers
|
||||||
</p>
|
</p>
|
||||||
<div className="w-full flex overflow-x-scroll gap-x-4">
|
<div className="w-full flex md:flex-wrap overflow-x-scroll gap-4">
|
||||||
<input hidden={true} name="VectorDB" value={vectorDB} />
|
<input hidden={true} name="VectorDB" value={vectorDB} />
|
||||||
<VectorDBOption
|
<VectorDBOption
|
||||||
name="Chroma"
|
name="Chroma"
|
||||||
|
@ -1,13 +1,5 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import {
|
import { X } from "react-feather";
|
||||||
Archive,
|
|
||||||
Lock,
|
|
||||||
X,
|
|
||||||
Users,
|
|
||||||
Database,
|
|
||||||
MessageSquare,
|
|
||||||
Eye,
|
|
||||||
} from "react-feather";
|
|
||||||
import ExportOrImportData from "./ExportImport";
|
import ExportOrImportData from "./ExportImport";
|
||||||
import PasswordProtection from "./PasswordProtection";
|
import PasswordProtection from "./PasswordProtection";
|
||||||
import System from "../../../models/system";
|
import System from "../../../models/system";
|
||||||
@ -15,23 +7,23 @@ import MultiUserMode from "./MultiUserMode";
|
|||||||
import useUser from "../../../hooks/useUser";
|
import useUser from "../../../hooks/useUser";
|
||||||
import VectorDBSelection from "./VectorDbs";
|
import VectorDBSelection from "./VectorDbs";
|
||||||
import LLMSelection from "./LLMSelection";
|
import LLMSelection from "./LLMSelection";
|
||||||
import paths from "../../../utils/paths";
|
import Appearance from "./Appearance";
|
||||||
|
|
||||||
const TABS = {
|
export const TABS = {
|
||||||
llm: LLMSelection,
|
llm: LLMSelection,
|
||||||
exportimport: ExportOrImportData,
|
exportimport: ExportOrImportData,
|
||||||
password: PasswordProtection,
|
password: PasswordProtection,
|
||||||
multiuser: MultiUserMode,
|
multiuser: MultiUserMode,
|
||||||
vectordb: VectorDBSelection,
|
vectordb: VectorDBSelection,
|
||||||
|
appearance: Appearance,
|
||||||
};
|
};
|
||||||
|
|
||||||
const noop = () => false;
|
const noop = () => false;
|
||||||
export default function SystemSettingsModal({ hideModal = noop }) {
|
export default function SystemSettingsModal({ tab = null, hideModal = noop }) {
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [selectedTab, setSelectedTab] = useState("llm");
|
|
||||||
const [settings, setSettings] = useState(null);
|
const [settings, setSettings] = useState(null);
|
||||||
const Component = TABS[selectedTab || "llm"];
|
const Component = TABS[tab || "llm"];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchKeys() {
|
async function fetchKeys() {
|
||||||
@ -64,12 +56,6 @@ export default function SystemSettingsModal({ hideModal = noop }) {
|
|||||||
<X className="text-gray-300 text-lg" />
|
<X className="text-gray-300 text-lg" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<SettingTabs
|
|
||||||
selectedTab={selectedTab}
|
|
||||||
changeTab={setSelectedTab}
|
|
||||||
settings={settings}
|
|
||||||
user={user}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="w-full flex h-[400px] p-6">
|
<div className="w-full flex h-[400px] p-6">
|
||||||
@ -84,92 +70,6 @@ export default function SystemSettingsModal({ hideModal = noop }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SettingTabs({ selectedTab, changeTab, settings, user }) {
|
|
||||||
if (!settings) {
|
|
||||||
return (
|
|
||||||
<div className="w-full flex h-[60px] pb-2">
|
|
||||||
<div className="w-full flex h-full bg-gray-200 dark:bg-stone-600 animate-pulse rounded-lg" />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ul className="flex overflow-x-scroll no-scroll -mb-px text-sm gap-x-2 font-medium text-center text-gray-500 dark:text-gray-400">
|
|
||||||
<SettingTab
|
|
||||||
active={selectedTab === "llm"}
|
|
||||||
displayName="LLM Choice"
|
|
||||||
tabName="llm"
|
|
||||||
icon={<MessageSquare className="h-4 w-4 flex-shrink-0" />}
|
|
||||||
onClick={changeTab}
|
|
||||||
/>
|
|
||||||
<SettingTab
|
|
||||||
active={selectedTab === "vectordb"}
|
|
||||||
displayName="Vector Database"
|
|
||||||
tabName="vectordb"
|
|
||||||
icon={<Database className="h-4 w-4 flex-shrink-0" />}
|
|
||||||
onClick={changeTab}
|
|
||||||
/>
|
|
||||||
<SettingTab
|
|
||||||
active={selectedTab === "exportimport"}
|
|
||||||
displayName="Export or Import"
|
|
||||||
tabName="exportimport"
|
|
||||||
icon={<Archive className="h-4 w-4 flex-shrink-0" />}
|
|
||||||
onClick={changeTab}
|
|
||||||
/>
|
|
||||||
{!settings?.MultiUserMode && (
|
|
||||||
<>
|
|
||||||
<SettingTab
|
|
||||||
active={selectedTab === "multiuser"}
|
|
||||||
displayName="Multi User Mode"
|
|
||||||
tabName="multiuser"
|
|
||||||
icon={<Users className="h-4 w-4 flex-shrink-0" />}
|
|
||||||
onClick={changeTab}
|
|
||||||
/>
|
|
||||||
<SettingTab
|
|
||||||
active={selectedTab === "password"}
|
|
||||||
displayName="Password Protection"
|
|
||||||
tabName="password"
|
|
||||||
icon={<Lock className="h-4 w-4 flex-shrink-0" />}
|
|
||||||
onClick={changeTab}
|
|
||||||
/>
|
|
||||||
<SettingTab
|
|
||||||
displayName="Appearance"
|
|
||||||
tabName="appearance"
|
|
||||||
icon={<Eye className="h-4 w-4 flex-shrink-0" />}
|
|
||||||
onClick={() => window.open(paths.appearance())}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</ul>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SettingTab({
|
|
||||||
active = false,
|
|
||||||
displayName,
|
|
||||||
tabName,
|
|
||||||
icon = "",
|
|
||||||
onClick,
|
|
||||||
}) {
|
|
||||||
const classes = active
|
|
||||||
? "text-blue-600 border-blue-600 active dark:text-blue-400 dark:border-blue-400 bg-blue-500 bg-opacity-5"
|
|
||||||
: "border-transparent hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300";
|
|
||||||
return (
|
|
||||||
<li className="mr-2">
|
|
||||||
<button
|
|
||||||
disabled={active}
|
|
||||||
onClick={() => onClick(tabName)}
|
|
||||||
className={
|
|
||||||
"flex items-center gap-x-1 p-4 border-b-2 rounded-t-lg group whitespace-nowrap " +
|
|
||||||
classes
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{icon} {displayName}
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useSystemSettingsModal() {
|
export function useSystemSettingsModal() {
|
||||||
const [showing, setShowing] = useState(false);
|
const [showing, setShowing] = useState(false);
|
||||||
const showModal = () => {
|
const showModal = () => {
|
||||||
|
181
frontend/src/components/Sidebar/SettingsOverlay/index.jsx
Normal file
181
frontend/src/components/Sidebar/SettingsOverlay/index.jsx
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import {
|
||||||
|
X,
|
||||||
|
Archive,
|
||||||
|
Lock,
|
||||||
|
Users,
|
||||||
|
Database,
|
||||||
|
MessageSquare,
|
||||||
|
Eye,
|
||||||
|
} from "react-feather";
|
||||||
|
import SystemSettingsModal, {
|
||||||
|
useSystemSettingsModal,
|
||||||
|
} from "../../Modals/Settings";
|
||||||
|
import useLogo from "../../../hooks/useLogo";
|
||||||
|
import System from "../../../models/system";
|
||||||
|
|
||||||
|
const OVERLAY_ID = "anything-llm-system-overlay";
|
||||||
|
const OVERLAY_CLASSES = {
|
||||||
|
enabled: ["z-10", "opacity-1"],
|
||||||
|
disabled: ["-z-10", "opacity-0"],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function SettingsOverlay() {
|
||||||
|
const { logo } = useLogo();
|
||||||
|
const [tab, setTab] = useState(null);
|
||||||
|
const [settings, setSettings] = useState(null);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const { showing, hideModal, showModal } = useSystemSettingsModal();
|
||||||
|
const selectTab = (tab = null) => {
|
||||||
|
setTab(tab);
|
||||||
|
showModal(true);
|
||||||
|
};
|
||||||
|
const handleModalClose = () => {
|
||||||
|
hideModal();
|
||||||
|
setTab(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchKeys() {
|
||||||
|
const _settings = await System.keys();
|
||||||
|
setSettings(_settings);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
fetchKeys();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
id={OVERLAY_ID}
|
||||||
|
className="absolute left-0 rounded-[26px] top-0 w-full h-full opacity-0 -z-10 p-[18px] transition-all duration-300 bg-white dark:bg-black-900 flex flex-col overflow-x-hidden items-between"
|
||||||
|
>
|
||||||
|
<div className="flex w-full items-center justify-between">
|
||||||
|
<div className="flex shrink-0 max-w-[50%] items-center justify-start">
|
||||||
|
<img
|
||||||
|
src={logo}
|
||||||
|
alt="Logo"
|
||||||
|
className="rounded max-h-[40px]"
|
||||||
|
style={{ objectFit: "contain" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-x-2 items-center text-slate-500">
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
setTab(null);
|
||||||
|
hideOverlay();
|
||||||
|
}}
|
||||||
|
className="transition-all duration-300 p-2 rounded-full bg-slate-200 text-slate-400 dark:bg-stone-800 hover:bg-slate-800 hover:text-slate-200 dark:hover:text-slate-200"
|
||||||
|
>
|
||||||
|
<X className="h-4 w-4 " />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="h-[100%] flex flex-col w-full justify-between pt-4 overflow-y-hidden">
|
||||||
|
<div className="h-auto sidebar-items dark:sidebar-items">
|
||||||
|
<p className="text-sm leading-loose my-2 text-slate-800 dark:text-slate-200 ">
|
||||||
|
Select a setting to configure
|
||||||
|
</p>
|
||||||
|
{loading ? (
|
||||||
|
<div className="flex flex-col gap-y-4 h-[65vh] pb-8 overflow-y-scroll no-scroll">
|
||||||
|
<div className="rounded-lg w-[90%] h-[36px] bg-stone-600 animate-pulse" />
|
||||||
|
<div className="rounded-lg w-[90%] h-[36px] bg-stone-600 animate-pulse" />
|
||||||
|
<div className="rounded-lg w-[90%] h-[36px] bg-stone-600 animate-pulse" />
|
||||||
|
<div className="rounded-lg w-[90%] h-[36px] bg-stone-600 animate-pulse" />
|
||||||
|
<div className="rounded-lg w-[90%] h-[36px] bg-stone-600 animate-pulse" />
|
||||||
|
<div className="rounded-lg w-[90%] h-[36px] bg-stone-600 animate-pulse" />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex flex-col gap-y-4 h-[65vh] pb-8 overflow-y-scroll no-scroll">
|
||||||
|
{!settings?.MultiUserMode && (
|
||||||
|
<Option
|
||||||
|
btnText="Appearance"
|
||||||
|
icon={<Eye className="h-4 w-4 flex-shrink-0" />}
|
||||||
|
isActive={tab === "appearance"}
|
||||||
|
onClick={() => selectTab("appearance")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Option
|
||||||
|
btnText="LLM Preference"
|
||||||
|
icon={<MessageSquare className="h-4 w-4 flex-shrink-0" />}
|
||||||
|
isActive={tab === "llm"}
|
||||||
|
onClick={() => selectTab("llm")}
|
||||||
|
/>
|
||||||
|
<Option
|
||||||
|
btnText="Vector Database"
|
||||||
|
icon={<Database className="h-4 w-4 flex-shrink-0" />}
|
||||||
|
isActive={tab === "vectordb"}
|
||||||
|
onClick={() => selectTab("vectordb")}
|
||||||
|
/>
|
||||||
|
<Option
|
||||||
|
btnText="Export or Import"
|
||||||
|
icon={<Archive className="h-4 w-4 flex-shrink-0" />}
|
||||||
|
isActive={tab === "exportimport"}
|
||||||
|
onClick={() => selectTab("exportimport")}
|
||||||
|
/>
|
||||||
|
{!settings?.MultiUserMode && (
|
||||||
|
<>
|
||||||
|
<Option
|
||||||
|
btnText="Password Protection"
|
||||||
|
icon={<Lock className="h-4 w-4 flex-shrink-0" />}
|
||||||
|
isActive={tab === "password"}
|
||||||
|
onClick={() => selectTab("password")}
|
||||||
|
/>
|
||||||
|
<Option
|
||||||
|
btnText="Multi User Mode"
|
||||||
|
icon={<Users className="h-4 w-4 flex-shrink-0" />}
|
||||||
|
isActive={tab === "multiuser"}
|
||||||
|
onClick={() => selectTab("multiuser")}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{showing && !!tab && (
|
||||||
|
<SystemSettingsModal tab={tab} hideModal={handleModalClose} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Option = ({ btnText, icon, isActive, onClick }) => {
|
||||||
|
return (
|
||||||
|
<div className="flex gap-x-2 items-center justify-between">
|
||||||
|
<button
|
||||||
|
onClick={onClick}
|
||||||
|
className={`flex flex-grow w-[75%] h-[36px] gap-x-2 py-[5px] px-4 border border-slate-400 rounded-lg text-slate-800 dark:text-slate-200 justify-start items-center ${
|
||||||
|
isActive
|
||||||
|
? "bg-gray-100 dark:bg-stone-600"
|
||||||
|
: "hover:bg-slate-100 dark:hover:bg-stone-900 "
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
<p className="text-slate-800 dark:text-slate-200 text-xs leading-loose font-semibold whitespace-nowrap overflow-hidden ">
|
||||||
|
{btnText}
|
||||||
|
</p>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
function showOverlay() {
|
||||||
|
document
|
||||||
|
.getElementById(OVERLAY_ID)
|
||||||
|
.classList.remove(...OVERLAY_CLASSES.disabled);
|
||||||
|
document.getElementById(OVERLAY_ID).classList.add(...OVERLAY_CLASSES.enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideOverlay() {
|
||||||
|
document
|
||||||
|
.getElementById(OVERLAY_ID)
|
||||||
|
.classList.remove(...OVERLAY_CLASSES.enabled);
|
||||||
|
document
|
||||||
|
.getElementById(OVERLAY_ID)
|
||||||
|
.classList.add(...OVERLAY_CLASSES.disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useSystemSettingsOverlay() {
|
||||||
|
return { showOverlay, hideOverlay };
|
||||||
|
}
|
@ -2,8 +2,6 @@ import React, { useEffect, useRef, useState } from "react";
|
|||||||
import {
|
import {
|
||||||
AtSign,
|
AtSign,
|
||||||
BookOpen,
|
BookOpen,
|
||||||
Briefcase,
|
|
||||||
Cpu,
|
|
||||||
GitHub,
|
GitHub,
|
||||||
LogOut,
|
LogOut,
|
||||||
Menu,
|
Menu,
|
||||||
@ -11,12 +9,10 @@ import {
|
|||||||
Plus,
|
Plus,
|
||||||
Shield,
|
Shield,
|
||||||
Tool,
|
Tool,
|
||||||
|
X,
|
||||||
} from "react-feather";
|
} from "react-feather";
|
||||||
import IndexCount from "./IndexCount";
|
import IndexCount from "./IndexCount";
|
||||||
import LLMStatus from "./LLMStatus";
|
import LLMStatus from "./LLMStatus";
|
||||||
import SystemSettingsModal, {
|
|
||||||
useSystemSettingsModal,
|
|
||||||
} from "../Modals/Settings";
|
|
||||||
import NewWorkspaceModal, {
|
import NewWorkspaceModal, {
|
||||||
useNewWorkspaceModal,
|
useNewWorkspaceModal,
|
||||||
} from "../Modals/NewWorkspace";
|
} from "../Modals/NewWorkspace";
|
||||||
@ -27,15 +23,12 @@ import useUser from "../../hooks/useUser";
|
|||||||
import { userFromStorage } from "../../utils/request";
|
import { userFromStorage } from "../../utils/request";
|
||||||
import { AUTH_TOKEN, AUTH_USER } from "../../utils/constants";
|
import { AUTH_TOKEN, AUTH_USER } from "../../utils/constants";
|
||||||
import useLogo from "../../hooks/useLogo";
|
import useLogo from "../../hooks/useLogo";
|
||||||
|
import SettingsOverlay, { useSystemSettingsOverlay } from "./SettingsOverlay";
|
||||||
|
|
||||||
export default function Sidebar() {
|
export default function Sidebar() {
|
||||||
const { logo } = useLogo();
|
const { logo } = useLogo();
|
||||||
const sidebarRef = useRef(null);
|
const sidebarRef = useRef(null);
|
||||||
const {
|
const { showOverlay } = useSystemSettingsOverlay();
|
||||||
showing: showingSystemSettingsModal,
|
|
||||||
showModal: showSystemSettingsModal,
|
|
||||||
hideModal: hideSystemSettingsModal,
|
|
||||||
} = useSystemSettingsModal();
|
|
||||||
const {
|
const {
|
||||||
showing: showingNewWsModal,
|
showing: showingNewWsModal,
|
||||||
showModal: showNewWsModal,
|
showModal: showNewWsModal,
|
||||||
@ -47,8 +40,9 @@ export default function Sidebar() {
|
|||||||
<div
|
<div
|
||||||
ref={sidebarRef}
|
ref={sidebarRef}
|
||||||
style={{ height: "calc(100% - 32px)" }}
|
style={{ height: "calc(100% - 32px)" }}
|
||||||
className="transition-all duration-500 relative m-[16px] rounded-[26px] bg-white dark:bg-black-900 min-w-[15.5%] p-[18px] "
|
className="relative transition-all duration-500 relative m-[16px] rounded-[26px] bg-white dark:bg-black-900 min-w-[15.5%] p-[18px] "
|
||||||
>
|
>
|
||||||
|
<SettingsOverlay />
|
||||||
<div className="w-full h-full flex flex-col overflow-x-hidden items-between">
|
<div className="w-full h-full flex flex-col overflow-x-hidden items-between">
|
||||||
{/* Header Information */}
|
{/* Header Information */}
|
||||||
<div className="flex w-full items-center justify-between">
|
<div className="flex w-full items-center justify-between">
|
||||||
@ -62,12 +56,7 @@ export default function Sidebar() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex gap-x-2 items-center text-slate-500">
|
<div className="flex gap-x-2 items-center text-slate-500">
|
||||||
<AdminHome />
|
<AdminHome />
|
||||||
<button
|
<SettingsButton onClick={showOverlay} />
|
||||||
onClick={showSystemSettingsModal}
|
|
||||||
className="transition-all duration-300 p-2 rounded-full bg-slate-200 text-slate-400 dark:bg-stone-800 hover:bg-slate-800 hover:text-slate-200 dark:hover:text-slate-200"
|
|
||||||
>
|
|
||||||
<Tool className="h-4 w-4 " />
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -142,9 +131,6 @@ export default function Sidebar() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{showingSystemSettingsModal && (
|
|
||||||
<SystemSettingsModal hideModal={hideSystemSettingsModal} />
|
|
||||||
)}
|
|
||||||
{showingNewWsModal && <NewWorkspaceModal hideModal={hideNewWsModal} />}
|
{showingNewWsModal && <NewWorkspaceModal hideModal={hideNewWsModal} />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@ -155,11 +141,7 @@ export function SidebarMobileHeader() {
|
|||||||
const sidebarRef = useRef(null);
|
const sidebarRef = useRef(null);
|
||||||
const [showSidebar, setShowSidebar] = useState(false);
|
const [showSidebar, setShowSidebar] = useState(false);
|
||||||
const [showBgOverlay, setShowBgOverlay] = useState(false);
|
const [showBgOverlay, setShowBgOverlay] = useState(false);
|
||||||
const {
|
const { showOverlay } = useSystemSettingsOverlay();
|
||||||
showing: showingSystemSettingsModal,
|
|
||||||
showModal: showSystemSettingsModal,
|
|
||||||
hideModal: hideSystemSettingsModal,
|
|
||||||
} = useSystemSettingsModal();
|
|
||||||
const {
|
const {
|
||||||
showing: showingNewWsModal,
|
showing: showingNewWsModal,
|
||||||
showModal: showNewWsModal,
|
showModal: showNewWsModal,
|
||||||
@ -167,6 +149,8 @@ export function SidebarMobileHeader() {
|
|||||||
} = useNewWorkspaceModal();
|
} = useNewWorkspaceModal();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// Darkens the rest of the screen
|
||||||
|
// when sidebar is open.
|
||||||
function handleBg() {
|
function handleBg() {
|
||||||
if (showSidebar) {
|
if (showSidebar) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -213,12 +197,13 @@ export function SidebarMobileHeader() {
|
|||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
ref={sidebarRef}
|
ref={sidebarRef}
|
||||||
className="h-[100vh] fixed top-0 left-0 rounded-r-[26px] bg-white dark:bg-black-900 w-[70%] p-[18px] "
|
className="relative h-[100vh] fixed top-0 left-0 rounded-r-[26px] bg-white dark:bg-black-900 w-[80%] p-[18px] "
|
||||||
>
|
>
|
||||||
|
<SettingsOverlay />
|
||||||
<div className="w-full h-full flex flex-col overflow-x-hidden items-between">
|
<div className="w-full h-full flex flex-col overflow-x-hidden items-between">
|
||||||
{/* Header Information */}
|
{/* Header Information */}
|
||||||
<div className="flex w-full items-center justify-between">
|
<div className="flex w-full items-center justify-between gap-x-4">
|
||||||
<div className="flex shrink-0 w-fit items-center justify-start">
|
<div className="flex shrink-1 w-fit items-center justify-start">
|
||||||
<img
|
<img
|
||||||
src={logo}
|
src={logo}
|
||||||
alt="Logo"
|
alt="Logo"
|
||||||
@ -226,14 +211,9 @@ export function SidebarMobileHeader() {
|
|||||||
style={{ objectFit: "contain" }}
|
style={{ objectFit: "contain" }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-x-2 items-center text-slate-500">
|
<div className="flex gap-x-2 items-center text-slate-500 shink-0">
|
||||||
<AdminHome />
|
<AdminHome />
|
||||||
<button
|
<SettingsButton onClick={showOverlay} />
|
||||||
onClick={showSystemSettingsModal}
|
|
||||||
className="transition-all duration-300 p-2 rounded-full bg-slate-200 text-slate-400 dark:bg-stone-800 hover:bg-slate-800 hover:text-slate-200 dark:hover:text-slate-200"
|
|
||||||
>
|
|
||||||
<Tool className="h-4 w-4 " />
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -311,9 +291,6 @@ export function SidebarMobileHeader() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{showingSystemSettingsModal && (
|
|
||||||
<SystemSettingsModal hideModal={hideSystemSettingsModal} />
|
|
||||||
)}
|
|
||||||
{showingNewWsModal && <NewWorkspaceModal hideModal={hideNewWsModal} />}
|
{showingNewWsModal && <NewWorkspaceModal hideModal={hideNewWsModal} />}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@ -355,6 +332,19 @@ function LogoutButton() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SettingsButton({ onClick }) {
|
||||||
|
const { user } = useUser();
|
||||||
|
if (!!user) return null;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={onClick}
|
||||||
|
className="transition-all duration-300 p-2 rounded-full bg-slate-200 text-slate-400 dark:bg-stone-800 hover:bg-slate-800 hover:text-slate-200 dark:hover:text-slate-200"
|
||||||
|
>
|
||||||
|
<Tool className="h-4 w-4 " />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function ManagedHosting() {
|
function ManagedHosting() {
|
||||||
if (window.location.origin.includes(".useanything.com")) return null;
|
if (window.location.origin.includes(".useanything.com")) return null;
|
||||||
return (
|
return (
|
||||||
|
@ -142,7 +142,7 @@ export default function Appearance() {
|
|||||||
Change the logo that appears in the sidebar.
|
Change the logo that appears in the sidebar.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center">
|
<div className="flex md:flex-row flex-col items-center">
|
||||||
<img
|
<img
|
||||||
src={logo}
|
src={logo}
|
||||||
alt="Uploaded Logo"
|
alt="Uploaded Logo"
|
||||||
|
@ -22,9 +22,6 @@ export default {
|
|||||||
feedback: () => {
|
feedback: () => {
|
||||||
return "https://mintplexlabs.typeform.com/to/i0KE3aEW";
|
return "https://mintplexlabs.typeform.com/to/i0KE3aEW";
|
||||||
},
|
},
|
||||||
appearance: () => {
|
|
||||||
return "/system/appearance";
|
|
||||||
},
|
|
||||||
workspace: {
|
workspace: {
|
||||||
chat: (slug) => {
|
chat: (slug) => {
|
||||||
return `/workspace/${slug}`;
|
return `/workspace/${slug}`;
|
||||||
|
Loading…
Reference in New Issue
Block a user