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

@ -81,8 +81,8 @@ export default function ActionsBar(props: ActionsBarProps) {
}%] flex flex-col items-center justify-center gap-0.5
${
selected === action.id
? "text-blue-700"
: "text-gray-400"
? "text-text-sidebar-tab-mobile-active"
: "text-text-sidebar-tab-mobile-inactive"
}
`}
onClick={handlerClick(action)}
@ -99,7 +99,9 @@ export default function ActionsBar(props: ActionsBarProps) {
<div
key={action.id}
className={`p-3 ${
selected === action.id ? "bg-blue-900" : "bg-transparent"
selected === action.id
? "bg-actions-bar-btn-default"
: "bg-transparent"
} rounded-md items-center ${action.className}`}
onClick={handlerClick(action)}
>

View File

@ -31,24 +31,22 @@ export default function Btn(props: {
switch (type) {
case "primary":
btnClassName = `${disabled ? "bg-blue-300" : "bg-blue-600"} text-white`;
btnClassName = `${
disabled ? "bg-primary-btn-disabled" : "bg-primary-btn shadow-btn"
} text-text-btn-primary `;
break;
case "danger":
btnClassName = `${
disabled ? "bg-blue-300" : "bg-blue-600"
} text-text-danger`;
btnClassName = `bg-danger-btn text-text-btn-danger`;
break;
default:
btnClassName = `${
disabled ? "bg-gray-100" : "bg-gray-300"
} text-gray-500`;
btnClassName = `bg-default-btn text-text-btn-default`;
}
return (
<button
className={`
${className ?? ""}
py-2 px-3 flex items-center justify-center gap-1 rounded-action-btn shadow-btn transition-all duration-300 select-none
py-2 px-3 flex items-center justify-center gap-1 rounded-action-btn transition-all duration-300 select-none
${disabled ? "cursor-not-allowed" : "cursor-pointer"}
${btnClassName}
`}

View File

@ -24,7 +24,7 @@ export default function Card(props: CardProps) {
{title}
</div>
)}
<div className={`px-4 py-1 rounded-lg bg-white ${className}`}>
<div className={`px-4 py-1 rounded-lg bg-card ${className}`}>
{children}
</div>
</>

View File

@ -55,11 +55,11 @@ export default function Input(props: CommonInputProps & InputProps) {
return (
<div
className={`w-[100%] rounded-chat-input bg-gray-100 flex gap-3 items-center px-3 py-2 ${className}`}
className={`w-[100%] rounded-chat-input bg-input flex gap-3 items-center px-3 py-2 ${className}`}
>
<input
{...rest}
className=" overflow-hidden text-black text-sm-title leading-input outline-none flex-1"
className=" overflow-hidden text-text-input text-sm-title leading-input outline-none flex-1"
type={internalType}
value={value}
onChange={(e) => {

View File

@ -75,9 +75,6 @@ export function ListItem(props: ListItemProps) {
default:
internalNextLine = false;
}
if (childrenMeta.type === "input") {
console.log("===============", internalNextLine, nextline, inputNextLine);
}
const update = useCallback((m: ChildrenMeta) => {
setMeta(m);
@ -85,7 +82,7 @@ export function ListItem(props: ListItemProps) {
return (
<div
className={`relative after:h-[0.5px] after:bottom-0 after:w-[100%] after:left-0 after:absolute last:after:hidden after:bg-gray-100 ${
className={`relative after:h-[0.5px] after:bottom-0 after:w-[100%] after:left-0 after:absolute last:after:hidden after:bg-list-item-divider ${
internalNextLine ? "" : "flex gap-3"
} justify-between items-center px-0 ${containerClassName} ${className}`}
onClick={onClick}
@ -96,7 +93,9 @@ export function ListItem(props: ListItemProps) {
<div className=" font-common text-sm-mobile font-weight-[500] line-clamp-1">
{title}
</div>
{subTitle && <div className={` text-sm text-gray-300`}>{subTitle}</div>}
{subTitle && (
<div className={` text-sm text-text-list-subtitle`}>{subTitle}</div>
)}
</div>
<ListContext.Provider value={{ ...context, update }}>
<div

View File

@ -13,7 +13,7 @@ export default function Loading({
}) {
let theme;
if (typeof window !== "undefined") {
theme = getCSSVar("--chat-panel-bg");
theme = getCSSVar("--default-container-bg");
}
const isMobileScreen = useMobileScreen();

View File

@ -61,7 +61,7 @@ export default function MenuLayout<
let containerClassName = "flex h-[100%] w-[100%]";
let listClassName =
"relative basis-sidebar h-[calc(100%-1.25rem)] pb-6 max-md:px-4 max-md:pb-4 rounded-md my-2.5 bg-gray-50";
"relative basis-sidebar h-[calc(100%-1.25rem)] pb-6 max-md:px-4 max-md:pb-4 rounded-md my-2.5 bg-menu";
let panelClassName = "flex-1 h-[100%] w-page";
if (isMobileScreen) {
@ -95,7 +95,7 @@ export default function MenuLayout<
onDragStart(e as any);
}}
>
<div className="opacity-0 group-hover:bg-[rgba($color: #000000, $alpha: 0.01) group-hover:opacity-20">
<div className="opacity-0 group-hover:bg-[rgba($color: #000000, $alpha: 0.01)] group-hover:opacity-20">
<DragIcon />
</div>
</div>

View File

@ -82,7 +82,7 @@ export default function Popover(props: {
let placementClassName;
let arrowClassName = "absolute left-[50%] translate-x-[calc(-50%)]";
// "absolute rotate-45 w-[8.5px] h-[8.5px] left-[50%] translate-x-[calc(-50%)] bg-black rounded-[1px] ";
arrowClassName += " ";
switch (placement) {

View File

@ -6,6 +6,8 @@ import useRelativePosition, {
} from "@/app/hooks/useRelativePosition";
import List from "@/app/components/List";
import Selected from "@/app/icons/selectedIcon.svg";
export type Option<Value> = {
value: Value;
label: string;
@ -56,15 +58,14 @@ const Select = <Value extends number | string>(props: SearchProps<Value>) => {
{options?.map((o) => (
<div
key={o.value}
className={`flex items-center p-3 gap-2 ${
selectedOption?.value === o.value ? "bg-gray-100 rounded-md" : ""
}`}
className={`flex items-center p-3 gap-2 rounded-md hover:bg-select-option-hovered`}
onClick={() => {
onSelect?.(o.value);
}}
>
{!!o.icon && <div className="">{o.icon}</div>}
<div className={`flex-1`}>{o.label}</div>
{selectedOption?.value === o.value && <Selected />}
</div>
))}
</div>
@ -78,13 +79,13 @@ const Select = <Value extends number | string>(props: SearchProps<Value>) => {
placement={
position?.poi.relativePosition[1] !== Orientation.bottom ? "rb" : "rt"
}
popoverClassName="border-actions-popover border-gray-200 rounded-md shadow-actions-popover w-actions-popover bg-white"
popoverClassName="border border-select-popover rounded-md shadow-select-popover-shadow w-actions-popover bg-select-popover-panel dark:bg-select-popover-panel-dark"
onShow={(e) => {
getRelativePosition(contentRef.current!, "");
}}
>
<div
className={`flex items-center gap-3 py-2 px-3 bg-gray-100 rounded-action-btn font-time text-sm-title ${selectClassName}`}
className={`flex items-center gap-3 py-2 px-3 bg-select rounded-action-btn font-time text-sm-title ${selectClassName}`}
ref={contentRef}
>
<div className={`flex items-center gap-2 flex-1`}>

View File

@ -55,17 +55,19 @@ export default function SlideRange(props: SlideRangeProps) {
className={`flex flex-col justify-center items-end gap-1 w-[100%] ${className} ${rangeClassName}`}
>
{!!description && (
<div className="text-text-hint text-common text-sm">{description}</div>
<div className="text-text-slider-block text-common text-sm">
{description}
</div>
)}
<div
className="flex my-1.5 relative w-[100%] h-1.5 bg-gray-200 rounded-slide"
className="flex my-1.5 relative w-[100%] h-1.5 bg-slider rounded-slide"
ref={slideRef}
>
<div className="absolute top-0 h-[100%] w-[var(--slide-value-size)] pointer-events-none bg-gray-500 rounded-slide">
<div className="absolute top-0 h-[100%] w-[var(--slide-value-size)] pointer-events-none bg-slider-slided-travel rounded-slide">
&nbsp;
</div>
<div
className=" absolute w-[30px] top-[50%] translate-y-[-50%] left-[var(--slide-value-size)] translate-x-[-50%] pointer-events-none h-slide-btn leading-slide-btn text-sm-mobile text-center rounded-slide border-[1px] border-gray-300 bg-white"
className=" absolute w-[30px] top-[50%] translate-y-[-50%] left-[var(--slide-value-size)] translate-x-[-50%] pointer-events-none h-slide-btn leading-slide-btn text-sm-mobile text-center rounded-slide border border-slider-block bg-slider-block"
// onPointerDown={onPointerDown}
>
{value}

View File

@ -15,12 +15,14 @@ export default function Switch(props: SwitchProps) {
<RadixSwitch.Root
checked={value}
onCheckedChange={onChange}
className={` flex w-switch h-switch bg-gray-200 p-0.5 box-content rounded-md ${switchClassName} ${
value ? "bg-switch-checked justify-end" : "bg-gray-200 justify-start"
className={` flex w-switch h-switch p-0.5 box-content rounded-md ${switchClassName} ${
value
? "bg-switch-checked justify-end"
: "bg-switch-unchecked justify-start"
}`}
>
<RadixSwitch.Thumb
className={` bg-white block w-4 h-4 drop-shadow-sm rounded-md`}
className={` bg-switch-btn block w-4 h-4 drop-shadow-sm rounded-md`}
/>
</RadixSwitch.Root>
);

View File

@ -9,7 +9,7 @@ export default function Thumbnail(props: ThumbnailProps) {
const { image, deleteImage } = props;
return (
<div
className={` h-thumbnail w-thumbnail cursor-default border-1 border-black border-opacity-10 rounded-action-btn flex-0 bg-cover bg-center`}
className={` h-thumbnail w-thumbnail cursor-default border border-thumbnail rounded-action-btn flex-0 bg-cover bg-center`}
style={{ backgroundImage: `url("${image}")` }}
>
<div

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="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),
);
}}
>
<div className={styles["clear-context-tips"]}>{Locale.Context.Clear}</div>
<div className={styles["clear-context-revert-btn"]}>
{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 (

View File

@ -1,4 +1,4 @@
import { useState } from "react";
import { useEffect, useState } from "react";
import { useDebouncedCallback } from "use-debounce";
import { autoGrowTextArea } from "../utils";
import { useAppConfig } from "../store";
@ -10,13 +10,14 @@ export default function useRows({
}) {
const [inputRows, setInputRows] = useState(2);
const config = useAppConfig();
const { isMobileScreen } = config;
const measure = useDebouncedCallback(
() => {
const rows = inputRef.current ? autoGrowTextArea(inputRef.current) : 1;
const inputRows = Math.min(
20,
Math.max(2 + (config.isMobileScreen ? -1 : 1), rows),
Math.max(2 + (isMobileScreen ? -1 : 1), rows),
);
setInputRows(inputRows);
},
@ -27,6 +28,10 @@ export default function useRows({
},
);
useEffect(() => {
measure();
}, [isMobileScreen]);
return {
inputRows,
measure,

View File

@ -1,34 +1,14 @@
import { useEffect } from "react";
import { useAppConfig } from "@/app/store/config";
import { getCSSVar } from "@/app/utils";
import { Theme, useAppConfig } from "@/app/store/config";
export function useSwitchTheme() {
const config = useAppConfig();
useEffect(() => {
document.body.classList.remove("light");
document.body.classList.remove("dark");
if (config.theme === "dark") {
if (config.theme === Theme.Dark) {
document.body.classList.add("dark");
} else if (config.theme === "light") {
document.body.classList.add("light");
}
const metaDescriptionDark = document.querySelector(
'meta[name="theme-color"][media*="dark"]',
);
const metaDescriptionLight = document.querySelector(
'meta[name="theme-color"][media*="light"]',
);
if (config.theme === "auto") {
metaDescriptionDark?.setAttribute("content", "#151515");
metaDescriptionLight?.setAttribute("content", "#fafafa");
} else {
const themeColor = getCSSVar("--theme-color");
metaDescriptionDark?.setAttribute("content", themeColor);
metaDescriptionLight?.setAttribute("content", themeColor);
}
}, [config.theme]);
}

View File

@ -0,0 +1,3 @@
<svg width="21" height="16" viewBox="0 0 21 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.1645 2.89288C20.4997 3.25987 20.474 3.82914 20.107 4.16437L10.254 13.1644C9.89015 13.4967 9.32664 13.4747 8.98991 13.1148L3.84285 7.61482C3.50321 7.2519 3.52209 6.68236 3.88502 6.34273C4.24794 6.00309 4.81748 6.02197 5.15711 6.3849L9.69659 11.2357L18.893 2.83535C19.26 2.50012 19.8293 2.52588 20.1645 2.89288Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 482 B

View File

@ -409,8 +409,8 @@ const cn = {
Toast: (x: any) => `包含 ${x} 条预设提示词`,
Edit: "当前对话设置",
Add: "新增一条对话",
Clear: "上下文已清除",
Revert: "恢复上下文",
Clear: "解除以上内容关联",
Revert: "撤销",
},
Plugin: {
Name: "插件",

View File

@ -24,13 +24,96 @@ body {
overflow: hidden;
}
*:focus-visible {
outline: none;
}
:root {
--tip-popover-color: #434360;
--chat-panel-bg: rgb(249, 250, 251, 1);
--global-bg: #e3e3ed;
--actived-widget-bg: #2e42f3;
--primary-btn-disabled-bg: rgba(60, 68, 255, 0.2);
--danger-btn-bg: #fff6f6;
--default-widget-bg: #f7f7f8;
--default-container-bg: #f7f7f8;
--similar-panel-bg: #fff;
--similar-highlight-hood-bg: #fff;
--similar-widget-btn-bg: #fff;
--chat-panel-message-bot-bg: #fff;
--chat-panel-message-user-bg: #4a5cff;
--similar-line-bg: #f0f0f3;
--chat-panel-message-mobile-bg: #f0f0f3;
--chat-menu-session-unselected-bg: #f0f0f3;
--similar-btn-hovered-bg: rgba(0, 0, 0, 0.05);
--slider-slided-travel-bg: #88889a;
--switch-unchecked-bg: #c9c9d1;
--chat-actions-btn-popover-bg: #434360;
--chat-panel-message-clear-divider-bg: #e2e2e6;
--chat-menu-session-hovered-bg: #e2e2e6;
--menu-item-selected-bg: #dee1fd;
--small-widget-border: rgba(0, 0, 0, 0.1);
--slider-block-border: #c9c9d1;
--chat-actions-popover-mobile-border: #f0f0f3;
--panel-header-border: #e2e2e6;
--chat-input-hood-border: #fff;
--chat-input-hood-focus-border: #606078;
--menu-item-selected-border: #c9cefc;
--sidebar-tab-mobile-active-text: #2e42f3;
--bg-contract-text: #fff;
--danger-btn-text: #ff5454;
--btn-default-text: #606078;
--weakness-text: #a5a5b3;
--key-text: #18182a;
--description-text: #88889a;
--message-clear-revert-text: #3c44ff;
--menu-item-time: rgba(0, 0, 0, 0.3);
--siderbar-mobile-height: 3.125rem;
--max-message-width: calc(var(--chat-panel-max-width) * 0.6);
}
.dark {
--global-bg: #303030;
--actived-widget-bg: #384cfc;
--primary-btn-disabled-bg: rgba(60, 68, 255, 0.2);
--danger-btn-bg: #20131a;
--default-widget-bg: #1d1d1d;
--default-container-bg: #1d1d1d;
--similar-panel-bg: #111;
--similar-highlight-hood-bg: #fff;
--similar-widget-btn-bg: #fff;
--chat-panel-message-bot-bg: #fff;
--chat-panel-message-user-bg: #4a5cff;
--similar-line-bg: #f0f0f3;
--chat-panel-message-mobile-bg: #f0f0f3;
--chat-menu-session-unselected-bg: #f0f0f3;
--similar-btn-hovered-bg: rgba(0, 0, 0, 0.05);
--slider-slided-travel-bg: #88889a;
--switch-unchecked-bg: #c9c9d1;
--chat-actions-btn-popover-bg: #434360;
--chat-panel-message-clear-divider-bg: #e2e2e6;
--chat-menu-session-hovered-bg: #e2e2e6;
--menu-item-selected-bg: #dee1fd;
--small-widget-border: rgba(0, 0, 0, 0.1);
--slider-block-border: #c9c9d1;
--chat-actions-popover-mobile-border: #f0f0f3;
--panel-header-border: #e2e2e6;
--chat-input-hood-border: #fff;
--chat-input-hood-focus-border: #606078;
--menu-item-selected-border: #c9cefc;
--sidebar-tab-mobile-active-text: #2e42f3;
--bg-contract-text: #fff;
--danger-btn-text: #ff5454;
--btn-default-text: #606078;
--weakness-text: #a5a5b3;
--key-text: #18182a;
--description-text: #88889a;
--message-clear-revert-text: #3c44ff;
--menu-item-time: rgba(0, 0, 0, 0.3);
--select-popover-panel-bg: #1d1d1d;
}
input {
text-align: inherit;
background-color: inherit;

View File

@ -42,6 +42,18 @@ module.exports = {
'chat-input-mobile': '19px',
'chat-input': '60px',
},
height: {
mobile: 'var(--siderbar-mobile-height)',
// mobile: '3.125rem',
'menu-title-mobile': '3rem',
'thumbnail': '5rem',
'chat-input-mobile': '19px',
'chat-input': '60px',
'chat-panel-mobile': '- var(--siderbar-mobile-height)',
'setting-panel-mobile': 'calc(100vh - var(--siderbar-mobile-height))',
'slide-btn': '18px',
'switch': '1rem',
},
minWidth: {
'select-mobile-lg': '200px',
'select-mobile': '170px',
@ -59,18 +71,6 @@ module.exports = {
'actions-popover': '203px',
'switch': '2.25rem',
},
height: {
mobile: 'var(--siderbar-mobile-height)',
// mobile: '3.125rem',
'menu-title-mobile': '3rem',
'thumbnail': '5rem',
'chat-input-mobile': '19px',
'chat-input': '60px',
'chat-panel-mobile': '- var(--siderbar-mobile-height)',
'setting-panel-mobile': 'calc(100vh - var(--siderbar-mobile-height))',
'slide-btn': '18px',
'switch': '1rem',
},
flexBasis: {
'sidebar': 'var(--menu-width)',
'page': 'calc(100% - var(--menu-width))',
@ -81,8 +81,53 @@ module.exports = {
'chat-panel-mobile': 'var(--siderbar-mobile-height)',
'message-img': 'calc((100%- var(--img-gap-count)*0.25rem)/var(--img-count))',
},
backgroundColor: {
'global': 'var(--global-bg)',
'actions-bar-btn-default': 'var(--actived-widget-bg)',
'primary-btn': 'var(--actived-widget-bg)',
'primary-btn-disabled': 'var(--primary-btn-disabled-bg)',
'danger-btn': 'var(--danger-btn-bg)',
'default-btn': 'var(--default-widget-bg)',
'card': 'var(--similar-panel-bg)',
'input': 'var(--default-widget-bg)',
'list-item-divider': 'var(--similar-line-bg)',
'menu': 'var(--default-container-bg)',
'select-option-hovered': 'var(--similar-btn-hovered-bg)',
'select-popover-panel': 'var(--similar-panel-bg)',
'select-popover-panel-dark': 'var(--select-popover-panel-bg)',
'select': 'var(--default-widget-bg)',
'slider': 'var(--similar-line-bg)',
'slider-slided-travel': 'var(--slider-slided-travel-bg)',
'slider-block': 'var(--similar-widget-btn-bg)',
'switch-unchecked': 'var(--switch-unchecked-bg)',
'switch-checked': 'var(--actived-widget-bg)',
'switch-btn': 'var(--similar-widget-btn-bg)',
'chat-actions-popover-panel-mobile': 'var(--similar-panel-bg)',
'chat-actions-btn-popover': 'var(--chat-actions-btn-popover-bg)',
'chat-actions-btn-hovered': 'var(--similar-btn-hovered-bg)',
'chat-panel-header-mask': 'var(--default-container-bg)',
'chat-panel-header-mobile': 'var(--similar-highlight-hood-bg)',
'chat-panel-input-hood': 'var(--similar-highlight-hood-bg)',
'chat-panel-message-user': 'var(--chat-panel-message-user-bg)',
'chat-panel-message-bot': 'var(--chat-panel-message-bot-bg)',
'chat-panel-message': 'var(--default-container-bg)',
'chat-panel-message-mobile': 'var(--chat-panel-message-mobile-bg)',
'chat-message-actions': 'var(--similar-panel-bg)',
'chat-message-actions-btn-hovered': 'var(--similar-btn-hovered-bg)',
'chat-panel': 'var(--default-container-bg)',
'chat-panel-message-clear-divider': 'var(--chat-panel-message-clear-divider-bg)',
'chat-menu-session-selected': 'var(--menu-item-selected-bg)',
'chat-menu-session-unselected': 'var(--chat-menu-session-unselected-bg)',
'chat-menu-session-hovered': 'var(--chat-menu-session-hovered-bg)',
'settings-menu-mobile': 'var(--default-container-bg)',
'settings-menu-item-mobile': 'var(--similar-highlight-hood-bg)',
'settings-menu-item-selected': 'var(--menu-item-selected-bg)',
'settings-header-mobile': 'var(--similar-highlight-hood-bg)',
'settings-panel': 'var(--default-container-bg)',
'sidebar-mobile': 'var(--similar-highlight-hood-bg)',
},
backgroundImage: {
'message-bg': 'linear-gradient(259deg, #9786FF 8.42%, #4A5CFF 90.13%)',
// 'chat-panel-message-user': 'linear-gradient(259deg, #9786FF 8.42%, #4A5CFF 90.13%)',
'thumbnail-mask': 'linear-gradient(0deg, rgba(0, 0, 0, 0.50) 0%, rgba(0, 0, 0, 0.50) 100%)',
},
transitionProperty: {
@ -94,23 +139,49 @@ module.exports = {
'message-width': 'var(--max-message-width)',
'setting-list': '710px',
},
backgroundColor: {
'select-btn': 'rgba(0, 0, 0, 0.05)',
'chat-actions-popover-color': 'var(--tip-popover-color)',
'chat-panel': 'var(--chat-panel-bg)',
'global': '#E3E3ED',
'switch-checked': '#2E42F3',
},
boxShadow: {
'btn': '0px 4px 10px 0px rgba(60, 68, 255, 0.14)',
'chat-input': '0px 4px 20px 0px rgba(60, 68, 255, 0.13)',
'actions-popover': '0px 14px 40px 0px rgba(0, 0, 0, 0.12)',
'actions-bar': '0px 4px 30px 0px rgba(0, 0, 0, 0.10)',
'chat-actions-popover-mobile': '0px 14px 40px 0px rgba(0, 0, 0, 0.12)',
'chat-input-hood-focus-shadow': '0px 4px 20px 0px rgba(60, 68, 255, 0.13)',
'select-popover-shadow': '0px 14px 40px 0px rgba(0, 0, 0, 0.12)',
'message-actions-bar': '0px 4px 30px 0px var(--small-widget-border)',
'prompt-hint-container': 'inset 0 4px 8px 0 rgba(0, 0, 0, 0.1)'
},
colors: {
'text-hint': '#A5A5B3',
'text-danger': '#FF5454',
'select-popover': 'var(--small-widget-border)',
'slider-block': 'var(--slider-block-border)',
'thumbnail': 'var(--small-widget-border)',
'chat-actions-popover-mobile': 'var(--chat-actions-popover-mobile-border)',
'chat-header-bottom': 'var(--panel-header-border)',
'chat-input-top': 'var(--panel-header-border)',
'chat-input-hood': 'var(--chat-input-hood-border)',
'chat-input-hood-focus': 'var(--chat-input-hood-focus-border)',
'chat-menu-session-selected': 'var(--menu-item-selected-border)',
'settings-menu-item-selected': 'var(--menu-item-selected-border)',
'settings-header': 'var(--panel-header-border)',
'text-sidebar-tab-mobile-active': 'var(--sidebar-tab-mobile-active-text)',
'text-sidebar-tab-mobile-inactive': 'var(--weakness-text)',
'text-btn-primary': 'var(--bg-contract-text)',
'text-btn-danger': 'var(--danger-btn-text)',
'text-btn-default': 'var(--btn-default-text)',
'text-input': 'var(--key-text)',
'text-list-subtitle': 'var(--weakness-text)',
'text-slider-block': 'var(--btn-default-text)',
'text-chat-actions-btn-popover': 'var(--bg-contract-text)',
'text-chat-header-title': 'var(--key-text)',
'text-chat-header-subtitle': 'var(--description-text)',
'text-chat-input-placeholder': 'var(--description-text)',
'text-chat-message-date': 'var(--description-text)',
'text-chat-message-markdown-user': 'var(--bg-contract-text)',
'text-chat-message-markdown-bot': 'var(--key-text)',
'text-chat-panel-message-clear': 'var(--weakness-text)',
'text-chat-panel-message-clear-revert': 'var(--message-clear-revert-text)',
'text-chat-menu-item-title': 'var(--key-text)',
'text-chat-menu-item-time': 'var(--menu-item-time)',
'text-chat-menu-item-description': 'var(--description-text)',
'text-settings-menu-title': 'var(--key-text)',
'text-settings-menu-item-title': 'var(--key-text)',
'text-settings-panel-header-title': 'var(--key-text)',
},
},
borderRadius: {
@ -129,13 +200,6 @@ module.exports = {
},
borderWidth: {
DEFAULT: '1px',
'0': '0',
'2': '2px',
'3': '3px',
'4': '4px',
'6': '6px',
'8': '8px',
'actions-popover': '1px',
},
},
plugins: [],