feat: light theme mode

This commit is contained in:
butterfly
2024-04-25 21:57:50 +08:00
parent bb7422c526
commit 59583e53bd
34 changed files with 335 additions and 174 deletions

View File

@@ -182,7 +182,7 @@ export function ChatActions(props: {
return (
<div
key={act.text}
className={`flex items-center gap-3 p-3 bg-white hover:bg-select-btn rounded-action-btn leading-6`}
className={`flex items-center gap-3 p-3 rounded-action-btn leading-6`}
onClick={act.onClick}
>
{act.icon}
@@ -200,14 +200,14 @@ export function ChatActions(props: {
trigger="click"
placement="rt"
noArrow
popoverClassName="border-actions-popover border-gray-200 rounded-md shadow-actions-popover w-actions-popover bg-white "
popoverClassName="border border-chat-actions-popover-mobile rounded-md shadow-chat-actions-popover-mobile w-actions-popover bg-chat-actions-popover-panel-mobile "
>
<AddCircleIcon />
</Popover>
);
}
const popoverClassName = `bg-chat-actions-popover-color whitespace-nowrap px-3 py-2.5 text-white text-sm-title rounded-md`;
const popoverClassName = `bg-chat-actions-btn-popover whitespace-nowrap px-3 py-2.5 text-text-chat-actions-btn-popover text-sm-title rounded-md`;
return (
<div className={`flex gap-2 item-center ${props.className}`}>
@@ -222,7 +222,7 @@ export function ChatActions(props: {
placement={ind ? "t" : "lt"}
>
<div
className="h-[32px] w-[32px] flex items-center justify-center hover:bg-gray-200 hover:rounded-action-btn"
className="h-[32px] w-[32px] flex items-center justify-center hover:bg-chat-actions-btn-hovered hover:rounded-action-btn"
onClick={act.onClick}
>
{act.icon}
@@ -242,7 +242,7 @@ export function ChatActions(props: {
placement={ind === arr.length - 1 ? "rt" : "t"}
>
<div
className="h-[32px] w-[32px] flex items-center justify-center hover:bg-gray-200 hover:rounded-action-btn"
className="h-[32px] w-[32px] flex items-center justify-center hover:bg-chat-actions-btn-hovered hover:rounded-action-btn"
onClick={act.onClick}
>
{act.icon}

View File

@@ -44,11 +44,11 @@ export default function ChatHeader(props: ChatHeaderProps) {
return (
<div
className={`absolute w-[100%] backdrop-blur-[30px] z-20 flex flex-0 justify-between items-center px-6 py-4 gap-chat-header-gap border-b-[1px] border-gray-200 ${containerClassName}`}
className={`absolute w-[100%] backdrop-blur-[30px] z-20 flex flex-0 justify-between items-center px-6 py-4 gap-chat-header-gap sm:border-b sm:border-chat-header-bottom ${containerClassName}`}
data-tauri-drag-region
>
<div
className={`absolute z-[-1] top-0 left-0 w-[100%] h-[100%] opacity-85 backdrop-blur-[20px] bg-gray-50 flex flex-0 justify-between items-center gap-chat-header-gap`}
className={`absolute z-[-1] top-0 left-0 w-[100%] h-[100%] opacity-85 backdrop-blur-[20px] sm:bg-chat-panel-header-mask bg-chat-panel-header-mobile flex flex-0 justify-between items-center gap-chat-header-gap`}
>
{" "}
</div>
@@ -63,12 +63,14 @@ export default function ChatHeader(props: ChatHeaderProps) {
<div className={`flex-1 ${titleClassName}`}>
<div
className={`line-clamp-1 cursor-pointer text-black text-chat-header-title font-common ${mainTitleClassName}`}
className={`line-clamp-1 cursor-pointer text-text-chat-header-title text-chat-header-title font-common ${mainTitleClassName}`}
onClickCapture={() => setIsEditingMessage(true)}
>
{!session.topic ? DEFAULT_TOPIC : session.topic}
</div>
<div className={`text-gray-500 text-sm ${subTitleClassName}`}>
<div
className={`text-text-chat-header-subtitle text-sm ${subTitleClassName}`}
>
{isMobileScreen ? (
<div
className="flex items-center gap-1"

View File

@@ -203,13 +203,14 @@ export default forwardRef<ChatInputPanelInstance, ChatInputPanelProps>(
emitImages: setAttachImages,
setUploading,
});
let containerClassName = "border-t border-chat-input-top";
let inputClassName = " flex flex-col px-5 pb-5";
let actionsClassName = "py-2.5";
let labelClassName = "rounded-md p-4 gap-4";
let textarea = "min-h-chat-input";
if (isMobileScreen) {
containerClassName = "rounded-tl-md rounded-tr-md";
inputClassName = "flex flex-row-reverse items-center gap-2 p-3";
actionsClassName = "";
labelClassName = " rounded-chat-input p-3 gap-3 flex-1";
@@ -217,13 +218,11 @@ export default forwardRef<ChatInputPanelInstance, ChatInputPanelProps>(
}
return (
<div
className={`relative w-[100%] box-border border-gray-200 border-t-[1px]`}
>
<div className={`relative w-[100%] box-border ${containerClassName}`}>
<PromptHints
prompts={promptHints}
onPromptSelect={onPromptSelect}
className=" border-gray-200"
className=" border-chat-input-top"
/>
<div className={`${inputClassName}`}>
@@ -251,7 +250,7 @@ export default forwardRef<ChatInputPanelInstance, ChatInputPanelProps>(
isMobileScreen={isMobileScreen}
/>
<label
className={`cursor-text flex flex-col bg-white border-[1px] border-white focus-within:border-blue-300 focus-within:shadow-chat-input ${labelClassName}`}
className={`cursor-text flex flex-col bg-chat-panel-input-hood border border-chat-input-hood sm:focus-within:border-chat-input-hood-focus sm:focus-within:shadow-chat-input-hood-focus-shadow ${labelClassName}`}
htmlFor="chat-input"
>
{attachImages.length != 0 && (
@@ -295,14 +294,14 @@ export default forwardRef<ChatInputPanelInstance, ChatInputPanelProps>(
{!isMobileScreen && (
<div className="flex items-center justify-center text-sm gap-3">
<div className="flex-1">&nbsp;</div>
<div className="text-gray-500 text-time line-clamp-1">
<div className="text-text-chat-input-placeholder text-time line-clamp-1">
{Locale.Chat.Input(submitKey)}
</div>
<Btn
className="min-w-[77px]"
icon={<SendIcon />}
text={Locale.Chat.Send}
// className={styles["chat-input-send"]}
disabled={!userInput.length}
type="primary"
onClick={() => doSubmit(userInput)}
/>

View File

@@ -141,7 +141,7 @@ export default function ChatMessagePanel(props: ChatMessagePanelProps) {
return (
<div
className={`pt-[80px] relative flex-1 overscroll-y-none overflow-y-auto overflow-x-hidden px-3 pb-6`}
className={`pt-[80px] relative flex-1 overscroll-y-none overflow-y-auto overflow-x-hidden px-3 pb-6 md:bg-chat-panel-message bg-chat-panel-message-mobile`}
ref={scrollRef}
onScroll={(e) => onChatBodyScroll(e.currentTarget)}
onMouseDown={() => inputRef.current?.blur()}
@@ -189,7 +189,7 @@ export default function ChatMessagePanel(props: ChatMessagePanelProps) {
}`}
>
<div
className={` pointer-events-none text-gray-500 text-right text-time whitespace-nowrap transition-all duration-500 text-sm absolute z-1 ${
className={` pointer-events-none text-text-chat-message-date text-right text-time whitespace-nowrap transition-all duration-500 text-sm absolute z-1 ${
isUser ? "right-0" : "left-0"
} bottom-[100%] hidden group-hover:block`}
>
@@ -200,8 +200,8 @@ export default function ChatMessagePanel(props: ChatMessagePanelProps) {
<div
className={`transition-all duration-300 select-text break-words font-common text-sm-title ${
isUser
? "rounded-user-message bg-message-bg"
: "rounded-bot-message bg-white"
? "rounded-user-message bg-chat-panel-message-user"
: "rounded-bot-message bg-chat-panel-message-bot"
} box-border peer py-2 px-3`}
onPointerMoveCapture={(e) =>
getRelativePosition(e.currentTarget, message.id)
@@ -223,7 +223,9 @@ export default function ChatMessagePanel(props: ChatMessagePanelProps) {
parentRef={scrollRef}
defaultShow={i >= messages.length - 6}
className={`max-w-message-width ${
isUser ? " text-white" : "text-black"
isUser
? " text-text-chat-message-markdown-user"
: "text-text-chat-message-markdown-bot"
}`}
/>
<Imgs message={message} isMobileScreen={isMobileScreen} />

View File

@@ -256,10 +256,20 @@ function _Chat() {
const currentModel = chatStore.currentSession().mask.modelConfig.model;
const allModels = useAllModels();
const models = useMemo(
() => allModels.filter((m) => m.available),
[allModels],
);
const models = useMemo(() => {
const filteredModels = allModels.filter((m) => m.available);
const defaultModel = filteredModels.find((m) => m.isDefault);
if (defaultModel) {
const arr = [
defaultModel,
...filteredModels.filter((m) => m !== defaultModel),
];
return arr;
} else {
return filteredModels;
}
}, [allModels]);
return (
<div

View File

@@ -1,24 +1,45 @@
import { useChatStore } from "@/app/store/chat";
import Locale from "@/app/locales";
import styles from "./index.module.scss";
import { useAppConfig } from "@/app/store";
export default function ClearContextDivider() {
const chatStore = useChatStore();
const { isMobileScreen } = useAppConfig();
return (
<div
className={styles["clear-context"]}
onClick={() =>
className={`mt-6 mb-8 flex items-center justify-center gap-2.5`}
onClick={() => {
if (!isMobileScreen) {
return;
}
chatStore.updateCurrentSession(
(session) => (session.clearContextIndex = undefined),
)
}
);
}}
>
<div className={styles["clear-context-tips"]}>{Locale.Context.Clear}</div>
<div className={styles["clear-context-revert-btn"]}>
{Locale.Context.Revert}
<div className="bg-chat-panel-message-clear-divider h-[1px] w-10"> </div>
<div className="flex items-center justify-between gap-1 text-sm">
<div className={`text-text-chat-panel-message-clear`}>
{Locale.Context.Clear}
</div>
<div
className={`text-text-chat-panel-message-clear-revert underline font-common ${
!isMobileScreen ? " cursor-pointer" : ""
}`}
onClick={() => {
if (isMobileScreen) {
return;
}
chatStore.updateCurrentSession(
(session) => (session.clearContextIndex = undefined),
);
}}
>
{Locale.Context.Revert}
</div>
</div>
<div className="bg-chat-panel-message-clear-divider h-[1px] w-10"> </div>
</div>
);
}

View File

@@ -50,7 +50,8 @@ const genActionsShema = (
(message: RenderMessage) => void
>,
) => {
const className = " !p-1 hover:bg-gray-100 !rounded-actions-bar-btn ";
const className =
" !p-1 hover:bg-chat-message-actions-btn-hovered !rounded-actions-bar-btn ";
return [
{
id: "Edit",
@@ -267,9 +268,10 @@ export default function MessageActions(props: MessageActionsProps) {
pointer-events-none
group-hover:opacity-100
group-hover:pointer-events-auto
bg-white
bg-chat-message-actions
rounded-md
shadow-actions-bar
shadow-message-actions-bar
dark:bg-none
${className}
`}
>

View File

@@ -72,7 +72,7 @@ export default function PromptHints(props: {
${
notShowPrompt
? "max-h-[0vh] border-none"
: "border-b-[1px] pt-2.5 max-h-[50vh]"
: "border-b pt-2.5 max-h-[50vh]"
}
${props.className}
`}

View File

@@ -56,8 +56,8 @@ export function SessionItem(props: {
className={`group relative flex p-3 items-center gap-2 self-stretch rounded-md mb-2 ${
props.selected &&
(currentPath === Path.Chat || currentPath === Path.Home)
? `bg-blue-100 border-blue-200 border `
: `bg-gray-100 hover:bg-gray-200`
? `bg-chat-menu-session-selected border-chat-menu-session-selected border `
: `bg-chat-menu-session-unselected hover:bg-chat-menu-session-hovered`
}`}
onClick={props.onClick}
ref={(ele) => {
@@ -76,17 +76,17 @@ export function SessionItem(props: {
<div className="flex flex-col flex-1">
<div className={`flex justify-between items-center`}>
<div
className={` text-gray-900 text-sm-title line-clamp-1 flex-1`}
className={` text-text-chat-menu-item-title text-sm-title line-clamp-1 flex-1`}
>
{props.title}
</div>
<div
className={`text-gray-500 text-sm group-hover:opacity-0 pl-3`}
className={`text-text-chat-menu-item-time text-sm group-hover:opacity-0 pl-3`}
>
{getTime(props.time)}
</div>
</div>
<div className={`text-gray-500 text-sm`}>
<div className={`text-text-chat-menu-item-description text-sm`}>
{Locale.ChatItem.ChatItemCount(props.count)}
</div>
</div>
@@ -145,17 +145,19 @@ export default MenuLayout(function SessionList(props) {
moveSession(source.index, destination.index);
};
let layoutClassName = "flex flex-col py-7 px-0";
let layoutClassName = "flex flex-col px-0";
let titleClassName = "py-7";
if (isMobileScreen) {
layoutClassName = "flex flex-col py-6 pb-chat-panel-mobile ";
layoutClassName = "flex flex-col pb-chat-panel-mobile ";
titleClassName = "py-6 box-content h-0";
}
return (
<div className={`h-[100%] ${layoutClassName}`}>
<div data-tauri-drag-region>
<div
className={`flex items-center justify-between`}
className={`flex items-center justify-between ${titleClassName}`}
data-tauri-drag-region
>
<div className="">
@@ -175,7 +177,9 @@ export default MenuLayout(function SessionList(props) {
<AddIcon />
</div>
</div>
<div className={`pb-3 text-sm sm:text-sm-mobile text-blue-500`}>
<div
className={`pb-3 text-sm sm:text-sm-mobile text-text-chat-header-subtitle`}
>
Build your own AI assistant.
</div>
</div>

View File

@@ -68,9 +68,6 @@ export default function DangerItems() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const btnStyle = " !shadow-none !bg-gray-50";
const textStyle = " !text-sm";
return (
<List
widgetStyle={{
@@ -126,7 +123,6 @@ export default function DangerItems() {
>
<Btn
text={Locale.Settings.Danger.Reset.Action}
className={btnStyle}
onClick={async () => {
if (await showConfirm(Locale.Settings.Danger.Reset.Confirm)) {
appConfig.reset();
@@ -141,7 +137,6 @@ export default function DangerItems() {
>
<Btn
text={Locale.Settings.Danger.Clear.Action}
className={btnStyle}
onClick={async () => {
if (await showConfirm(Locale.Settings.Danger.Clear.Confirm)) {
chatStore.clearAllData();

View File

@@ -21,7 +21,6 @@ export default function PromptSetting(props: PromptSettingProps) {
const promptStore = usePromptStore();
const customCount = promptStore.getUserPrompts().length ?? 0;
const btnStyle = " !shadow-none !bg-gray-50";
const textStyle = " !text-sm";
return (
@@ -45,7 +44,6 @@ export default function PromptSetting(props: PromptSettingProps) {
>
<div className="flex gap-3">
<Btn
className={btnStyle}
onClick={() => setShowPromptModal(true)}
text={
<span className={textStyle}>{Locale.Settings.Prompt.Edit}</span>

View File

@@ -1,5 +1,4 @@
import { useNavigate } from "react-router-dom";
import { Path } from "@/app/constant";
import Locale from "@/app/locales";
import GobackIcon from "@/app/icons/goback.svg";
@@ -19,7 +18,7 @@ export default function SettingHeader(props: ChatHeaderProps) {
let subTitleClassName = "";
if (isMobileScreen) {
containerClassName = "h-menu-title-mobile";
containerClassName = "h-menu-title-mobile bg-settings-header-mobile";
titleClassName = "flex flex-col items-center justify-center gap-0.5 text";
mainTitleClassName = "text-sm-title h-[19px] leading-5";
subTitleClassName = "text-sm-mobile-tab leading-4";
@@ -27,7 +26,7 @@ export default function SettingHeader(props: ChatHeaderProps) {
return (
<div
className={`relative flex flex-0 justify-between items-center px-6 py-4 gap-chat-header-gap border-b-[1px] border-gray-200 ${containerClassName}`}
className={`relative flex flex-0 justify-between items-center px-6 py-4 gap-chat-header-gap border-b border-settings-header ${containerClassName}`}
data-tauri-drag-region
>
{isMobileScreen ? (
@@ -41,7 +40,7 @@ export default function SettingHeader(props: ChatHeaderProps) {
<div className={`flex-1 ${titleClassName}`}>
<div
className={`line-clamp-1 cursor-pointer text-black text-chat-header-title font-common ${mainTitleClassName}`}
className={`line-clamp-1 cursor-pointer text-text-settings-panel-header-title text-chat-header-title font-common ${mainTitleClassName}`}
>
{Locale.Settings.Title}
</div>

View File

@@ -60,7 +60,7 @@ export default function Settings(props: MenuWrapperInspectProps) {
return (
<div
className={`flex flex-col overflow-hidden bg-chat-panel ${containerClassName}`}
className={`flex flex-col overflow-hidden bg-settings-panel ${containerClassName}`}
>
<SettingHeader
isMobileScreen={isMobileScreen}

View File

@@ -33,7 +33,6 @@ export default function SyncItems() {
};
}, [chatStore.sessions, maskStore.masks, promptStore.prompts]);
const btnStyle = " !shadow-none !bg-gray-50";
const textStyle = "!text-sm";
return (
<>
@@ -50,7 +49,6 @@ export default function SyncItems() {
>
<div className="flex gap-3">
<Btn
className={btnStyle}
onClick={() => {
setShowSyncConfigModal(true);
}}
@@ -58,7 +56,6 @@ export default function SyncItems() {
></Btn>
{couldSync && (
<Btn
className={btnStyle}
onClick={async () => {
try {
await syncStore.sync();
@@ -80,14 +77,12 @@ export default function SyncItems() {
>
<div className="flex gap-3">
<Btn
className={btnStyle}
onClick={() => {
syncStore.export();
}}
text={<span className={textStyle}>{Locale.UI.Export}</span>}
></Btn>
<Btn
className={btnStyle}
onClick={async () => {
syncStore.import();
}}

View File

@@ -17,9 +17,9 @@ export default MenuLayout(function SettingList(props) {
let itemClassName = "";
if (isMobileScreen) {
layoutClassName = "h-[100%] mx-[-1.5rem] px-6 py-6 bg-blue-50";
layoutClassName = "h-[100%] mx-[-1.5rem] px-6 py-6 bg-settings-menu-mobile";
titleClassName = "h-menu-title-mobile";
itemClassName = "p-4 bg-white";
itemClassName = "p-4 bg-settings-menu-item-mobile";
}
return (
@@ -29,25 +29,19 @@ export default MenuLayout(function SettingList(props) {
className={`flex items-center justify-between ${titleClassName}`}
data-tauri-drag-region
>
<div className="text-setting-title text-black font-common font-setting-title">
<div className="text-setting-title text-text-settings-menu-title font-common font-setting-title">
{Locale.Settings.Title}
</div>
</div>
{/* <div className={`pb-3 text-sm sm:text-sm-mobile text-blue-500`}>
{Locale.Settings.SubTitle}
</div> */}
</div>
<div
className={`flex flex-col overflow-y-auto overflow-x-hidden w-[100%]`}
>
<div
// className={`p-4 font-common text-setting-items font-normal text-black
// border-[1px] border-blue-200 border-opacity-0 rounded-md
// `}
className={`p-4 font-common text-setting-items font-normal text-black
border-[1px] border-blue-200 border-opacity-0 rounded-md
hover:border-opacity-100 hover:bg-blue-100 ${itemClassName}
className={`p-4 font-common text-setting-items font-normal text-text-settings-menu-item-title
border border-settings-menu-item-selected border-opacity-0 rounded-md
hover:border-opacity-100 hover:font-semibold hover:bg-settings-menu-item-selected ${itemClassName}
flex justify-between items-center
`}
onClick={() => {

View File

@@ -46,7 +46,8 @@ export function SideBar(props: { className?: string }) {
if (isMobileScreen) {
containerClassName = "flex flex-col-reverse w-[100%] h-[100%]";
tabActionsClassName = "bg-gray-100 rounded-tl-md rounded-tr-md h-mobile";
tabActionsClassName =
"bg-sidebar-mobile rounded-tl-md rounded-tr-md h-mobile";
}
return (