diff --git a/app/components/button.module.scss b/app/components/button.module.scss index e7d5d89..3a3393e 100644 --- a/app/components/button.module.scss +++ b/app/components/button.module.scss @@ -49,4 +49,7 @@ .icon-button-text { margin-left: 5px; font-size: 12px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } diff --git a/app/components/chat-list.tsx b/app/components/chat-list.tsx index ab5d849..cab8812 100644 --- a/app/components/chat-list.tsx +++ b/app/components/chat-list.tsx @@ -96,7 +96,7 @@ export function ChatList() { index={i} selected={i === selectedIndex} onClick={() => selectSession(i)} - onDelete={chatStore.deleteSession} + onDelete={() => chatStore.deleteSession(i)} /> ))} {provided.placeholder} diff --git a/app/components/chat.tsx b/app/components/chat.tsx index c5c257e..d25deec 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -3,7 +3,7 @@ import { memo, useState, useRef, useEffect, useLayoutEffect } from "react"; import SendWhiteIcon from "../icons/send-white.svg"; import BrainIcon from "../icons/brain.svg"; -import ExportIcon from "../icons/export.svg"; +import ExportIcon from "../icons/share.svg"; import ReturnIcon from "../icons/return.svg"; import CopyIcon from "../icons/copy.svg"; import DownloadIcon from "../icons/download.svg"; @@ -11,6 +11,8 @@ import LoadingIcon from "../icons/three-dots.svg"; import BotIcon from "../icons/bot.svg"; import AddIcon from "../icons/add.svg"; import DeleteIcon from "../icons/delete.svg"; +import MaxIcon from "../icons/max.svg"; +import MinIcon from "../icons/min.svg"; import { Message, @@ -19,6 +21,7 @@ import { BOT_HELLO, ROLES, createMessage, + useAccessStore, } from "../store"; import { @@ -485,11 +488,17 @@ export function Chat(props: { const context: RenderMessage[] = session.context.slice(); + const accessStore = useAccessStore(); + if ( context.length === 0 && session.messages.at(0)?.content !== BOT_HELLO.content ) { - context.push(BOT_HELLO); + const copiedHello = Object.assign({}, BOT_HELLO); + if (!accessStore.isAuthorized()) { + copiedHello.content = Locale.Error.Unauthorized; + } + context.push(copiedHello); } // preview messages @@ -584,6 +593,17 @@ export function Chat(props: { }} /> +
+ : } + bordered + onClick={() => { + chatStore.updateConfig( + (config) => (config.tightBorder = !config.tightBorder), + ); + }} + /> +
Math.min(500, Math.max(220, x)); + + const chatStore = useChatStore(); + const startX = useRef(0); + const startDragWidth = useRef(chatStore.config.sidebarWidth ?? 300); + const lastUpdateTime = useRef(Date.now()); + + const handleMouseMove = useRef((e: MouseEvent) => { + if (Date.now() < lastUpdateTime.current + 100) { + return; + } + lastUpdateTime.current = Date.now(); + const d = e.clientX - startX.current; + const nextWidth = limit(startDragWidth.current + d); + chatStore.updateConfig((config) => (config.sidebarWidth = nextWidth)); + }); + + const handleMouseUp = useRef(() => { + startDragWidth.current = chatStore.config.sidebarWidth ?? 300; + window.removeEventListener("mousemove", handleMouseMove.current); + window.removeEventListener("mouseup", handleMouseUp.current); + }); + + const onDragMouseDown = (e: MouseEvent) => { + startX.current = e.clientX; + + window.addEventListener("mousemove", handleMouseMove.current); + window.addEventListener("mouseup", handleMouseUp.current); + }; + + useEffect(() => { + document.documentElement.style.setProperty( + "--sidebar-width", + `${limit(chatStore.config.sidebarWidth ?? 300)}px`, + ); + }, [chatStore.config.sidebarWidth]); + + return { + onDragMouseDown, + }; +} + const useHasHydrated = () => { const [hasHydrated, setHasHydrated] = useState(false); @@ -101,6 +151,9 @@ function _Home() { const [openSettings, setOpenSettings] = useState(false); const config = useChatStore((state) => state.config); + // drag side bar + const { onDragMouseDown } = useDragSideBar(); + useSwitchTheme(); if (loading) { @@ -174,6 +227,11 @@ function _Home() { /> + +
onDragMouseDown(e as any)} + >
diff --git a/app/components/settings.module.scss b/app/components/settings.module.scss index 7d40d83..830e1ba 100644 --- a/app/components/settings.module.scss +++ b/app/components/settings.module.scss @@ -19,11 +19,16 @@ cursor: pointer; } -.password-input { +.password-input-container { + max-width: 50%; display: flex; justify-content: flex-end; .password-eye { margin-right: 4px; } + + .password-input { + min-width: 80%; + } } diff --git a/app/components/settings.tsx b/app/components/settings.tsx index 0d1c1d0..bbb28b4 100644 --- a/app/components/settings.tsx +++ b/app/components/settings.tsx @@ -60,13 +60,17 @@ function PasswordInput(props: HTMLProps) { } return ( -
+
: } onClick={changeVisibility} className={styles["password-eye"]} /> - +
); } @@ -120,8 +124,7 @@ export function Settings(props: { closeSettings: () => void }) { const builtinCount = SearchService.count.builtin; const customCount = promptStore.prompts.size ?? 0; - const showUsage = !!accessStore.token || !!accessStore.accessCode; - + const showUsage = accessStore.isAuthorized(); useEffect(() => { checkUpdate(); showUsage && checkUsage(); @@ -342,37 +345,7 @@ export function Settings(props: { closeSettings: () => void }) { > - - - - updateConfig( - (config) => - (config.disablePromptHint = e.currentTarget.checked), - ) - } - > - - - } - text={Locale.Settings.Prompt.Edit} - onClick={() => showToast(Locale.WIP)} - /> - - {enabledAccessControl ? ( void }) { + + + + updateConfig( + (config) => + (config.disablePromptHint = e.currentTarget.checked), + ) + } + > + + + + } + text={Locale.Settings.Prompt.Edit} + onClick={() => showToast(Locale.WIP)} + /> + + +