feat(ui): make message timeline hideable (#428)

## Summary
- Add a behavior setting to show or hide the message timeline sidebar.
- Remove the timeline layout gutter when the sidebar is disabled.
- Add setting labels for all supported locales.

## Why
user wants a more minimal workspace and a little more horizontal room
without losing the default timeline experience for everyone else.

## Validation
- npm run typecheck --workspace @codenomad/ui
- git diff --check
- npm run build:tauri, then launched the raw release exe

Fixes #418
This commit is contained in:
Pascal André 2026-05-10 18:44:43 +02:00 committed by GitHub
parent 4090989d12
commit 342531090e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 53 additions and 2 deletions

View file

@ -80,6 +80,7 @@ const App: Component = () => {
recordWorkspaceLaunch,
toggleShowThinkingBlocks,
toggleKeyboardShortcutHints,
toggleShowMessageTimeline,
toggleShowTimelineTools,
toggleAutoCleanupBlankSessions,
toggleUsageMetrics,
@ -411,6 +412,7 @@ const App: Component = () => {
toggleAutoCleanupBlankSessions,
toggleShowThinkingBlocks,
toggleKeyboardShortcutHints,
toggleShowMessageTimeline,
toggleShowTimelineTools,
toggleUsageMetrics,
togglePromptSubmitOnEnter,

View file

@ -50,6 +50,7 @@ export default function MessageSection(props: MessageSectionProps) {
const { preferences, updatePreferences } = useConfig()
const { t } = useI18n()
const showUsagePreference = () => preferences().showUsageMetrics ?? true
const showMessageTimelinePreference = () => preferences().showMessageTimeline ?? true
const showTimelineToolsPreference = () => preferences().showTimelineTools ?? true
const holdLongAssistantRepliesEnabled = () => preferences().holdLongAssistantReplies ?? true
const store = createMemo<InstanceMessageStore>(() => messageStoreBus.getOrCreate(props.instanceId))
@ -1226,6 +1227,8 @@ export default function MessageSection(props: MessageSectionProps) {
clearQuoteSelection()
})
const showTimeline = createMemo(() => showMessageTimelinePreference() && hasTimelineSegments())
return (
<div
class="message-stream-container"
@ -1234,7 +1237,7 @@ export default function MessageSection(props: MessageSectionProps) {
data-stream-active={isActive() ? "true" : "false"}
>
<div
class={`message-layout${hasTimelineSegments() ? " message-layout--with-timeline" : ""}`}
class={`message-layout${showTimeline() ? " message-layout--with-timeline" : ""}`}
data-scroll-buttons={scrollButtonsCount()}
>
<VirtualFollowList
@ -1616,7 +1619,7 @@ export default function MessageSection(props: MessageSectionProps) {
</div>
</Show>
<Show when={hasTimelineSegments()}>
<Show when={showTimeline()}>
<div class="message-timeline-sidebar">
<MessageTimeline
segments={timelineSegments()}

View file

@ -20,6 +20,7 @@ export const AppearanceSettingsSection: Component = () => {
updatePreferences,
toggleShowThinkingBlocks,
toggleKeyboardShortcutHints,
toggleShowMessageTimeline,
toggleShowTimelineTools,
toggleUsageMetrics,
toggleAutoCleanupBlankSessions,
@ -38,6 +39,7 @@ export const AppearanceSettingsSection: Component = () => {
updatePreferences,
toggleShowThinkingBlocks,
toggleKeyboardShortcutHints,
toggleShowMessageTimeline,
toggleShowTimelineTools,
toggleUsageMetrics,
toggleAutoCleanupBlankSessions,

View file

@ -31,6 +31,7 @@ export interface UseCommandsOptions {
preferences: Accessor<Preferences>
toggleShowThinkingBlocks: () => void
toggleKeyboardShortcutHints: () => void
toggleShowMessageTimeline: () => void
toggleShowTimelineTools: () => void
toggleUsageMetrics: () => void
toggleAutoCleanupBlankSessions: () => void
@ -420,6 +421,7 @@ export function useCommands(options: UseCommandsOptions) {
preferences: options.preferences,
toggleShowThinkingBlocks: options.toggleShowThinkingBlocks,
toggleKeyboardShortcutHints: options.toggleKeyboardShortcutHints,
toggleShowMessageTimeline: options.toggleShowMessageTimeline,
toggleShowTimelineTools: options.toggleShowTimelineTools,
toggleUsageMetrics: options.toggleUsageMetrics,
toggleAutoCleanupBlankSessions: options.toggleAutoCleanupBlankSessions,

View file

@ -135,6 +135,8 @@ export const settingsMessages = {
"settings.behavior.thinking.subtitle": "Show or hide AI thinking sections in messages.",
"settings.behavior.thinkingDefault.title": "Thinking default",
"settings.behavior.thinkingDefault.subtitle": "Choose whether thinking sections start expanded or collapsed.",
"settings.behavior.messageTimeline.title": "Message timeline",
"settings.behavior.messageTimeline.subtitle": "Show or hide the message timeline sidebar.",
"settings.behavior.timelineTools.title": "Timeline tool calls",
"settings.behavior.timelineTools.subtitle": "Show or hide tool call entries in the message timeline.",
"settings.behavior.diffView.title": "Diff view",

View file

@ -134,6 +134,8 @@ export const settingsMessages = {
"settings.behavior.thinking.subtitle": "Muestra u oculta las secciones de pensamiento de la IA en los mensajes.",
"settings.behavior.thinkingDefault.title": "Pensamiento por defecto",
"settings.behavior.thinkingDefault.subtitle": "Elige si las secciones de pensamiento comienzan expandidas o contraidas.",
"settings.behavior.messageTimeline.title": "Linea de tiempo de mensajes",
"settings.behavior.messageTimeline.subtitle": "Muestra u oculta la barra lateral de la linea de tiempo de mensajes.",
"settings.behavior.timelineTools.title": "Llamadas de herramientas en la linea de tiempo",
"settings.behavior.timelineTools.subtitle": "Muestra u oculta entradas de llamadas de herramientas en la linea de tiempo de mensajes.",
"settings.behavior.diffView.title": "Vista de diferencias",

View file

@ -134,6 +134,8 @@ export const settingsMessages = {
"settings.behavior.thinking.subtitle": "Afficher ou masquer les sections de reflexion de l'IA dans les messages.",
"settings.behavior.thinkingDefault.title": "Etat initial de la reflexion",
"settings.behavior.thinkingDefault.subtitle": "Choisir si les sections de reflexion commencent developpees ou reduites.",
"settings.behavior.messageTimeline.title": "Chronologie des messages",
"settings.behavior.messageTimeline.subtitle": "Afficher ou masquer la barre laterale de chronologie des messages.",
"settings.behavior.timelineTools.title": "Appels d'outils dans la chronologie",
"settings.behavior.timelineTools.subtitle": "Afficher ou masquer les entrees d'appels d'outils dans la chronologie des messages.",
"settings.behavior.diffView.title": "Vue du diff",

View file

@ -133,6 +133,8 @@ export const settingsMessages = {
"settings.behavior.thinking.subtitle": "הצג או הסתר קטעי חשיבה של ה-AI בהודעות.",
"settings.behavior.thinkingDefault.title": "ברירת מחדל לחשיבה",
"settings.behavior.thinkingDefault.subtitle": "בחר האם קטעי חשיבה מתחילים פרוסים או מכווצים.",
"settings.behavior.messageTimeline.title": "ציר זמן הודעות",
"settings.behavior.messageTimeline.subtitle": "הצג או הסתר את סרגל הצד של ציר זמן ההודעות.",
"settings.behavior.timelineTools.title": "קריאות כלי בציר הזמן",
"settings.behavior.timelineTools.subtitle": "הצג או הסתר קריאות כלי בציר הודעות.",
"settings.behavior.diffView.title": "תצוגת diff",

View file

@ -134,6 +134,8 @@ export const settingsMessages = {
"settings.behavior.thinking.subtitle": "メッセージ内のAIの思考セクションを表示/非表示にします。",
"settings.behavior.thinkingDefault.title": "思考の既定",
"settings.behavior.thinkingDefault.subtitle": "思考セクションを最初に展開/折りたたみのどちらで表示するかを選びます。",
"settings.behavior.messageTimeline.title": "メッセージタイムライン",
"settings.behavior.messageTimeline.subtitle": "メッセージタイムラインのサイドバーを表示/非表示にします。",
"settings.behavior.timelineTools.title": "タイムラインのツール呼び出し",
"settings.behavior.timelineTools.subtitle": "メッセージタイムラインでツール呼び出しを表示/非表示にします。",
"settings.behavior.diffView.title": "差分表示",

View file

@ -134,6 +134,8 @@ export const settingsMessages = {
"settings.behavior.thinking.subtitle": "Показывать или скрывать разделы размышлений ИИ в сообщениях.",
"settings.behavior.thinkingDefault.title": "Размышления по умолчанию",
"settings.behavior.thinkingDefault.subtitle": "Выберите, начинать ли разделы размышлений развернутыми или свернутыми.",
"settings.behavior.messageTimeline.title": "Таймлайн сообщений",
"settings.behavior.messageTimeline.subtitle": "Показывать или скрывать боковую панель таймлайна сообщений.",
"settings.behavior.timelineTools.title": "Вызовы инструментов в таймлайне",
"settings.behavior.timelineTools.subtitle": "Показывать или скрывать записи вызовов инструментов в таймлайне сообщений.",
"settings.behavior.diffView.title": "Вид диффа",

View file

@ -134,6 +134,8 @@ export const settingsMessages = {
"settings.behavior.thinking.subtitle": "在消息中显示或隐藏AI的思考区块。",
"settings.behavior.thinkingDefault.title": "思考默认状态",
"settings.behavior.thinkingDefault.subtitle": "选择思考区块默认是展开还是折叠。",
"settings.behavior.messageTimeline.title": "消息时间线",
"settings.behavior.messageTimeline.subtitle": "显示或隐藏消息时间线侧边栏。",
"settings.behavior.timelineTools.title": "时间线工具调用",
"settings.behavior.timelineTools.subtitle": "在消息时间线中显示或隐藏工具调用条目。",
"settings.behavior.diffView.title": "差异视图",

View file

@ -38,6 +38,7 @@ export type BehaviorRegistryActions = {
updatePreferences?: (updates: Partial<Preferences>) => void
toggleShowThinkingBlocks: () => void
toggleKeyboardShortcutHints: () => void
toggleShowMessageTimeline: () => void
toggleShowTimelineTools: () => void
toggleUsageMetrics: () => void
toggleAutoCleanupBlankSessions: () => void
@ -122,6 +123,24 @@ export function getBehaviorSettings(actions: BehaviorRegistryActions): BehaviorS
{ value: "collapsed", labelKey: "commands.common.collapsed" },
],
},
{
kind: "toggle",
id: "behavior.messageTimeline",
titleKey: "settings.behavior.messageTimeline.title",
subtitleKey: "settings.behavior.messageTimeline.subtitle",
get: (p) => Boolean(p.showMessageTimeline ?? true),
set: (next) => {
if (updatePreferences) {
updatePreferences({ showMessageTimeline: next })
return
}
setBooleanByToggle(
() => Boolean(prefs().showMessageTimeline ?? true),
actions.toggleShowMessageTimeline,
next,
)
},
},
{
kind: "toggle",
id: "behavior.timelineToolCalls",

View file

@ -54,6 +54,7 @@ export interface UiSettings {
showThinkingBlocks: boolean
showKeyboardShortcutHints: boolean
thinkingBlocksExpansion: ExpansionPreference
showMessageTimeline: boolean
showTimelineTools: boolean
holdLongAssistantReplies: boolean
promptSubmitOnEnter: boolean
@ -134,6 +135,7 @@ const defaultUiSettings: UiSettings = {
showThinkingBlocks: false,
showKeyboardShortcutHints: true,
thinkingBlocksExpansion: "expanded",
showMessageTimeline: true,
showTimelineTools: true,
holdLongAssistantReplies: true,
promptSubmitOnEnter: false,
@ -169,6 +171,7 @@ function normalizeUiSettings(input?: Partial<UiSettings> | null): UiSettings {
showKeyboardShortcutHints:
sanitized.showKeyboardShortcutHints ?? defaultUiSettings.showKeyboardShortcutHints,
thinkingBlocksExpansion: sanitized.thinkingBlocksExpansion ?? defaultUiSettings.thinkingBlocksExpansion,
showMessageTimeline: sanitized.showMessageTimeline ?? defaultUiSettings.showMessageTimeline,
showTimelineTools: sanitized.showTimelineTools ?? defaultUiSettings.showTimelineTools,
holdLongAssistantReplies: sanitized.holdLongAssistantReplies ?? defaultUiSettings.holdLongAssistantReplies,
promptSubmitOnEnter: sanitized.promptSubmitOnEnter ?? defaultUiSettings.promptSubmitOnEnter,
@ -661,6 +664,10 @@ function toggleShowTimelineTools(): void {
updateUiSettings({ showTimelineTools: !preferences().showTimelineTools })
}
function toggleShowMessageTimeline(): void {
updateUiSettings({ showMessageTimeline: !(preferences().showMessageTimeline ?? true) })
}
function toggleUsageMetrics(): void {
updateUiSettings({ showUsageMetrics: !preferences().showUsageMetrics })
}
@ -743,6 +750,7 @@ interface ConfigContextValue {
// ui settings helpers
toggleShowThinkingBlocks: typeof toggleShowThinkingBlocks
toggleKeyboardShortcutHints: typeof toggleKeyboardShortcutHints
toggleShowMessageTimeline: typeof toggleShowMessageTimeline
toggleShowTimelineTools: typeof toggleShowTimelineTools
toggleUsageMetrics: typeof toggleUsageMetrics
toggleAutoCleanupBlankSessions: typeof toggleAutoCleanupBlankSessions
@ -794,6 +802,7 @@ const configContextValue: ConfigContextValue = {
setModelThinkingSelection,
toggleShowThinkingBlocks,
toggleKeyboardShortcutHints,
toggleShowMessageTimeline,
toggleShowTimelineTools,
toggleUsageMetrics,
toggleAutoCleanupBlankSessions,