feat(P3-6): configurable composer toolbar buttons
CI / Build & Quality Checks (push) Successful in 10m24s
Trigger Desktop Build / trigger (push) Successful in 7s

Each button (Format, Emoji, Sticker, GIF, Location, Poll, Voice,
Schedule) can be individually hidden in Settings → Editor.
All default to on, stored in composerToolbarButtons object.
getSettings deep-merges the nested object so new buttons default
to true for existing users with saved settings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 13:20:29 -04:00
parent b7daabe2e0
commit 891f2daf99
3 changed files with 275 additions and 123 deletions
@@ -37,6 +37,7 @@ import { SequenceCard } from '../../../components/sequence-card';
import { useSetting } from '../../../state/hooks/settings';
import {
ChatBackground,
ComposerToolbarSettings,
DateFormat,
MessageLayout,
MessageSpacing,
@@ -855,6 +856,14 @@ function Editor() {
const [enterForNewline, setEnterForNewline] = useSetting(settingsAtom, 'enterForNewline');
const [isMarkdown, setIsMarkdown] = useSetting(settingsAtom, 'isMarkdown');
const [editorToolbar, setEditorToolbar] = useSetting(settingsAtom, 'editorToolbar');
const [composerToolbarButtons, setComposerToolbarButtons] = useSetting(
settingsAtom,
'composerToolbarButtons',
);
const toggleToolbarButton = (key: keyof ComposerToolbarSettings) => {
setComposerToolbarButtons({ ...composerToolbarButtons, [key]: !composerToolbarButtons[key] });
};
return (
<Box direction="Column" gap="100">
@@ -881,6 +890,90 @@ function Editor() {
after={<Switch variant="Primary" value={editorToolbar} onChange={setEditorToolbar} />}
/>
</SequenceCard>
<Text size="L400" style={{ marginTop: '8px' }}>Composer Toolbar Buttons</Text>
<SequenceCard className={SequenceCardStyle} variant="SurfaceVariant" direction="Column">
<SettingTile
title="Format Toggle"
description="Button to show/hide the text formatting toolbar."
after={
<Switch
variant="Primary"
value={composerToolbarButtons?.showFormat ?? true}
onChange={() => toggleToolbarButton('showFormat')}
/>
}
/>
<SettingTile
title="Emoji"
after={
<Switch
variant="Primary"
value={composerToolbarButtons?.showEmoji ?? true}
onChange={() => toggleToolbarButton('showEmoji')}
/>
}
/>
<SettingTile
title="Sticker"
after={
<Switch
variant="Primary"
value={composerToolbarButtons?.showSticker ?? true}
onChange={() => toggleToolbarButton('showSticker')}
/>
}
/>
<SettingTile
title="GIF"
after={
<Switch
variant="Primary"
value={composerToolbarButtons?.showGif ?? true}
onChange={() => toggleToolbarButton('showGif')}
/>
}
/>
<SettingTile
title="Location"
after={
<Switch
variant="Primary"
value={composerToolbarButtons?.showLocation ?? true}
onChange={() => toggleToolbarButton('showLocation')}
/>
}
/>
<SettingTile
title="Poll"
after={
<Switch
variant="Primary"
value={composerToolbarButtons?.showPoll ?? true}
onChange={() => toggleToolbarButton('showPoll')}
/>
}
/>
<SettingTile
title="Voice Message"
after={
<Switch
variant="Primary"
value={composerToolbarButtons?.showVoice ?? true}
onChange={() => toggleToolbarButton('showVoice')}
/>
}
/>
<SettingTile
title="Schedule Message"
after={
<Switch
variant="Primary"
value={composerToolbarButtons?.showSchedule ?? true}
onChange={() => toggleToolbarButton('showSchedule')}
/>
}
/>
</SequenceCard>
</Box>
);
}