mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2024-11-19 12:40:09 +01:00
Dark mode setup themes (#2411)
* setup generic tailwind theme + ability to add new themes * add theme context * use correct colors from design for sidebar + fix padding
This commit is contained in:
parent
cbc4e80d31
commit
d0546a47df
@ -15,6 +15,7 @@ import i18n from "./i18n";
|
||||
import { PfpProvider } from "./PfpContext";
|
||||
import { LogoProvider } from "./LogoContext";
|
||||
import { FullScreenLoader } from "./components/Preloader";
|
||||
import { ThemeProvider } from "./ThemeContext";
|
||||
|
||||
const Main = lazy(() => import("@/pages/Main"));
|
||||
const InvitePage = lazy(() => import("@/pages/Invite"));
|
||||
@ -75,132 +76,139 @@ export default function App() {
|
||||
<LogoProvider>
|
||||
<PfpProvider>
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<Routes>
|
||||
<Route path="/" element={<PrivateRoute Component={Main} />} />
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route
|
||||
path="/workspace/:slug/settings/:tab"
|
||||
element={<ManagerRoute Component={WorkspaceSettings} />}
|
||||
/>
|
||||
<Route
|
||||
path="/workspace/:slug"
|
||||
element={<PrivateRoute Component={WorkspaceChat} />}
|
||||
/>
|
||||
<Route
|
||||
path="/workspace/:slug/t/:threadSlug"
|
||||
element={<PrivateRoute Component={WorkspaceChat} />}
|
||||
/>
|
||||
<Route path="/accept-invite/:code" element={<InvitePage />} />
|
||||
<ThemeProvider>
|
||||
<Routes>
|
||||
<Route path="/" element={<PrivateRoute Component={Main} />} />
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route
|
||||
path="/workspace/:slug/settings/:tab"
|
||||
element={<ManagerRoute Component={WorkspaceSettings} />}
|
||||
/>
|
||||
<Route
|
||||
path="/workspace/:slug"
|
||||
element={<PrivateRoute Component={WorkspaceChat} />}
|
||||
/>
|
||||
<Route
|
||||
path="/workspace/:slug/t/:threadSlug"
|
||||
element={<PrivateRoute Component={WorkspaceChat} />}
|
||||
/>
|
||||
<Route path="/accept-invite/:code" element={<InvitePage />} />
|
||||
|
||||
{/* Admin */}
|
||||
<Route
|
||||
path="/settings/llm-preference"
|
||||
element={<AdminRoute Component={GeneralLLMPreference} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/transcription-preference"
|
||||
element={
|
||||
<AdminRoute Component={GeneralTranscriptionPreference} />
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/audio-preference"
|
||||
element={<AdminRoute Component={GeneralAudioPreference} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/embedding-preference"
|
||||
element={
|
||||
<AdminRoute Component={GeneralEmbeddingPreference} />
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/text-splitter-preference"
|
||||
element={
|
||||
<AdminRoute Component={EmbeddingTextSplitterPreference} />
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/vector-database"
|
||||
element={<AdminRoute Component={GeneralVectorDatabase} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/agents"
|
||||
element={<AdminRoute Component={AdminAgents} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/event-logs"
|
||||
element={<AdminRoute Component={AdminLogs} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/embed-config"
|
||||
element={<AdminRoute Component={EmbedConfigSetup} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/embed-chats"
|
||||
element={<AdminRoute Component={EmbedChats} />}
|
||||
/>
|
||||
{/* Manager */}
|
||||
<Route
|
||||
path="/settings/security"
|
||||
element={<ManagerRoute Component={GeneralSecurity} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/privacy"
|
||||
element={<AdminRoute Component={PrivacyAndData} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/appearance"
|
||||
element={<ManagerRoute Component={GeneralAppearance} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/beta-features"
|
||||
element={<AdminRoute Component={ExperimentalFeatures} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/api-keys"
|
||||
element={<AdminRoute Component={GeneralApiKeys} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/browser-extension"
|
||||
element={<ManagerRoute Component={GeneralBrowserExtension} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/workspace-chats"
|
||||
element={<ManagerRoute Component={GeneralChats} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/system-preferences"
|
||||
element={<ManagerRoute Component={AdminSystem} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/invites"
|
||||
element={<ManagerRoute Component={AdminInvites} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/users"
|
||||
element={<ManagerRoute Component={AdminUsers} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/workspaces"
|
||||
element={<ManagerRoute Component={AdminWorkspaces} />}
|
||||
/>
|
||||
{/* Onboarding Flow */}
|
||||
<Route path="/onboarding" element={<OnboardingFlow />} />
|
||||
<Route path="/onboarding/:step" element={<OnboardingFlow />} />
|
||||
{/* Admin */}
|
||||
<Route
|
||||
path="/settings/llm-preference"
|
||||
element={<AdminRoute Component={GeneralLLMPreference} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/transcription-preference"
|
||||
element={
|
||||
<AdminRoute Component={GeneralTranscriptionPreference} />
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/audio-preference"
|
||||
element={<AdminRoute Component={GeneralAudioPreference} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/embedding-preference"
|
||||
element={
|
||||
<AdminRoute Component={GeneralEmbeddingPreference} />
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/text-splitter-preference"
|
||||
element={
|
||||
<AdminRoute Component={EmbeddingTextSplitterPreference} />
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/vector-database"
|
||||
element={<AdminRoute Component={GeneralVectorDatabase} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/agents"
|
||||
element={<AdminRoute Component={AdminAgents} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/event-logs"
|
||||
element={<AdminRoute Component={AdminLogs} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/embed-config"
|
||||
element={<AdminRoute Component={EmbedConfigSetup} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/embed-chats"
|
||||
element={<AdminRoute Component={EmbedChats} />}
|
||||
/>
|
||||
{/* Manager */}
|
||||
<Route
|
||||
path="/settings/security"
|
||||
element={<ManagerRoute Component={GeneralSecurity} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/privacy"
|
||||
element={<AdminRoute Component={PrivacyAndData} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/appearance"
|
||||
element={<ManagerRoute Component={GeneralAppearance} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/beta-features"
|
||||
element={<AdminRoute Component={ExperimentalFeatures} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/api-keys"
|
||||
element={<AdminRoute Component={GeneralApiKeys} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/browser-extension"
|
||||
element={
|
||||
<ManagerRoute Component={GeneralBrowserExtension} />
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/workspace-chats"
|
||||
element={<ManagerRoute Component={GeneralChats} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/system-preferences"
|
||||
element={<ManagerRoute Component={AdminSystem} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/invites"
|
||||
element={<ManagerRoute Component={AdminInvites} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/users"
|
||||
element={<ManagerRoute Component={AdminUsers} />}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/workspaces"
|
||||
element={<ManagerRoute Component={AdminWorkspaces} />}
|
||||
/>
|
||||
{/* Onboarding Flow */}
|
||||
<Route path="/onboarding" element={<OnboardingFlow />} />
|
||||
<Route
|
||||
path="/onboarding/:step"
|
||||
element={<OnboardingFlow />}
|
||||
/>
|
||||
|
||||
{/* Experimental feature pages */}
|
||||
{/* Live Document Sync feature */}
|
||||
<Route
|
||||
path="/settings/beta-features/live-document-sync/manage"
|
||||
element={<AdminRoute Component={LiveDocumentSyncManage} />}
|
||||
/>
|
||||
{/* Experimental feature pages */}
|
||||
{/* Live Document Sync feature */}
|
||||
<Route
|
||||
path="/settings/beta-features/live-document-sync/manage"
|
||||
element={<AdminRoute Component={LiveDocumentSyncManage} />}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path="/fine-tuning"
|
||||
element={<AdminRoute Component={FineTuningWalkthrough} />}
|
||||
/>
|
||||
</Routes>
|
||||
<ToastContainer />
|
||||
<Route
|
||||
path="/fine-tuning"
|
||||
element={<AdminRoute Component={FineTuningWalkthrough} />}
|
||||
/>
|
||||
</Routes>
|
||||
<ToastContainer />
|
||||
</ThemeProvider>
|
||||
</I18nextProvider>
|
||||
</PfpProvider>
|
||||
</LogoProvider>
|
||||
|
16
frontend/src/ThemeContext.jsx
Normal file
16
frontend/src/ThemeContext.jsx
Normal file
@ -0,0 +1,16 @@
|
||||
import React, { createContext, useContext } from "react";
|
||||
import { useTheme } from "./hooks/useTheme";
|
||||
|
||||
const ThemeContext = createContext();
|
||||
|
||||
export function ThemeProvider({ children }) {
|
||||
const themeValue = useTheme();
|
||||
|
||||
return (
|
||||
<ThemeContext.Provider value={themeValue}>{children}</ThemeContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useThemeContext() {
|
||||
return useContext(ThemeContext);
|
||||
}
|
@ -54,7 +54,7 @@ export default function Footer() {
|
||||
href={paths.github()}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="transition-all duration-300 p-2 rounded-full text-white bg-footer-icon hover:bg-footer-icon-hover"
|
||||
className="transition-all duration-300 p-2 rounded-full text-white bg-theme-sidebar-footer-icon hover:bg-theme-sidebar-footer-icon-hover"
|
||||
aria-label="Find us on Github"
|
||||
data-tooltip-id="open-github"
|
||||
data-tooltip-content="View source code on Github"
|
||||
@ -67,7 +67,7 @@ export default function Footer() {
|
||||
href={paths.docs()}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="transition-all duration-300 p-2 rounded-full text-white bg-footer-icon hover:bg-footer-icon-hover"
|
||||
className="transition-all duration-300 p-2 rounded-full text-white bg-theme-sidebar-footer-icon hover:bg-theme-sidebar-footer-icon-hover"
|
||||
aria-label="Docs"
|
||||
data-tooltip-id="open-documentation"
|
||||
data-tooltip-content="Open AnythingLLM help docs"
|
||||
@ -80,7 +80,7 @@ export default function Footer() {
|
||||
href={paths.discord()}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="transition-all duration-300 p-2 rounded-full text-white bg-footer-icon hover:bg-footer-icon-hover"
|
||||
className="transition-all duration-300 p-2 rounded-full text-white bg-theme-sidebar-footer-icon hover:bg-theme-sidebar-footer-icon-hover"
|
||||
aria-label="Join our Discord server"
|
||||
data-tooltip-id="open-discord"
|
||||
data-tooltip-content="Join the AnythingLLM Discord"
|
||||
@ -106,7 +106,7 @@ export default function Footer() {
|
||||
href={item.url}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="transition-all duration-300 p-2 rounded-full text-white bg-footer-icon hover:bg-footer-icon-hover"
|
||||
className="transition-all duration-300 p-2 rounded-full text-white bg-theme-sidebar-footer-icon hover:bg-theme-sidebar-footer-icon-hover"
|
||||
>
|
||||
{React.createElement(
|
||||
ICON_COMPONENTS?.[item.icon] ?? ICON_COMPONENTS.Info,
|
||||
|
@ -16,7 +16,7 @@ export default function SettingsButton() {
|
||||
<ToolTipWrapper id="go-home">
|
||||
<Link
|
||||
to={paths.home()}
|
||||
className="transition-all duration-300 p-2 rounded-full text-white bg-footer-icon hover:bg-footer-icon-hover"
|
||||
className="transition-all duration-300 p-2 rounded-full text-white bg-theme-sidebar-footer-icon hover:bg-theme-sidebar-footer-icon-hover"
|
||||
aria-label="Home"
|
||||
data-tooltip-id="go-home"
|
||||
data-tooltip-content="Back to workspaces"
|
||||
@ -32,7 +32,7 @@ export default function SettingsButton() {
|
||||
to={
|
||||
!!user?.role ? paths.settings.system() : paths.settings.appearance()
|
||||
}
|
||||
className="transition-all duration-300 p-2 rounded-full text-white bg-footer-icon hover:bg-footer-icon-hover"
|
||||
className="transition-all duration-300 p-2 rounded-full text-white bg-theme-sidebar-footer-icon hover:bg-theme-sidebar-footer-icon-hover"
|
||||
aria-label="Settings"
|
||||
data-tooltip-id="open-settings"
|
||||
data-tooltip-content="Open settings"
|
||||
|
@ -33,7 +33,7 @@ export default function ThreadItem({
|
||||
|
||||
return (
|
||||
<div
|
||||
className="w-full relative flex h-[38px] items-center border-none hover:bg-slate-600/20 rounded-lg"
|
||||
className="w-full relative flex h-[38px] items-center border-none rounded-lg"
|
||||
role="listitem"
|
||||
>
|
||||
{/* Curved line Element and leader if required */}
|
||||
@ -41,9 +41,9 @@ export default function ThreadItem({
|
||||
style={{ width: THREAD_CALLOUT_DETAIL_WIDTH / 2 }}
|
||||
className={`${
|
||||
isActive
|
||||
? "border-l-2 border-b-2 border-white"
|
||||
: "border-l border-b border-slate-300"
|
||||
} h-[50%] absolute top-0 z-10 left-2 rounded-bl-lg`}
|
||||
? "border-l-2 border-b-2 border-white z-30"
|
||||
: "border-l border-b border-[#6F6F71] z-10"
|
||||
} h-[50%] absolute top-0 left-2 rounded-bl-lg`}
|
||||
></div>
|
||||
{/* Downstroke border for next item */}
|
||||
{hasNext && (
|
||||
@ -51,9 +51,9 @@ export default function ThreadItem({
|
||||
style={{ width: THREAD_CALLOUT_DETAIL_WIDTH / 2 }}
|
||||
className={`${
|
||||
idx <= activeIdx && !isActive
|
||||
? "border-l-2 border-white"
|
||||
: "border-l border-slate-300"
|
||||
} h-[100%] absolute top-0 z-1 left-2`}
|
||||
? "border-l-2 border-white z-20"
|
||||
: "border-l border-[#6F6F71] z-10"
|
||||
} h-[100%] absolute top-0 left-2`}
|
||||
></div>
|
||||
)}
|
||||
|
||||
@ -62,10 +62,10 @@ export default function ThreadItem({
|
||||
style={{ width: THREAD_CALLOUT_DETAIL_WIDTH + 8 }}
|
||||
className="h-full"
|
||||
/>
|
||||
<div className="flex w-full items-center justify-between pr-2 group relative">
|
||||
<div className={`flex w-full items-center justify-between pr-2 group relative ${isActive ? 'bg-white/5' : 'hover:bg-white/5'} rounded-[4px]`}>
|
||||
{thread.deleted ? (
|
||||
<div className="w-full flex justify-between">
|
||||
<div className="w-full ">
|
||||
<div className="w-full pl-2 py-1">
|
||||
<p className={`text-left text-sm text-slate-400/50 italic`}>
|
||||
deleted thread
|
||||
</p>
|
||||
@ -88,12 +88,12 @@ export default function ThreadItem({
|
||||
href={
|
||||
window.location.pathname === linkTo || ctrlPressed ? "#" : linkTo
|
||||
}
|
||||
className="w-full"
|
||||
className="w-full pl-2 py-1"
|
||||
aria-current={isActive ? "page" : ""}
|
||||
>
|
||||
<p
|
||||
className={`text-left text-sm ${
|
||||
isActive ? "font-medium text-white" : "text-slate-400"
|
||||
isActive ? "font-medium text-white" : "text-white/40"
|
||||
}`}
|
||||
>
|
||||
{truncate(thread.name, 25)}
|
||||
@ -101,7 +101,7 @@ export default function ThreadItem({
|
||||
</a>
|
||||
)}
|
||||
{!!thread.slug && !thread.deleted && (
|
||||
<div ref={optionsContainer}>
|
||||
<div ref={optionsContainer} className="flex items-center"> {/* Added flex and items-center */}
|
||||
{ctrlPressed ? (
|
||||
<button
|
||||
type="button"
|
||||
|
@ -107,7 +107,7 @@ export default function ThreadContainer({ workspace }) {
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex flex-col bg-pulse w-full h-10 items-center justify-center">
|
||||
<p className="text-xs text-slate-600 animate-pulse">
|
||||
<p className="text-xs text-white animate-pulse">
|
||||
loading threads....
|
||||
</p>
|
||||
</div>
|
||||
@ -171,25 +171,25 @@ function NewThreadButton({ workspace }) {
|
||||
return (
|
||||
<button
|
||||
onClick={onClick}
|
||||
className="w-full relative flex h-[40px] items-center border-none hover:bg-slate-600/20 rounded-lg"
|
||||
className="w-full relative flex h-[40px] items-center border-none hover:bg-white/5 rounded-lg"
|
||||
>
|
||||
<div className="flex w-full gap-x-2 items-center pl-4">
|
||||
<div className="bg-zinc-600 p-2 rounded-lg h-[24px] w-[24px] flex items-center justify-center">
|
||||
<div className="bg-white/20 p-2 rounded-lg h-[24px] w-[24px] flex items-center justify-center">
|
||||
{loading ? (
|
||||
<CircleNotch
|
||||
weight="bold"
|
||||
size={14}
|
||||
className="shrink-0 animate-spin text-slate-100"
|
||||
className="shrink-0 animate-spin text-white"
|
||||
/>
|
||||
) : (
|
||||
<Plus weight="bold" size={14} className="shrink-0 text-slate-100" />
|
||||
<Plus weight="bold" size={14} className="shrink-0 text-white" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{loading ? (
|
||||
<p className="text-left text-slate-100 text-sm">Starting Thread...</p>
|
||||
<p className="text-left text-white text-sm">Starting Thread...</p>
|
||||
) : (
|
||||
<p className="text-left text-slate-100 text-sm">New Thread</p>
|
||||
<p className="text-left text-white text-sm">New Thread</p>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
@ -210,7 +210,7 @@ function DeleteAllThreadButton({ ctrlPressed, threads, onDelete }) {
|
||||
<Trash
|
||||
weight="bold"
|
||||
size={14}
|
||||
className="shrink-0 text-slate-100 group-hover:text-red-400"
|
||||
className="shrink-0 text-white group-hover:text-red-400"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-white text-left text-sm group-hover:text-red-400">
|
||||
|
@ -60,9 +60,9 @@ export default function ActiveWorkspaces() {
|
||||
className={`
|
||||
transition-all duration-[200ms]
|
||||
flex flex-grow w-[75%] gap-x-2 py-[6px] px-[12px] rounded-[4px] text-white justify-start items-center
|
||||
bg-workspace-item-default
|
||||
hover:bg-workspace-item-hover hover:font-bold
|
||||
${isActive ? "bg-workspace-item-selected font-bold" : ""}
|
||||
bg-theme-sidebar-item-default
|
||||
hover:bg-theme-sidebar-item-hover hover:font-bold
|
||||
${isActive ? "bg-theme-sidebar-item-selected font-bold" : ""}
|
||||
`}
|
||||
>
|
||||
<div className="flex flex-row justify-between w-full">
|
||||
|
@ -39,7 +39,7 @@ export default function Sidebar() {
|
||||
</Link>
|
||||
<div
|
||||
ref={sidebarRef}
|
||||
className="relative m-[16px] rounded-[16px] bg-sidebar-bg border-[2px] border-sidebar-border min-w-[250px] p-[10px] h-[calc(100%-76px)]"
|
||||
className="relative m-[16px] rounded-[16px] bg-theme-bg-sidebar border-[2px] border-theme-sidebar-border 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]">
|
||||
@ -61,7 +61,7 @@ export default function Sidebar() {
|
||||
<ActiveWorkspaces />
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute bottom-0 left-0 right-0 pt-4 pb-3 rounded-b-[16px] bg-sidebar-bg bg-opacity-80 backdrop-filter backdrop-blur-md z-10">
|
||||
<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 />
|
||||
</div>
|
||||
</div>
|
||||
@ -104,7 +104,7 @@ export function SidebarMobileHeader() {
|
||||
<>
|
||||
<div
|
||||
aria-label="Show sidebar"
|
||||
className="fixed top-0 left-0 right-0 z-10 flex justify-between items-center px-4 py-2 bg-sidebar-bg text-slate-200 shadow-lg h-16"
|
||||
className="fixed top-0 left-0 right-0 z-10 flex justify-between items-center px-4 py-2 bg-theme-bg-sidebar text-slate-200 shadow-lg h-16"
|
||||
>
|
||||
<button
|
||||
onClick={() => setShowSidebar(true)}
|
||||
@ -138,7 +138,7 @@ export function SidebarMobileHeader() {
|
||||
/>
|
||||
<div
|
||||
ref={sidebarRef}
|
||||
className="relative h-[100vh] fixed top-0 left-0 rounded-r-[26px] bg-sidebar-bg w-[80%] p-[18px] "
|
||||
className="relative h-[100vh] fixed top-0 left-0 rounded-r-[26px] bg-theme-bg-sidebar w-[80%] p-[18px] "
|
||||
>
|
||||
<div className="w-full h-full flex flex-col overflow-x-hidden items-between">
|
||||
{/* Header Information */}
|
||||
@ -178,7 +178,7 @@ export function SidebarMobileHeader() {
|
||||
<ActiveWorkspaces />
|
||||
</div>
|
||||
</div>
|
||||
<div className="z-99 absolute bottom-0 left-0 right-0 pt-2 pb-6 rounded-br-[26px] bg-sidebar-bg bg-opacity-80 backdrop-filter backdrop-blur-md">
|
||||
<div className="z-99 absolute bottom-0 left-0 right-0 pt-2 pb-6 rounded-br-[26px] bg-theme-bg-sidebar bg-opacity-80 backdrop-filter backdrop-blur-md">
|
||||
<Footer />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -303,7 +303,7 @@ function WorkspaceChatSuggestions({ suggestions = [], sendSuggestion }) {
|
||||
{suggestions.map((suggestion, index) => (
|
||||
<button
|
||||
key={index}
|
||||
className="text-left p-2.5 border rounded-xl border-white/20 bg-sidebar hover:bg-workspace-item-selected-gradient"
|
||||
className="text-left p-2.5 border rounded-xl border-white/20 bg-sidebar hover:bg-theme-sidebar-item-selected-gradient"
|
||||
onClick={() => sendSuggestion(suggestion.heading, suggestion.message)}
|
||||
>
|
||||
<p className="font-semibold">{suggestion.heading}</p>
|
||||
|
19
frontend/src/hooks/useTheme.js
Normal file
19
frontend/src/hooks/useTheme.js
Normal file
@ -0,0 +1,19 @@
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
const availableThemes = {
|
||||
default: "Default",
|
||||
light: "Light",
|
||||
};
|
||||
|
||||
export function useTheme() {
|
||||
const [theme, setTheme] = useState(() => {
|
||||
return localStorage.getItem("theme") || "default";
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
document.documentElement.setAttribute("data-theme", theme);
|
||||
localStorage.setItem("theme", theme);
|
||||
}, [theme]);
|
||||
|
||||
return { theme, setTheme, availableThemes };
|
||||
}
|
@ -2,6 +2,37 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
/* Default theme */
|
||||
--theme-bg-primary: #0e0f0f;
|
||||
--theme-bg-secondary: #1a1b1e;
|
||||
--theme-bg-sidebar: #0e0f0f;
|
||||
--theme-bg-container: #0e0f0f;
|
||||
--theme-text-primary: #ffffff;
|
||||
--theme-text-secondary: rgba(255, 255, 255, 0.6);
|
||||
--theme-sidebar-item-default: rgba(255, 255, 255, 0.1);
|
||||
--theme-sidebar-item-selected: rgba(255, 255, 255, 0.3);
|
||||
--theme-sidebar-item-hover: #3f3f42;
|
||||
--theme-sidebar-footer-icon: rgba(255, 255, 255, 0.1);
|
||||
--theme-sidebar-footer-icon-hover: rgba(255, 255, 255, 0.2);
|
||||
--theme-sidebar-border: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
[data-theme="light"] {
|
||||
--theme-bg-primary: #ffffff;
|
||||
--theme-bg-secondary: #f4f4f4;
|
||||
--theme-bg-sidebar: #f4f4f4;
|
||||
--theme-bg-container: #ffffff;
|
||||
--theme-text-primary: #000000;
|
||||
--theme-text-secondary: #4a5568;
|
||||
--theme-sidebar-item-default: rgba(0, 0, 0, 0.1);
|
||||
--theme-sidebar-item-selected: rgba(0, 0, 0, 0.2);
|
||||
--theme-sidebar-item-hover: #e2e8f0;
|
||||
--theme-sidebar-footer-icon: rgba(0, 0, 0, 0.3);
|
||||
--theme-sidebar-footer-icon-hover: rgba(0, 0, 0, 0.5);
|
||||
--theme-sidebar-border: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
|
@ -333,7 +333,7 @@ function SkillLayout({ children, hasChanges, handleSubmit, handleCancel }) {
|
||||
return (
|
||||
<div
|
||||
id="workspace-agent-settings-container"
|
||||
className="w-screen h-screen overflow-hidden bg-main-container-bg flex md:mt-0 mt-6"
|
||||
className="w-screen h-screen overflow-hidden bg-theme-bg-container flex md:mt-0 mt-6"
|
||||
>
|
||||
<Sidebar />
|
||||
<div
|
||||
|
@ -8,7 +8,7 @@ import DocumentSyncQueueRow from "./DocumentSyncQueueRow";
|
||||
|
||||
export default function LiveDocumentSyncManager() {
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
<div
|
||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||
|
@ -90,7 +90,7 @@ function FeatureLayout({ children }) {
|
||||
return (
|
||||
<div
|
||||
id="workspace-feature-settings-container"
|
||||
className="w-screen h-screen overflow-hidden bg-main-container-bg flex md:mt-0 mt-6"
|
||||
className="w-screen h-screen overflow-hidden bg-theme-bg-container flex md:mt-0 mt-6"
|
||||
>
|
||||
<Sidebar />
|
||||
<div
|
||||
|
@ -16,7 +16,7 @@ export default function AdminInvites() {
|
||||
const { isOpen, openModal, closeModal } = useModal();
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
<div
|
||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||
|
@ -54,7 +54,7 @@ export default function AdminLogs() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
<div
|
||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||
|
@ -38,7 +38,7 @@ export default function AdminSystem() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
<div
|
||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||
|
@ -16,7 +16,7 @@ export default function AdminUsers() {
|
||||
const { isOpen, openModal, closeModal } = useModal();
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
<div
|
||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||
|
@ -15,7 +15,7 @@ export default function AdminWorkspaces() {
|
||||
const { isOpen, openModal, closeModal } = useModal();
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
<div
|
||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||
|
@ -133,7 +133,7 @@ export function FineTuningCreationLayout({ setStep, children }) {
|
||||
return (
|
||||
<div
|
||||
id="fine-tune-create-order-container"
|
||||
className="w-screen h-screen overflow-hidden bg-main-container-bg flex md:mt-0 mt-6"
|
||||
className="w-screen h-screen overflow-hidden bg-theme-bg-container flex md:mt-0 mt-6"
|
||||
>
|
||||
<Sidebar />
|
||||
<div
|
||||
|
@ -19,7 +19,7 @@ export default function AdminApiKeys() {
|
||||
const { isOpen, openModal, closeModal } = useModal();
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
<div
|
||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||
|
@ -10,7 +10,7 @@ export default function LanguagePreference() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col gap-y-1">
|
||||
<div className="flex flex-col gap-y-1 mt-6">
|
||||
<h2 className="text-base leading-6 font-bold text-white">
|
||||
Display Language
|
||||
</h2>
|
||||
|
@ -0,0 +1,27 @@
|
||||
import { useTheme } from "@/hooks/useTheme";
|
||||
|
||||
export default function ThemePreference() {
|
||||
const { theme, setTheme, availableThemes } = useTheme();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-y-1 mt-4">
|
||||
<h2 className="text-base leading-6 font-bold text-white">Theme</h2>
|
||||
<p className="text-xs leading-[18px] font-base text-white/60">
|
||||
Select your preferred theme for the application.
|
||||
</p>
|
||||
<div className="flex items-center gap-x-4">
|
||||
<select
|
||||
value={theme}
|
||||
onChange={(e) => setTheme(e.target.value)}
|
||||
className="bg-zinc-900 w-fit mt-2 px-4 border-gray-500 text-white text-sm rounded-lg block py-2"
|
||||
>
|
||||
{Object.entries(availableThemes).map(([key, value]) => (
|
||||
<option key={key} value={key}>
|
||||
{value}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -9,11 +9,13 @@ import CustomAppName from "./CustomAppName";
|
||||
import LanguagePreference from "./LanguagePreference";
|
||||
import CustomSiteSettings from "./CustomSiteSettings";
|
||||
import ShowScrollbar from "./ShowScrollbar";
|
||||
import ThemePreference from "./ThemePreference";
|
||||
|
||||
export default function Appearance() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
<div
|
||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||
@ -30,6 +32,8 @@ export default function Appearance() {
|
||||
{t("appearance.description")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ThemePreference />
|
||||
<LanguagePreference />
|
||||
<ShowScrollbar />
|
||||
<CustomLogo />
|
||||
|
@ -20,7 +20,7 @@ export default function AudioPreference() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
{loading ? (
|
||||
<div
|
||||
|
@ -39,7 +39,7 @@ export default function BrowserExtensionApiKeys() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
<div
|
||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||
|
@ -115,7 +115,7 @@ export default function WorkspaceChats() {
|
||||
}, [offset]);
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
<div
|
||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||
|
@ -88,7 +88,7 @@ export default function EmbedChats() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
<div
|
||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||
|
@ -16,7 +16,7 @@ export default function EmbedConfigs() {
|
||||
const { isOpen, openModal, closeModal } = useModal();
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
<div
|
||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||
|
@ -211,7 +211,7 @@ export default function GeneralEmbeddingPreference() {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
{loading ? (
|
||||
<div
|
||||
|
@ -63,7 +63,7 @@ export default function EmbeddingTextSplitterPreference() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
{loading ? (
|
||||
<div
|
||||
|
@ -328,7 +328,7 @@ export default function GeneralLLMPreference() {
|
||||
(llm) => llm.value === selectedLLM
|
||||
);
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
{loading ? (
|
||||
<div
|
||||
|
@ -26,7 +26,7 @@ export default function PrivacyAndDataHandling() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
<div
|
||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||
|
@ -11,7 +11,7 @@ import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function GeneralSecurity() {
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
<div
|
||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||
|
@ -99,7 +99,7 @@ export default function TranscriptionModelPreference() {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
{loading ? (
|
||||
<div
|
||||
|
@ -171,7 +171,7 @@ export default function GeneralVectorDatabase() {
|
||||
const selectedVDBObject = VECTOR_DBS.find((vdb) => vdb.value === selectedVDB);
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<Sidebar />
|
||||
{loading ? (
|
||||
<div
|
||||
|
@ -32,7 +32,7 @@ export default function InvitePage() {
|
||||
|
||||
if (result.status === "loading") {
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
<FullScreenLoader />
|
||||
</div>
|
||||
);
|
||||
@ -40,14 +40,14 @@ export default function InvitePage() {
|
||||
|
||||
if (result.status === "invalid") {
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex items-center justify-center">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex items-center justify-center">
|
||||
<p className="text-red-400 text-lg">{result.message}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex items-center justify-center">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex items-center justify-center">
|
||||
<ModalWrapper isOpen={true}>
|
||||
<NewUserModal />
|
||||
</ModalWrapper>
|
||||
|
@ -17,7 +17,7 @@ export default function Main() {
|
||||
return (
|
||||
<>
|
||||
<UserMenu>
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
{!isMobile && <Sidebar />}
|
||||
<DefaultChatContainer />
|
||||
</div>
|
||||
|
@ -45,7 +45,7 @@ function ShowWorkspaceChat() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
{!isMobile && <Sidebar />}
|
||||
<WorkspaceChatContainer loading={loading} workspace={workspace} />
|
||||
</div>
|
||||
|
@ -130,7 +130,7 @@ export default function SuggestedChatMessages({ slug }) {
|
||||
<button
|
||||
key={index}
|
||||
onClick={(e) => startEditing(e, index)}
|
||||
className={`text-left p-2.5 border rounded-xl w-full border-white/20 bg-sidebar hover:bg-workspace-item-selected-gradient ${
|
||||
className={`text-left p-2.5 border rounded-xl w-full border-white/20 bg-sidebar hover:bg-theme-sidebar-item-selected-gradient ${
|
||||
editingIndex === index ? "border-sky-400" : ""
|
||||
}`}
|
||||
>
|
||||
|
@ -73,7 +73,7 @@ function ShowWorkspaceChat() {
|
||||
|
||||
const TabContent = TABS[tab];
|
||||
return (
|
||||
<div className="w-screen h-screen overflow-hidden bg-main-container-bg flex">
|
||||
<div className="w-screen h-screen overflow-hidden bg-theme-bg-container flex">
|
||||
{!isMobile && <Sidebar />}
|
||||
<div
|
||||
style={{ height: isMobile ? "100%" : "calc(100% - 32px)" }}
|
||||
|
@ -44,17 +44,32 @@ export default {
|
||||
warn: "#854708",
|
||||
success: "#05603A",
|
||||
darker: "#F4F4F4",
|
||||
// Sidebar colors
|
||||
"sidebar-bg": "#0E0F0F",
|
||||
"workspace-item-default": "rgba(255, 255, 255, 0.1)",
|
||||
"workspace-item-selected": "rgba(255, 255, 255, 0.3)",
|
||||
"workspace-item-hover": "#3F3F42",
|
||||
"footer-icon": "rgba(255, 255, 255, 0.1)",
|
||||
"footer-icon-hover": "rgba(255, 255, 255, 0.2)",
|
||||
"sidebar-border": "rgba(255, 255, 255, 0.1)",
|
||||
|
||||
// Main container colors
|
||||
"main-container-bg": "#0E0F0F",
|
||||
// Generic theme colors
|
||||
theme: {
|
||||
bg: {
|
||||
primary: 'var(--theme-bg-primary)',
|
||||
secondary: 'var(--theme-bg-secondary)',
|
||||
sidebar: 'var(--theme-bg-sidebar)',
|
||||
container: 'var(--theme-bg-container)',
|
||||
},
|
||||
text: {
|
||||
primary: 'var(--theme-text-primary)',
|
||||
secondary: 'var(--theme-text-secondary)',
|
||||
},
|
||||
sidebar: {
|
||||
item: {
|
||||
default: 'var(--theme-sidebar-item-default)',
|
||||
selected: 'var(--theme-sidebar-item-selected)',
|
||||
hover: 'var(--theme-sidebar-item-hover)',
|
||||
},
|
||||
footer: {
|
||||
icon: 'var(--theme-sidebar-footer-icon)',
|
||||
'icon-hover': 'var(--theme-sidebar-footer-icon-hover)',
|
||||
},
|
||||
border: 'var(--theme-sidebar-border)',
|
||||
},
|
||||
},
|
||||
},
|
||||
backgroundImage: {
|
||||
"preference-gradient":
|
||||
|
Loading…
Reference in New Issue
Block a user