fix(ui): add toggle for holding long assistant replies
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Show, createEffect, createMemo, createSignal, onCleanup, on, untrack } from "solid-js"
|
||||
import { MoreHorizontal, Trash, X } from "lucide-solid"
|
||||
import { MoreHorizontal, Pause, Trash, X } from "lucide-solid"
|
||||
import Kbd from "./kbd"
|
||||
import MessageBlock from "./message-block"
|
||||
import { getMessageAnchorId, getMessageIdFromAnchorId } from "./message-anchors"
|
||||
@@ -42,10 +42,11 @@ export interface MessageSectionProps {
|
||||
}
|
||||
|
||||
export default function MessageSection(props: MessageSectionProps) {
|
||||
const { preferences } = useConfig()
|
||||
const { preferences, updatePreferences } = useConfig()
|
||||
const { t } = useI18n()
|
||||
const showUsagePreference = () => preferences().showUsageMetrics ?? true
|
||||
const showTimelineToolsPreference = () => preferences().showTimelineTools ?? true
|
||||
const holdLongAssistantRepliesEnabled = () => preferences().holdLongAssistantReplies ?? true
|
||||
const store = createMemo<InstanceMessageStore>(() => messageStoreBus.getOrCreate(props.instanceId))
|
||||
const messageIds = createMemo(() => store().getSessionMessageIds(props.sessionId))
|
||||
const visibleMessageIds = createMemo(() => {
|
||||
@@ -635,10 +636,15 @@ export default function MessageSection(props: MessageSectionProps) {
|
||||
})
|
||||
|
||||
const autoPinHoldTargetKey = createMemo(() => {
|
||||
if (!holdLongAssistantRepliesEnabled()) return null
|
||||
const messageId = lastVisibleMessageId()
|
||||
return isAssistantTextMessage(messageId) ? messageId : null
|
||||
})
|
||||
|
||||
function toggleHoldLongAssistantReplies() {
|
||||
updatePreferences({ holdLongAssistantReplies: !holdLongAssistantRepliesEnabled() })
|
||||
}
|
||||
|
||||
function isAssistantTextMessage(messageId: string | null | undefined) {
|
||||
if (!messageId) return false
|
||||
const resolvedStore = store()
|
||||
@@ -1109,6 +1115,52 @@ export default function MessageSection(props: MessageSectionProps) {
|
||||
scrollToBottomAriaLabel={() => t("messageSection.scroll.toLatestAriaLabel")}
|
||||
registerApi={(api) => setListApi(api)}
|
||||
registerState={(state) => setListState(state)}
|
||||
renderControls={(state, api) => (
|
||||
<div class="message-scroll-button-wrapper">
|
||||
<button
|
||||
type="button"
|
||||
class="message-scroll-button"
|
||||
data-active={holdLongAssistantRepliesEnabled() ? "true" : "false"}
|
||||
onClick={toggleHoldLongAssistantReplies}
|
||||
aria-label={
|
||||
holdLongAssistantRepliesEnabled()
|
||||
? t("messageSection.scroll.disableHoldAriaLabel")
|
||||
: t("messageSection.scroll.enableHoldAriaLabel")
|
||||
}
|
||||
title={
|
||||
holdLongAssistantRepliesEnabled()
|
||||
? t("messageSection.scroll.disableHoldAriaLabel")
|
||||
: t("messageSection.scroll.enableHoldAriaLabel")
|
||||
}
|
||||
>
|
||||
<Pause class="message-scroll-icon message-scroll-icon--toggle w-4 h-4" aria-hidden="true" />
|
||||
</button>
|
||||
<Show when={state.showScrollTopButton()}>
|
||||
<button
|
||||
type="button"
|
||||
class="message-scroll-button"
|
||||
onClick={() => api.scrollToTop()}
|
||||
aria-label={t("messageSection.scroll.toFirstAriaLabel")}
|
||||
>
|
||||
<span class="message-scroll-icon" aria-hidden="true">
|
||||
↑
|
||||
</span>
|
||||
</button>
|
||||
</Show>
|
||||
<Show when={state.showScrollBottomButton()}>
|
||||
<button
|
||||
type="button"
|
||||
class="message-scroll-button"
|
||||
onClick={() => api.scrollToBottom()}
|
||||
aria-label={t("messageSection.scroll.toLatestAriaLabel")}
|
||||
>
|
||||
<span class="message-scroll-icon" aria-hidden="true">
|
||||
↓
|
||||
</span>
|
||||
</button>
|
||||
</Show>
|
||||
</div>
|
||||
)}
|
||||
renderBeforeItems={() => (
|
||||
<>
|
||||
<Show when={!props.loading && visibleMessageIds().length === 0}>
|
||||
|
||||
@@ -18,6 +18,8 @@ export const messagingMessages = {
|
||||
"messageSection.loading.messages": "Loading messages...",
|
||||
"messageSection.scroll.toFirstAriaLabel": "Scroll to first message",
|
||||
"messageSection.scroll.toLatestAriaLabel": "Scroll to latest message",
|
||||
"messageSection.scroll.enableHoldAriaLabel": "Enable hold for long assistant replies",
|
||||
"messageSection.scroll.disableHoldAriaLabel": "Disable hold for long assistant replies",
|
||||
"messageSection.quote.addAsQuote": "Add as quote",
|
||||
"messageSection.quote.addAsCode": "Add as code",
|
||||
"messageSection.quote.copy": "Copy",
|
||||
|
||||
@@ -18,6 +18,8 @@ export const messagingMessages = {
|
||||
"messageSection.loading.messages": "Cargando mensajes...",
|
||||
"messageSection.scroll.toFirstAriaLabel": "Desplazarse al primer mensaje",
|
||||
"messageSection.scroll.toLatestAriaLabel": "Desplazarse al último mensaje",
|
||||
"messageSection.scroll.enableHoldAriaLabel": "Activar pausa para respuestas largas del asistente",
|
||||
"messageSection.scroll.disableHoldAriaLabel": "Desactivar pausa para respuestas largas del asistente",
|
||||
"messageSection.quote.addAsQuote": "Añadir como cita",
|
||||
"messageSection.quote.addAsCode": "Añadir como código",
|
||||
"messageSection.quote.copy": "Copiar",
|
||||
|
||||
@@ -18,6 +18,8 @@ export const messagingMessages = {
|
||||
"messageSection.loading.messages": "Chargement des messages...",
|
||||
"messageSection.scroll.toFirstAriaLabel": "Aller au premier message",
|
||||
"messageSection.scroll.toLatestAriaLabel": "Aller au dernier message",
|
||||
"messageSection.scroll.enableHoldAriaLabel": "Activer le maintien pour les longues réponses de l'assistant",
|
||||
"messageSection.scroll.disableHoldAriaLabel": "Désactiver le maintien pour les longues réponses de l'assistant",
|
||||
"messageSection.quote.addAsQuote": "Ajouter en citation",
|
||||
"messageSection.quote.addAsCode": "Ajouter en code",
|
||||
"messageSection.quote.copy": "Copier",
|
||||
|
||||
@@ -18,6 +18,8 @@ export const messagingMessages = {
|
||||
"messageSection.loading.messages": "טוען הודעות...",
|
||||
"messageSection.scroll.toFirstAriaLabel": "גלול להודעה הראשונה",
|
||||
"messageSection.scroll.toLatestAriaLabel": "גלול להודעה האחרונה",
|
||||
"messageSection.scroll.enableHoldAriaLabel": "הפעל עצירה לתגובות עוזר ארוכות",
|
||||
"messageSection.scroll.disableHoldAriaLabel": "כבה עצירה לתגובות עוזר ארוכות",
|
||||
"messageSection.quote.addAsQuote": "הוסף כציטוט",
|
||||
"messageSection.quote.addAsCode": "הוסף כקוד",
|
||||
"messageSection.quote.copy": "העתק",
|
||||
|
||||
@@ -18,6 +18,8 @@ export const messagingMessages = {
|
||||
"messageSection.loading.messages": "メッセージを読み込み中...",
|
||||
"messageSection.scroll.toFirstAriaLabel": "最初のメッセージへスクロール",
|
||||
"messageSection.scroll.toLatestAriaLabel": "最新のメッセージへスクロール",
|
||||
"messageSection.scroll.enableHoldAriaLabel": "長いアシスタント返信の保持を有効にする",
|
||||
"messageSection.scroll.disableHoldAriaLabel": "長いアシスタント返信の保持を無効にする",
|
||||
"messageSection.quote.addAsQuote": "引用として追加",
|
||||
"messageSection.quote.addAsCode": "コードとして追加",
|
||||
"messageSection.quote.copy": "コピー",
|
||||
|
||||
@@ -18,6 +18,8 @@ export const messagingMessages = {
|
||||
"messageSection.loading.messages": "Загрузка сообщений…",
|
||||
"messageSection.scroll.toFirstAriaLabel": "Прокрутить к первому сообщению",
|
||||
"messageSection.scroll.toLatestAriaLabel": "Прокрутить к последнему сообщению",
|
||||
"messageSection.scroll.enableHoldAriaLabel": "Включить удержание для длинных ответов ассистента",
|
||||
"messageSection.scroll.disableHoldAriaLabel": "Выключить удержание для длинных ответов ассистента",
|
||||
"messageSection.quote.addAsQuote": "Добавить как цитату",
|
||||
"messageSection.quote.addAsCode": "Добавить как код",
|
||||
"messageSection.quote.copy": "Копировать",
|
||||
|
||||
@@ -18,6 +18,8 @@ export const messagingMessages = {
|
||||
"messageSection.loading.messages": "正在加载消息...",
|
||||
"messageSection.scroll.toFirstAriaLabel": "滚动到第一条消息",
|
||||
"messageSection.scroll.toLatestAriaLabel": "滚动到最新消息",
|
||||
"messageSection.scroll.enableHoldAriaLabel": "启用长助手回复保持",
|
||||
"messageSection.scroll.disableHoldAriaLabel": "禁用长助手回复保持",
|
||||
"messageSection.quote.addAsQuote": "作为引用添加",
|
||||
"messageSection.quote.addAsCode": "作为代码添加",
|
||||
"messageSection.quote.copy": "复制",
|
||||
|
||||
@@ -55,6 +55,7 @@ export interface UiSettings {
|
||||
showKeyboardShortcutHints: boolean
|
||||
thinkingBlocksExpansion: ExpansionPreference
|
||||
showTimelineTools: boolean
|
||||
holdLongAssistantReplies: boolean
|
||||
promptSubmitOnEnter: boolean
|
||||
showPromptVoiceInput: boolean
|
||||
locale?: string
|
||||
@@ -133,6 +134,7 @@ const defaultUiSettings: UiSettings = {
|
||||
showKeyboardShortcutHints: true,
|
||||
thinkingBlocksExpansion: "expanded",
|
||||
showTimelineTools: true,
|
||||
holdLongAssistantReplies: true,
|
||||
promptSubmitOnEnter: false,
|
||||
showPromptVoiceInput: true,
|
||||
diffViewMode: "split",
|
||||
@@ -166,6 +168,7 @@ function normalizeUiSettings(input?: Partial<UiSettings> | null): UiSettings {
|
||||
sanitized.showKeyboardShortcutHints ?? defaultUiSettings.showKeyboardShortcutHints,
|
||||
thinkingBlocksExpansion: sanitized.thinkingBlocksExpansion ?? defaultUiSettings.thinkingBlocksExpansion,
|
||||
showTimelineTools: sanitized.showTimelineTools ?? defaultUiSettings.showTimelineTools,
|
||||
holdLongAssistantReplies: sanitized.holdLongAssistantReplies ?? defaultUiSettings.holdLongAssistantReplies,
|
||||
promptSubmitOnEnter: sanitized.promptSubmitOnEnter ?? defaultUiSettings.promptSubmitOnEnter,
|
||||
showPromptVoiceInput: sanitized.showPromptVoiceInput ?? defaultUiSettings.showPromptVoiceInput,
|
||||
locale: sanitized.locale ?? defaultUiSettings.locale,
|
||||
|
||||
@@ -242,6 +242,10 @@
|
||||
color: var(--accent-primary);
|
||||
}
|
||||
|
||||
.message-scroll-button[data-active="false"] .message-scroll-icon--toggle {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.message-quote-popover {
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
|
||||
Reference in New Issue
Block a user