diff --git a/app/components/chat.module.scss b/app/components/chat.module.scss index a3ab56062..d407d28e4 100644 --- a/app/components/chat.module.scss +++ b/app/components/chat.module.scss @@ -14,10 +14,11 @@ padding: 4px 10px; animation: slide-in ease 0.3s; box-shadow: var(--card-shadow); - transition: all ease 0.3s; + transition: width ease 0.3s; align-items: center; height: 16px; width: var(--icon-width); + overflow: hidden; &:not(:last-child) { margin-right: 5px; @@ -29,14 +30,16 @@ opacity: 0; transform: translateX(-5px); transition: all ease 0.3s; - transition-delay: 0.1s; pointer-events: none; } &:hover { + --delay: 0.5s; width: var(--full-width); + transition-delay: var(--delay); .text { + transition-delay: var(--delay); opacity: 1; transform: translate(0); } diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 7f54a7dd5..58dc01bd0 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -370,18 +370,27 @@ function ChatAction(props: { function useScrollToBottom() { // for auto-scroll const scrollRef = useRef(null); - const [autoScroll, setAutoScroll] = useState(true); + const autoScroll = useRef(true); const scrollToBottom = useCallback(() => { const dom = scrollRef.current; if (dom) { requestAnimationFrame(() => dom.scrollTo(0, dom.scrollHeight)); } }, []); + const setAutoScroll = (enable: boolean) => { + autoScroll.current = enable; + }; // auto scroll useEffect(() => { - autoScroll && scrollToBottom(); - }); + const intervalId = setInterval(() => { + if (autoScroll.current) { + scrollToBottom(); + } + }, 30); + return () => clearInterval(intervalId); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); return { scrollRef, @@ -504,6 +513,7 @@ export function ChatActions(props: { {showModelSelector && ( ({ title: m, value: m, @@ -531,7 +541,7 @@ export function EditMessageModal(props: { onClose: () => void }) { return (
[ - state.currentSession(), - state.currentSessionIndex, - ]); + const session = chatStore.currentSession(); const config = useAppConfig(); const fontSize = config.fontSize; @@ -607,9 +614,14 @@ export function Chat() { const isMobileScreen = useMobileScreen(); const navigate = useNavigate(); + const lastBodyScroolTop = useRef(0); const onChatBodyScroll = (e: HTMLElement) => { const isTouchBottom = e.scrollTop + e.clientHeight >= e.scrollHeight - 10; setHitBottom(isTouchBottom); + + // only enable auto scroll when scroll down and touched bottom + setAutoScroll(e.scrollTop >= lastBodyScroolTop.current && isTouchBottom); + lastBodyScroolTop.current = e.scrollTop; }; // prompt hints @@ -1035,7 +1047,6 @@ export function Chat() { ref={scrollRef} onScroll={(e) => onChatBodyScroll(e.currentTarget)} onMouseDown={() => inputRef.current?.blur()} - onWheel={(e) => setAutoScroll(hitBottom && e.deltaY > 0)} onTouchStart={() => { inputRef.current?.blur(); setAutoScroll(false); @@ -1147,7 +1158,7 @@ export function Chat() { }} fontSize={fontSize} parentRef={scrollRef} - defaultShow={i >= messages.length - 10} + defaultShow={i >= messages.length - 6} />
@@ -1192,7 +1203,6 @@ export function Chat() { value={userInput} onKeyDown={onInputKeyDown} onFocus={() => setAutoScroll(true)} - onBlur={() => setAutoScroll(false)} rows={inputRows} autoFocus={autoFocus} style={{ diff --git a/app/components/model-config.tsx b/app/components/model-config.tsx index 76866129b..63950a40d 100644 --- a/app/components/model-config.tsx +++ b/app/components/model-config.tsx @@ -76,7 +76,7 @@ export function ModelConfigList(props: { props.updateConfig( @@ -169,7 +169,7 @@ export function ModelConfigList(props: { title={props.modelConfig.historyMessageCount.toString()} value={props.modelConfig.historyMessageCount} min="0" - max="32" + max="64" step="1" onChange={(e) => props.updateConfig( diff --git a/app/components/ui-lib.tsx b/app/components/ui-lib.tsx index bf83712da..7025daf7e 100644 --- a/app/components/ui-lib.tsx +++ b/app/components/ui-lib.tsx @@ -443,6 +443,7 @@ export function Selector(props: { subTitle?: string; value: T; }>; + defaultSelectedValue?: T; onSelection?: (selection: T[]) => void; onClose?: () => void; multiple?: boolean; @@ -452,6 +453,7 @@ export function Selector(props: {
{props.items.map((item, i) => { + const selected = props.defaultSelectedValue === item.value; return ( (props: { props.onSelection?.([item.value]); props.onClose?.(); }} - > + > + {selected ? ( +
+ ) : ( + <> + )} + ); })}
diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 9b80e6269..87a815953 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -19,6 +19,7 @@ const cn = { Chat: { SubTitle: (count: number) => `与 SoulShellGPT 的 ${count} 条对话`, EditMessage: { + Title: "编辑消息记录", Topic: { Title: "聊天主题", SubTitle: "更改当前聊天主题", @@ -274,7 +275,7 @@ const cn = { Context: { Toast: (x: any) => `包含 ${x} 条预设提示词`, Edit: "当前对话设置", - Add: "新增预设对话", + Add: "新增一条对话", Clear: "上下文已清除", Revert: "恢复上下文", }, diff --git a/app/locales/cs.ts b/app/locales/cs.ts index 63d2c237f..b8a3b974c 100644 --- a/app/locales/cs.ts +++ b/app/locales/cs.ts @@ -5,7 +5,7 @@ const cs: PartialLocaleType = { WIP: "V přípravě...", Error: { Unauthorized: - "Neoprávněný přístup, zadejte přístupový kód na stránce nastavení.", + "Neoprávněný přístup, zadejte přístupový kód na [stránce](/#/auth) nastavení.", }, ChatItem: { ChatItemCount: (count: number) => `${count} zpráv`, diff --git a/app/locales/de.ts b/app/locales/de.ts index e8d4dc9c7..59b1fc927 100644 --- a/app/locales/de.ts +++ b/app/locales/de.ts @@ -5,7 +5,7 @@ const de: PartialLocaleType = { WIP: "In Bearbeitung...", Error: { Unauthorized: - "Unbefugter Zugriff, bitte geben Sie den Zugangscode auf der Einstellungsseite ein.", + "Unbefugter Zugriff, bitte geben Sie den Zugangscode auf der [Einstellungsseite](/#/auth) ein.", }, ChatItem: { ChatItemCount: (count: number) => `${count} Nachrichten`, diff --git a/app/locales/en.ts b/app/locales/en.ts index 4d9f633de..db60a32d4 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -21,6 +21,7 @@ const en: LocaleType = { Chat: { SubTitle: (count: number) => `${count} messages with SoulShellGPT`, EditMessage: { + Title: "Edit All Messages", Topic: { Title: "Topic", SubTitle: "Change the current topic", diff --git a/app/locales/es.ts b/app/locales/es.ts index 5f5ffc75d..6145eccc8 100644 --- a/app/locales/es.ts +++ b/app/locales/es.ts @@ -5,7 +5,7 @@ const es: PartialLocaleType = { WIP: "En construcción...", Error: { Unauthorized: - "Acceso no autorizado, por favor ingrese el código de acceso en la página de configuración.", + "Acceso no autorizado, por favor ingrese el código de acceso en la [página](/#/auth) de configuración.", }, ChatItem: { ChatItemCount: (count: number) => `${count} mensajes`, diff --git a/app/locales/fr.ts b/app/locales/fr.ts index f4cd1490d..a98d4a432 100644 --- a/app/locales/fr.ts +++ b/app/locales/fr.ts @@ -5,7 +5,7 @@ const fr: PartialLocaleType = { WIP: "Prochainement...", Error: { Unauthorized: - "Accès non autorisé, veuillez saisir le code d'accès dans la page des paramètres.", + "Accès non autorisé, veuillez saisir le code d'accès dans la [page](/#/auth) des paramètres.", }, ChatItem: { ChatItemCount: (count: number) => `${count} messages en total`, diff --git a/app/locales/it.ts b/app/locales/it.ts index 4b74ff3f0..6a2eabf40 100644 --- a/app/locales/it.ts +++ b/app/locales/it.ts @@ -5,7 +5,7 @@ const it: PartialLocaleType = { WIP: "Work in progress...", Error: { Unauthorized: - "Accesso non autorizzato, inserire il codice di accesso nella pagina delle impostazioni.", + "Accesso non autorizzato, inserire il codice di accesso nella [pagina](/#/auth) delle impostazioni.", }, ChatItem: { ChatItemCount: (count: number) => `${count} messaggi`, diff --git a/app/locales/ko.ts b/app/locales/ko.ts index ac5ee5df2..194e44769 100644 --- a/app/locales/ko.ts +++ b/app/locales/ko.ts @@ -5,7 +5,8 @@ import type { PartialLocaleType } from "./index"; const ko: PartialLocaleType = { WIP: "곧 출시 예정...", Error: { - Unauthorized: "권한이 없습니다. 설정 페이지에서 액세스 코드를 입력하세요.", + Unauthorized: + "권한이 없습니다. 설정 페이지에서 액세스 코드를 [입력하세요](/#/auth).", }, ChatItem: { ChatItemCount: (count: number) => `${count}개의 메시지`, diff --git a/app/locales/no.ts b/app/locales/no.ts index e4b834964..43c92916f 100644 --- a/app/locales/no.ts +++ b/app/locales/no.ts @@ -4,7 +4,8 @@ import type { PartialLocaleType } from "./index"; const no: PartialLocaleType = { WIP: "Arbeid pågår ...", Error: { - Unauthorized: "Du har ikke tilgang. Vennlig oppgi tildelt adgangskode.", + Unauthorized: + "Du har ikke tilgang. [Vennlig oppgi tildelt adgangskode](/#/auth).", }, ChatItem: { ChatItemCount: (count: number) => `${count} meldinger`, diff --git a/app/locales/ru.ts b/app/locales/ru.ts index 76be21a36..313acf544 100644 --- a/app/locales/ru.ts +++ b/app/locales/ru.ts @@ -5,7 +5,7 @@ const ru: PartialLocaleType = { WIP: "Скоро...", Error: { Unauthorized: - "Несанкционированный доступ. Пожалуйста, введите код доступа на странице настроек.", + "Несанкционированный доступ. Пожалуйста, введите код доступа на [странице](/#/auth) настроек.", }, ChatItem: { ChatItemCount: (count: number) => `${count} сообщений`, diff --git a/app/locales/tr.ts b/app/locales/tr.ts index ad6b66fd4..46fdd6285 100644 --- a/app/locales/tr.ts +++ b/app/locales/tr.ts @@ -5,7 +5,7 @@ const tr: PartialLocaleType = { WIP: "Çalışma devam ediyor...", Error: { Unauthorized: - "Yetkisiz erişim, lütfen erişim kodunu ayarlar sayfasından giriniz.", + "Yetkisiz erişim, lütfen erişim kodunu ayarlar [sayfasından](/#/auth) giriniz.", }, ChatItem: { ChatItemCount: (count: number) => `${count} mesaj`, diff --git a/app/locales/tw.ts b/app/locales/tw.ts index 7ec8aaee0..175629c7b 100644 --- a/app/locales/tw.ts +++ b/app/locales/tw.ts @@ -4,7 +4,7 @@ import type { PartialLocaleType } from "./index"; const tw: PartialLocaleType = { WIP: "該功能仍在開發中……", Error: { - Unauthorized: "目前您的狀態是未授權,請前往設定頁面輸入授權碼。", + Unauthorized: "目前您的狀態是未授權,請前往[設定頁面](/#/auth)輸入授權碼。", }, ChatItem: { ChatItemCount: (count: number) => `${count} 條對話`, diff --git a/app/store/config.ts b/app/store/config.ts index dbecf1ae1..e865f024c 100644 --- a/app/store/config.ts +++ b/app/store/config.ts @@ -81,7 +81,7 @@ export const ModalConfigValidator = { return x as ModelType; }, max_tokens(x: number) { - return limitNumber(x, 0, 32000, 2000); + return limitNumber(x, 0, 100000, 2000); }, presence_penalty(x: number) { return limitNumber(x, -2, 2, 0);