From 45468a547697fefbd4594eae4b12ddba3bcb7c8b Mon Sep 17 00:00:00 2001 From: Candide Kemmler Date: Wed, 23 Apr 2025 21:25:31 +0200 Subject: [PATCH 1/2] feat(ui): introduce UI config system and integrate with layout and components - Added new files under `lib/` and `hooks/` to manage and provide UI configuration - Updated layout and dark mode switcher to use the new UI config - Tweaked thread component for compatibility --- src/app/layout.tsx | 17 +-- src/components/dark-mode-switcher.tsx | 25 +++++ src/components/thread/index.tsx | 151 +++++++++++++++----------- src/hooks/useUIConfig.ts | 9 ++ src/lib/custom-ui-config.ts | 3 + src/lib/get-ui-config.ts | 15 +++ src/lib/ui-config-provider.tsx | 48 ++++++++ src/lib/ui-config.ts | 45 ++++++++ 8 files changed, 241 insertions(+), 72 deletions(-) create mode 100644 src/components/dark-mode-switcher.tsx create mode 100644 src/hooks/useUIConfig.ts create mode 100644 src/lib/custom-ui-config.ts create mode 100644 src/lib/get-ui-config.ts create mode 100644 src/lib/ui-config-provider.tsx create mode 100644 src/lib/ui-config.ts diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 234f21d..05b781a 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,8 +1,9 @@ +import { UIConfigProvider } from "@/lib/ui-config-provider"; import type { Metadata } from "next"; -import "./globals.css"; import { Inter } from "next/font/google"; -import React from "react"; import { NuqsAdapter } from "nuqs/adapters/next/app"; +import React from "react"; +import "./globals.css"; const inter = Inter({ subsets: ["latin"], @@ -21,10 +22,12 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - - - {children} - - + + + + {children} + + + ); } diff --git a/src/components/dark-mode-switcher.tsx b/src/components/dark-mode-switcher.tsx new file mode 100644 index 0000000..4e4b134 --- /dev/null +++ b/src/components/dark-mode-switcher.tsx @@ -0,0 +1,25 @@ +"use client"; + +import { Moon, Sun } from "lucide-react"; +import { useUIConfig } from "@/hooks/useUIConfig"; + +export const ThemeToggleButton = () => { + const { theme, setTheme } = useUIConfig(); + + const toggleTheme = () => { + setTheme(theme === "dark" ? "light" : "dark"); + }; + + const isDark = theme === "dark"; + + return ( + + ); +}; diff --git a/src/components/thread/index.tsx b/src/components/thread/index.tsx index 1cec4a2..bc1e4f1 100644 --- a/src/components/thread/index.tsx +++ b/src/components/thread/index.tsx @@ -26,6 +26,8 @@ import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom"; import ThreadHistory from "./history"; import { toast } from "sonner"; import { useMediaQuery } from "@/hooks/useMediaQuery"; +import { useUIConfig } from "@/hooks/useUIConfig"; +import { ThemeToggleButton } from "../dark-mode-switcher"; import { Label } from "../ui/label"; import { Switch } from "../ui/switch"; import { GitHubSVG } from "../icons/github"; @@ -114,6 +116,7 @@ export function Thread() { const [input, setInput] = useState(""); const [firstTokenReceived, setFirstTokenReceived] = useState(false); const isLargeScreen = useMediaQuery("(min-width: 1024px)"); + const { config } = useUIConfig(); const stream = useStreamContext(); const messages = stream.messages; @@ -212,30 +215,32 @@ export function Thread() { return (
-
- -
+ - -
-
-
+
+ +
+ +
+ )} {!chatStarted && (
-
- {(!chatHistoryOpen || !isLargeScreen) && ( - - )} -
-
- + {!config.layout.hideThreadHistory && ( +
+ {(!chatHistoryOpen || !isLargeScreen) && ( + + )} +
+ )} +
+ {config.layout.showThemeToggle && } + {!config.layout.hideGithubButton && }
)} @@ -308,20 +316,29 @@ export function Thread() { damping: 30, }} > - - - Agent Chat - + {config.brand.brandHeaderTopLeft ? ( + config.brand.brandHeaderTopLeft() + ) : ( + <> + + + Agent Chat + + + )}
-
- -
+ {!config.layout.hideGithubButton && ( +
+ +
+ )} + {config.layout.showThemeToggle && } } footer={ -
- {!chatStarted && ( +
+ {!chatStarted && config.brand.brandHeaderWelcome ? ( + config.brand.brandHeaderWelcome() + ) : !config.layout.hideBrandHeaderAboveChatBox ? (

Agent Chat

- )} + ) : null} @@ -420,19 +439,21 @@ export function Thread() {
-
- - -
+ {!config.layout.hideToolCallsToggleButton && ( +
+ + +
+ )}
{stream.isLoading ? (
)} @@ -333,12 +333,12 @@ export function Thread() {
- {!config.layout.hideGithubButton && ( + {!config.layout?.hideGithubButton && (
)} - {config.layout.showThemeToggle && } + {config.layout?.showThemeToggle && } {!chatStarted && config.brand.brandHeaderWelcome ? ( config.brand.brandHeaderWelcome() - ) : !config.layout.hideBrandHeaderAboveChatBox ? ( + ) : !config.layout?.hideBrandHeaderAboveChatBox ? (

@@ -439,7 +439,7 @@ export function Thread() {
- {!config.layout.hideToolCallsToggleButton && ( + {!config.layout?.hideToolCallsToggleButton && (