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:
Sean Hatfield 2024-10-02 18:06:31 -07:00 committed by GitHub
parent cbc4e80d31
commit d0546a47df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 319 additions and 199 deletions

View File

@ -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>

View 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);
}

View File

@ -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,

View File

@ -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"

View File

@ -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"

View File

@ -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">

View File

@ -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">

View File

@ -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>

View File

@ -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>

View 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 };
}

View File

@ -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;

View File

@ -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

View File

@ -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)" }}

View File

@ -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

View File

@ -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)" }}

View File

@ -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)" }}

View File

@ -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)" }}

View File

@ -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)" }}

View File

@ -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)" }}

View File

@ -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

View File

@ -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)" }}

View File

@ -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>

View File

@ -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>
);
}

View File

@ -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 />

View File

@ -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

View File

@ -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)" }}

View File

@ -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)" }}

View File

@ -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)" }}

View File

@ -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)" }}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)" }}

View File

@ -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)" }}

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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" : ""
}`}
>

View File

@ -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)" }}

View File

@ -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":