Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dark theme #676

Merged
merged 3 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion frontend/.ladle/components.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
import React from 'react';
import React, { useEffect } from 'react';
import '../src/i18n';
import { GlobalProvider } from '@ladle/react';
import { useLadleContext } from '@ladle/react';
import '../src/index.css';

export const Provider: GlobalProvider = ({ children }) => {
const { globalState } = useLadleContext();

useEffect(() => {
const bodyClass = document.body.classList;

if (globalState.theme === 'dark') {
bodyClass.add('dark');
} else {
bodyClass.remove('dark');
}
}, [globalState.theme]);

return <>{children}</>;
};
Yukinobu-Mine marked this conversation as resolved.
Show resolved Hide resolved
6 changes: 3 additions & 3 deletions frontend/src/components/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,21 @@ const Alert: React.FC<Props> = (props) => {
return (
<div
className={twMerge(
'flex flex-col rounded border border-aws-squid-ink shadow-lg',
'flex flex-col rounded border border-aws-squid-ink-light dark:border-aws-squid-ink-dark shadow-lg',
props.severity === 'info' && 'bg-aws-aqua',
props.severity === 'warning' && 'bg-yellow',
props.severity === 'error' && 'bg-red',
props.className
)}>
<div
className={twMerge(
'flex gap-2 p-2 font-bold text-aws-font-color-white'
'flex gap-2 p-2 font-bold text-aws-font-color-white-light dark:text-aws-font-color-white-dark'
)}>
{icon}
<div>{props.title}</div>
</div>

<div className="px-2 pb-2 text-aws-font-color-white">
<div className="px-2 pb-2 text-aws-font-color-white-light dark:text-aws-font-color-white-dark">
{props.children}
</div>
</div>
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/ApiKeyItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const ApiKeyItem: React.FC<Props> = (props) => {
{isLoading ? (
<Skeleton className="h-8 w-full" />
) : (
<div className="flex flex-col gap-1 rounded border border-aws-font-color/50 p-1 text-sm">
<div className="flex flex-col gap-1 rounded border border-aws-font-color-light/50 dark:border-aws-font-color-dark p-1 text-sm">
<div className="text-base font-semibold">
{botApiKey?.description}
</div>
Expand All @@ -80,7 +80,7 @@ const ApiKeyItem: React.FC<Props> = (props) => {
{t('bot.apiSettings.label.apiKeyDetail.inactive')}
</div>
)}
<div className="text-xs text-aws-font-color/70">
<div className="text-xs text-aws-font-color-light/70 dark:text-aws-font-color-dark/70">
<div className="mr-1 inline">
{t('bot.apiSettings.label.apiKeyDetail.creationDate')}:
</div>
Expand All @@ -98,7 +98,7 @@ const ApiKeyItem: React.FC<Props> = (props) => {
<ButtonCopy text={botApiKey?.value ?? ''} className="-my-2" />
<Button
text
className="-m-2 font-bold text-aws-sea-blue"
className="-m-2 font-bold text-aws-sea-blue-light dark:text-aws-sea-blue-dark"
onClick={() => {
setIsHideKey(!isHideKey);
}}>
Expand Down
16 changes: 12 additions & 4 deletions frontend/src/components/AppContent.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import ChatListDrawer from './ChatListDrawer';
import { BaseProps } from '../@types/common';
import { ConversationMeta } from '../@types/conversation';
Expand All @@ -18,6 +18,7 @@ import useUser from '../hooks/useUser';
import DialogConfirmDeleteChat from './DialogConfirmDeleteChat';
import DialogConfirmClearConversations from './DialogConfirmClearConversations';
import DialogSelectLanguage from './DialogSelectLanguage';
import useLocalStorage from '../hooks/useLocalStorage';

type Props = BaseProps & {
signOut?: () => void;
Expand All @@ -34,6 +35,13 @@ const AppContent: React.FC<Props> = (props) => {
const { newChat, isGeneratedTitle } = useChat();
const { isConversationOrNewChat, pathPattern } = usePageTitlePathPattern();
const { isAdmin } = useUser();
const [theme] = useLocalStorage(
'theme',
'light'
);
useEffect(() => {
document.documentElement.className = theme;
}, [theme]);

const onClickNewChat = useCallback(() => {
navigate('/');
Expand Down Expand Up @@ -74,7 +82,7 @@ const AppContent: React.FC<Props> = (props) => {
const [isOpenSelectLangage, setIsOpenSelectLangage] = useState(false);

return (
<div className="relative flex h-dvh w-screen bg-aws-paper">
<div className="relative flex h-dvh w-screen bg-aws-paper-light dark:bg-aws-paper-dark">
<ChatListDrawer
isAdmin={isAdmin}
conversations={conversations}
Expand Down Expand Up @@ -120,7 +128,7 @@ const AppContent: React.FC<Props> = (props) => {

<main className="min-h-dvh relative flex flex-col flex-1 overflow-y-hidden transition-width">

<header className="visible flex h-12 w-full items-center bg-aws-squid-ink p-3 text-lg text-aws-font-color-white lg:hidden lg:h-0">
<header className="visible flex h-12 w-full items-center bg-aws-squid-ink-light dark:bg-aws-squid-ink-dark p-3 text-lg text-aws-font-color-white-light dark:text-aws-font-color-white-dark lg:hidden lg:h-0">
<button
className="mr-2 rounded-full p-2 hover:brightness-50 focus:outline-none focus:ring-1 "
onClick={() => {
Expand Down Expand Up @@ -149,7 +157,7 @@ const AppContent: React.FC<Props> = (props) => {
</header>

<div
className="h-full overflow-hidden overflow-y-auto text-aws-font-color"
className="h-full overflow-hidden overflow-y-auto text-aws-font-color-light dark:text-aws-font-color-dark"
id="main">
<SnackbarProvider>
<Outlet />
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/AuthAmplify.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const AuthAmplify: React.FC<Props> = ({ socialProviders, children }) => {
socialProviders={socialProviders}
components={{
Header: () => (
<div className="mb-5 mt-10 flex justify-center text-3xl text-aws-font-color">
<div className="mb-5 mt-10 flex justify-center text-3xl text-aws-font-color-light">
{!MISTRAL_ENABLED ? t('app.name') : t('app.nameWithoutClaude')}
</div>
),
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/AuthCustom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const AuthCustom: React.FC<Props> = ({ children }) => {
</div>
) : !authenticated ? (
<div className="flex flex-col items-center gap-4">
<div className="mb-5 mt-10 text-4xl text-aws-sea-blue">
<div className="mb-5 mt-10 text-4xl text-aws-sea-blue-light">
{!MISTRAL_ENABLED ? t('app.name') : t('app.nameWithoutClaude')}
</div>
<Button onClick={() => handleSignIn()} className="px-20 text-xl">
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ const Button = forwardRef<HTMLButtonElement, Props>((props, ref) => {
ref={ref}
className={twMerge(
'flex items-center justify-center whitespace-nowrap rounded-lg border p-1 px-3',
props.text && 'border-0',
props.outlined && 'border-aws-squid-ink/50 hover:bg-white ',
props.text && 'border-0 dark:text-aws-font-color-dark',
props.outlined && 'border-aws-squid-ink-light/50 dark:border-aws-font-color-gray/50 hover:bg-white dark:hover:bg-aws-ui-color-dark dark:text-aws-font-color-dark',
!props.text &&
!props.outlined &&
'bg-aws-sea-blue text-aws-font-color-white',
'bg-aws-sea-blue-light dark:bg-aws-ui-color-dark dark:border-aws-ui-color-dark text-aws-font-color-white-light dark:text-aws-font-color-white-dark',
props.disabled || props.loading ? 'opacity-30' : 'hover:brightness-75',
props.className
)}
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/ButtonFileChoose.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ const ButtonFileChoose: React.FC<Props> = (props) => {
props.className,
'flex items-center justify-center whitespace-nowrap rounded-lg hover:shadow hover:brightness-75',
props.icon
? 'rounded-full p-2 text-xl text-aws-sea-blue'
: 'border bg-aws-sea-blue p-1 px-3 text-aws-font-color-white',
? 'rounded-full p-2 text-xl text-aws-sea-blue-light dark:text-aws-sea-blue-dark'
: 'border dark:border-aws-ui-color-dark bg-aws-sea-blue-light dark:bg-aws-ui-color-dark p-1 px-3 text-aws-font-color-white-light dark:text-aws-font-color-white-dark',
props.disabled ? 'opacity-30 ' : 'cursor-pointer'
)}>
{props.children}
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/ButtonIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const ButtonIcon: React.FC<Props> = (props) => {
<button
className={twMerge(
'flex items-center justify-center rounded-full p-2 text-xl hover:shadow',
'dark:text-aws-font-color-dark dark:hover:shadow-aws-font-color-dark',
props.disabled ? 'opacity-30' : 'hover:brightness-75',
props.className
)}
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/ButtonSend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ const ButtonSend: React.FC<Props> = (props) => {
return (
<button
className={twMerge(
'flex items-center justify-center rounded-xl bg-aws-sea-blue p-2 text-xl text-white hover:bg-aws-sea-blue-hover',
'flex items-center justify-center rounded-xl p-2 text-xl',
'bg-aws-sea-blue-light text-white hover:bg-aws-sea-blue-hover-light',
'dark:bg-aws-sea-blue-dark dark:hover:bg-aws-sea-blue-hover-dark',
props.disabled ? 'opacity-30' : '',
props.className
)}
Expand Down
47 changes: 45 additions & 2 deletions frontend/src/components/ChatListDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import React, {
} from 'react';
import { BaseProps } from '../@types/common';
import { useLocation, useParams } from 'react-router-dom';
import { IoMoonSharp, IoSunnyOutline } from "react-icons/io5";
import useDrawer from '../hooks/useDrawer';
import ButtonIcon from './ButtonIcon';
import {
Expand All @@ -28,11 +29,13 @@ import { ConversationMeta } from '../@types/conversation';
import { BotListItem } from '../@types/bot';
import { isMobile } from 'react-device-detect';
import useChat from '../hooks/useChat';
import useLocalStorage from '../hooks/useLocalStorage';
import { useTranslation } from 'react-i18next';
import Menu from './Menu';
import DrawerItem from './DrawerItem';
import ExpandableDrawerGroup from './ExpandableDrawerGroup';
import { usePageLabel } from '../routes';
import Toggle from '../components/Toggle.tsx';

type Props = BaseProps & {
isAdmin: boolean;
Expand Down Expand Up @@ -194,10 +197,17 @@ const ChatListDrawer: React.FC<Props> = (props) => {
const [prevConversations, setPrevConversations] =
useState<typeof conversations>();
const [generateTitleIndex, setGenerateTitleIndex] = useState(-1);
// If you want to add a theme, change the type from boolean to string and change the UI from toggle to pulldown.
const [isDarkTheme, setIsDarkTheme] = useState(false);

const { newChat, conversationId } = useChat();
const { botId } = useParams();

const [theme, setTheme] = useLocalStorage(
'theme',
'light'
);

useEffect(() => {
setPrevConversations(conversations);
}, [conversations]);
Expand All @@ -217,6 +227,12 @@ const ChatListDrawer: React.FC<Props> = (props) => {
}
}, [conversations, prevConversations]);

useEffect(() => {
if (theme === 'dark') {
setIsDarkTheme(true);
}
}, [theme]);

const onClickNewChat = useCallback(() => {
newChat();
closeSamllDrawer();
Expand All @@ -232,6 +248,17 @@ const ChatListDrawer: React.FC<Props> = (props) => {
[]
);

const changeTheme = (isDarkTheme: boolean) => {
setIsDarkTheme(isDarkTheme);
if (isDarkTheme) {
document.documentElement.className = 'dark';
setTheme('dark');
} else {
document.documentElement.className = 'light';
setTheme('light');
}
};

const smallDrawer = useRef<HTMLDivElement>(null);

const closeSamllDrawer = useCallback(() => {
Expand Down Expand Up @@ -262,7 +289,7 @@ const ChatListDrawer: React.FC<Props> = (props) => {

return (
<>
<div className="relative h-full overflow-y-auto bg-aws-squid-ink scrollbar-thin scrollbar-track-white scrollbar-thumb-aws-squid-ink/30 ">
<div className="relative h-full overflow-y-auto bg-aws-squid-ink-light dark:bg-aws-ui-color-dark scrollbar-thin scrollbar-track-white scrollbar-thumb-aws-squid-ink-light/30 dark:scrollbar-thumb-aws-ui-color-dark/30">
<nav
className={`lg:visible lg:w-64 ${
opened ? 'visible w-64' : 'invisible w-0'
Expand Down Expand Up @@ -361,12 +388,28 @@ const ChatListDrawer: React.FC<Props> = (props) => {
<div
className={`${
opened ? 'w-64' : 'w-0'
} fixed bottom-0 flex h-12 items-center justify-start border-t bg-aws-squid-ink transition-width lg:w-64`}>
} fixed bottom-0 flex h-12 items-center justify-between p-2 border-t bg-aws-squid-ink-light dark:bg-aws-ui-color-dark transition-width lg:w-64`}>
<Menu
onSignOut={props.onSignOut}
onSelectLanguage={props.onSelectLanguage}
onClearConversations={props.onClearConversations}
/>

<div className="flex items-center gap-2">
{isDarkTheme ? (
<>
<IoMoonSharp />
</>
): (
<>
<IoSunnyOutline />
</>
)}
<Toggle
value={isDarkTheme}
onChange={(isDarkTheme) => changeTheme(isDarkTheme)}
/>
</div>
</div>
</nav>
</div>
Expand Down
12 changes: 6 additions & 6 deletions frontend/src/components/ChatMessage.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ export const Conversation = () => {
<div
key={idx}
className={`${
message.role === 'assistant' ? 'bg-aws-squid-ink/5' : ''
message.role === 'assistant' ? 'bg-aws-squid-ink-light/5 dark:bg-aws-squid-ink-dark/5' : 'dark:text-aws-font-color-dark'
}`}>
<ChatMessage
chatContent={message}
/>

<div className="w-full border-b border-aws-squid-ink/10"></div>
<div className="w-full border-b border-aws-squid-ink-light/10 dark:border-aws-squid-ink-dark/10"></div>
</div>
))}
</>
Expand Down Expand Up @@ -123,13 +123,13 @@ export const ConversationThinking = () => {
<div
key={idx}
className={`${
message.role === 'assistant' ? 'bg-aws-squid-ink/5' : ''
message.role === 'assistant' ? 'bg-aws-squid-ink-light/5 dark:bg-aws-squid-ink-dark/5' : 'dark:text-aws-font-color-dark'
}`}>
<ChatMessage
chatContent={message}
/>

<div className="w-full border-b border-aws-squid-ink/10"></div>
<div className="w-full border-b border-aws-squid-ink-light/10 dark:border-aws-squid-ink-dark/10"></div>
</div>
))}
</>
Expand Down Expand Up @@ -272,7 +272,7 @@ export const ConversationWithAgnet = () => {
<div
key={idx}
className={`${
message.role === 'assistant' ? 'bg-aws-squid-ink/5' : ''
message.role === 'assistant' ? 'bg-aws-squid-ink-light/5 dark:bg-aws-squid-ink-dark/5' : 'dark:text-aws-font-color-dark'
}`}>
<ChatMessage
chatContent={message}
Expand Down Expand Up @@ -313,7 +313,7 @@ export const ConversationWithAgnet = () => {
]}
/>

<div className="w-full border-b border-aws-squid-ink/10"></div>
<div className="w-full border-b border-aws-squid-ink-light/10 dark:border-aws-squid-ink-dark/10"></div>
</div>
))}
</>
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/ChatMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ const ChatMessage: React.FC<Props> = (props) => {

<div className="order-first col-span-12 flex lg:order-none lg:col-span-8 lg:col-start-3">
{chatContent?.role === 'user' && (
<div className="h-min rounded bg-aws-sea-blue p-2 text-xl text-white">
<div className="h-min rounded bg-aws-sea-blue-light dark:bg-aws-sea-blue-dark p-2 text-xl text-white">
<PiUserFill />
</div>
)}
Expand Down Expand Up @@ -312,7 +312,7 @@ const ChatMessage: React.FC<Props> = (props) => {
<div className="flex flex-col items-end lg:items-start">
{chatContent?.role === 'user' && !isEdit && (
<ButtonIcon
className="text-dark-gray"
className="text-dark-gray dark:text-light-gray"
onClick={() => {
setChangedContent(chatContent.content[firstTextContent].body);
setIsEdit(true);
Expand All @@ -323,7 +323,7 @@ const ChatMessage: React.FC<Props> = (props) => {
{chatContent?.role === 'assistant' && (
<div className="flex">
<ButtonIcon
className="text-dark-gray"
className="text-dark-gray dark:text-light-gray"
onClick={() => setIsFeedbackOpen(true)}>
{chatContent.feedback && !chatContent.feedback.thumbsUp ? (
<PiThumbsDownFill />
Expand All @@ -332,7 +332,7 @@ const ChatMessage: React.FC<Props> = (props) => {
)}
</ButtonIcon>
<ButtonCopy
className="text-dark-gray"
className="text-dark-gray dark:text-light-gray"
text={chatContent.content[0].body}
/>
</div>
Expand Down
Loading
Loading