Stage 398: PR #2687 — feat: hide suggestions preference (closes #2679)

Closes #2679

Co-authored-by: Michaelyklam <Michaelyklam@users.noreply.github.com>
This commit is contained in:
Hermes AgentandMichaelyklam committed 2026-05-21 17:43:48 +00:00
1 parent c70ec3ba19
commit 7d3013245a
10 files changed
+119

No files matched your search

+4
View File
@@ -3,6 +3,10 @@
## [Unreleased]
### Added
- **PR #2687** by @Michaelyklam (closes #2679) — Add a Settings → Preferences toggle backed by `hide_empty_state_suggestions` to hide the three default new-chat suggestion buttons. The empty-state copy stays visible, but the suggestion grid can now be removed from fresh chats to avoid accidental mobile taps.
## [v0.51.104] — 2026-05-21 — Release CB (stage-397 — 9-PR batch — i18n zh-CN/zh-TW cron status + geist-contrast skin polish + tablet hardware Enter + stale Codex slash model state + SSE reconnect jitter + cron run inline expansion + inflight send race + new-chat model provider sync + virtualized sidebar scroll-clamp resync + transcript cache invalidation on same-count content)
+2
View File
@@ -4311,6 +4311,7 @@ _SETTINGS_DEFAULTS = {
"send_key": "enter", # 'enter' or 'ctrl+enter'
"show_token_usage": False, # show input/output token badge below assistant messages
"show_quota_chip": False, # show ambient provider quota chip in composer footer (default off; wide desktop only when enabled, see style.css @media)
"hide_empty_state_suggestions": False, # hide the default new-chat suggestion buttons
"show_tps": False, # show tokens-per-second chip in assistant message headers
"fade_text_effect": False, # animate newly streamed words with a lightweight fade-in effect
"show_cli_sessions": False, # merge CLI sessions from state.db into the sidebar
@@ -4455,6 +4456,7 @@ _SETTINGS_BOOL_KEYS = {
"onboarding_completed",
"show_token_usage",
"show_quota_chip",
"hide_empty_state_suggestions",
"show_tps",
"fade_text_effect",
"show_cli_sessions",
Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

+9
View File
@@ -1152,6 +1152,11 @@ document.querySelectorAll('.suggestion').forEach(btn=>{
btn.onclick=()=>{$('msg').value=btn.dataset.msg;send();};
});
function applyEmptyStateSuggestionPref(){
if(!$('emptyState')) return;
$('emptyState').classList.toggle('no-suggestions',window._hideEmptyStateSuggestions===true);
}
window.addEventListener('resize',()=>{
_syncWorkspacePanelInlineWidth();
syncWorkspacePanelState();
@@ -1431,6 +1436,8 @@ function applyBotName(){
window._sendKey=s.send_key||'enter';
window._showTokenUsage=!!s.show_token_usage;
window._showQuotaChip=s.show_quota_chip===true;
window._hideEmptyStateSuggestions=s.hide_empty_state_suggestions===true;
applyEmptyStateSuggestionPref();
window._showTps=!!s.show_tps;
window._fadeTextEffect=!!s.fade_text_effect;
window._showCliSessions=!!s.show_cli_sessions;
@@ -1520,6 +1527,8 @@ function applyBotName(){
window._sendKey='enter';
window._showTokenUsage=false;
window._showQuotaChip=false;
window._hideEmptyStateSuggestions=false;
applyEmptyStateSuggestionPref();
window._showTps=false;
window._fadeTextEffect=false;
window._showCliSessions=false;
+22
View File
@@ -556,6 +556,8 @@ const LOCALES = {
settings_label_language: 'Language',
settings_label_quota_chip: 'Show provider quota chip in composer',
settings_desc_quota_chip: 'Displays an ambient remaining-quota indicator (e.g. OpenRouter credit balance) in the composer footer. Default off. Only visible on wide displays (≥1400px) when enabled, to keep the composer uncluttered on laptop and standard desktop widths.',
settings_label_hide_suggestions: 'Hide new-chat suggestions',
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
settings_label_token_usage: 'Show token usage',
settings_label_sidebar_density: 'Sidebar density',
cmd_reasoning: 'Toggle thinking visibility (show/hide), set effort level, or check current status',
@@ -1785,6 +1787,8 @@ const LOCALES = {
settings_label_language: 'Lingua',
settings_label_quota_chip: 'Mostra il chip della quota del provider nel compositore',
settings_desc_quota_chip: "Mostra un indicatore di quota residua (es. saldo crediti OpenRouter) nel piè di pagina del compositore. Predefinito disattivato. Visibile solo su schermi larghi (≥1400px) quando attivato, per mantenere il compositore non affollato su laptop e desktop standard.",
settings_label_hide_suggestions: 'Hide new-chat suggestions',
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
settings_label_token_usage: 'Mostra uso token',
settings_label_sidebar_density: 'Densità sidebar',
cmd_reasoning: 'Mostra/nascondi ragionamento, imposta livello sforzo o controlla stato attuale',
@@ -3006,6 +3010,8 @@ const LOCALES = {
settings_label_language: '言語',
settings_label_quota_chip: 'コンポーザーにプロバイダーのクォータチップを表示',
settings_desc_quota_chip: 'コンポーザーのフッターに残りクォータインジケーター(例: OpenRouter のクレジット残高)を表示します。デフォルトはオフ。有効にした場合、ラップトップや標準デスクトップの幅でコンポーザーが混雑しないよう、ワイドディスプレイ(≥1400px)でのみ表示されます。',
settings_label_hide_suggestions: 'Hide new-chat suggestions',
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
settings_label_token_usage: 'トークン使用量を表示',
settings_label_sidebar_density: 'サイドバー密度',
cmd_reasoning: '思考表示の切り替え (表示/非表示)、努力レベル設定、現在状態の確認',
@@ -4033,6 +4039,8 @@ const LOCALES = {
settings_label_language: 'Язык',
settings_label_quota_chip: 'Показывать чип квоты провайдера в композиторе',
settings_desc_quota_chip: 'Отображает фоновый индикатор остатка квоты (например, баланс кредитов OpenRouter) в подвале композитора. По умолчанию отключено. Виден только на широких экранах (≥1400px) при включении, чтобы не загромождать композитор на ноутбуках и стандартных мониторах.',
settings_label_hide_suggestions: 'Hide new-chat suggestions',
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
settings_label_token_usage: 'Показывать использование токенов',
settings_label_sidebar_density: 'Плотность боковой панели',
cmd_reasoning: 'Toggle thinking visibility (show/hide), set effort level, or check current status',
@@ -5183,6 +5191,8 @@ const LOCALES = {
settings_label_language: 'Idioma',
settings_label_quota_chip: 'Mostrar el chip de cuota del proveedor en el compositor',
settings_desc_quota_chip: 'Muestra un indicador ambiental de cuota restante (por ejemplo, saldo de crédito de OpenRouter) en el pie del compositor. Predeterminado: desactivado. Solo visible en pantallas anchas (≥1400px) cuando se activa, para mantener el compositor despejado en portátiles y monitores estándar.',
settings_label_hide_suggestions: 'Hide new-chat suggestions',
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
settings_label_token_usage: 'Mostrar uso de tokens',
settings_label_sidebar_density: 'Densidad de la barra lateral',
cmd_reasoning: 'Toggle thinking visibility (show/hide), set effort level, or check current status',
@@ -6326,6 +6336,8 @@ const LOCALES = {
settings_label_language: 'Sprache',
settings_label_quota_chip: 'Anbieter-Kontingent-Chip im Editor anzeigen',
settings_desc_quota_chip: 'Zeigt einen Hintergrund-Indikator des verbleibenden Kontingents (z. B. OpenRouter-Guthaben) in der Editor-Fußzeile an. Standardmäßig deaktiviert. Bei Aktivierung nur auf breiten Bildschirmen (≥1400px) sichtbar, damit der Editor auf Laptops und Standard-Desktops übersichtlich bleibt.',
settings_label_hide_suggestions: 'Hide new-chat suggestions',
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
settings_label_token_usage: 'Token-Verbrauch anzeigen',
settings_label_sidebar_density: 'Seitenleistendichte',
cmd_reasoning: 'Toggle thinking visibility (show/hide), set effort level, or check current status',
@@ -7521,6 +7533,8 @@ const LOCALES = {
settings_label_language: '语言',
settings_label_quota_chip: '在编辑器中显示供应商配额标签',
settings_desc_quota_chip: '在编辑器底部显示剩余配额指示器(如 OpenRouter 信用余额)。默认关闭。启用时仅在宽屏(≥1400px)显示,以保持笔记本和标准桌面屏幕上编辑器的整洁。',
settings_label_hide_suggestions: 'Hide new-chat suggestions',
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
settings_label_token_usage: '显示 token 用量',
settings_label_sidebar_density: '侧边栏密度',
cmd_reasoning: '切换思维可见性(显示/隐藏)、设置工作强度或查看当前状态',
@@ -8693,6 +8707,8 @@ const LOCALES = {
settings_label_language: '\u8a9e\u8a00',
settings_label_quota_chip: '在編輯器中顯示供應商配額標籤',
settings_desc_quota_chip: '在編輯器底部顯示剩餘配額指示器(如 OpenRouter 點數餘額)。預設關閉。啟用時僅在寬螢幕(≥1400px)顯示,以保持筆記型電腦和標準桌面螢幕上編輯器的整潔。',
settings_label_hide_suggestions: 'Hide new-chat suggestions',
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
settings_label_token_usage: '\u986f\u793a token \u7528\u91cf',
settings_label_sidebar_density: '側邊欄密度',
cmd_reasoning: '切換思考區塊可見性(顯示/隱藏)或設定努力等級',
@@ -10000,6 +10016,8 @@ const LOCALES = {
settings_label_language: 'Idioma',
settings_label_quota_chip: 'Mostrar o chip de cota do provedor no compositor',
settings_desc_quota_chip: 'Exibe um indicador ambiente de cota restante (por exemplo, saldo de crédito do OpenRouter) no rodapé do compositor. Desativado por padrão. Visível apenas em telas largas (≥1400px) quando ativado, para manter o compositor livre em laptops e monitores padrão.',
settings_label_hide_suggestions: 'Hide new-chat suggestions',
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
settings_label_token_usage: 'Mostrar uso de tokens',
settings_label_sidebar_density: 'Densidade da sidebar',
cmd_reasoning: 'Alternar visibilidade do pensamento (mostrar/ocultar)',
@@ -11124,6 +11142,8 @@ const LOCALES = {
settings_label_language: '언어',
settings_label_quota_chip: '작성기에 공급자 할당량 칩 표시',
settings_desc_quota_chip: '작성기 푸터에 남은 할당량 표시기(예: OpenRouter 크레딧 잔액)를 표시합니다. 기본값은 끔. 활성화 시 노트북과 표준 데스크톱에서 작성기가 복잡해지지 않도록 와이드 디스플레이(≥1400px)에서만 표시됩니다.',
settings_label_hide_suggestions: 'Hide new-chat suggestions',
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
settings_label_token_usage: '토큰 사용량 표시',
settings_label_sidebar_density: '사이드바 밀도',
cmd_reasoning: 'Toggle thinking visibility (show/hide), set effort level, or check current status',
@@ -12263,6 +12283,8 @@ const LOCALES = {
settings_label_language: 'Langue',
settings_label_quota_chip: 'Afficher la pastille de quota du fournisseur dans le compositeur',
settings_desc_quota_chip: "Affiche un indicateur ambiant de quota restant (par ex. solde de crédit OpenRouter) dans le pied du compositeur. Désactivé par défaut. Visible uniquement sur les écrans larges (≥1400px) lorsqu'activé, pour garder le compositeur dégagé sur les ordinateurs portables et les bureaux standard.",
settings_label_hide_suggestions: 'Hide new-chat suggestions',
settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.',
settings_label_token_usage: 'Afficher l\'utilisation du jeton',
settings_label_sidebar_density: 'Densité de la barre latérale',
cmd_reasoning: 'Basculez la visibilité de la réflexion (afficher/masquer), définir le niveau d\'effort ou vérifier l\'état actuel',
+7
View File
@@ -995,6 +995,13 @@
<select id="settingsModel" style="width:100%;padding:8px;background:var(--code-bg);color:var(--text);border:1px solid var(--border2);border-radius:6px"></select>
<div style="font-size:11px;color:var(--muted);margin-top:4px" data-i18n="settings_desc_model">Used for new conversations. Existing conversations keep their selected model.</div>
</div>
<div class="settings-field">
<label style="display:flex;align-items:center;gap:8px;cursor:pointer">
<input type="checkbox" id="settingsHideSuggestions" style="width:15px;height:15px;accent-color:var(--accent)">
<span data-i18n="settings_label_hide_suggestions">Hide new-chat suggestions</span>
</label>
<div style="font-size:11px;color:var(--muted);margin-top:4px" data-i18n="settings_desc_hide_suggestions">Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.</div>
</div>
<div class="settings-field">
<label for="settingsSendKey" data-i18n="settings_label_send_key">Send Key</label>
<select id="settingsSendKey" style="width:100%;padding:8px;background:var(--code-bg);color:var(--text);border:1px solid var(--border2);border-radius:6px">
+17
View File
@@ -5414,6 +5414,8 @@ function _preferencesPayloadFromUi(){
if(showUsageCb) payload.show_token_usage=showUsageCb.checked;
const showQuotaChipCb=$('settingsShowQuotaChip');
if(showQuotaChipCb) payload.show_quota_chip=showQuotaChipCb.checked;
const hideSuggestionsCb=$('settingsHideSuggestions');
if(hideSuggestionsCb) payload.hide_empty_state_suggestions=hideSuggestionsCb.checked;
const showTpsCb=$('settingsShowTps');
if(showTpsCb) payload.show_tps=showTpsCb.checked;
const fadeTextCb=$('settingsFadeTextEffect');
@@ -5496,6 +5498,10 @@ async function _autosavePreferencesSettings(payload){
if(typeof clearMessageRenderCache==='function') clearMessageRenderCache();
if(typeof renderMessages==='function') renderMessages();
}
if(payload&&payload.hide_empty_state_suggestions!==undefined){
window._hideEmptyStateSuggestions=!!(saved&&saved.hide_empty_state_suggestions);
if(typeof applyEmptyStateSuggestionPref==='function') applyEmptyStateSuggestionPref();
}
_settingsPreferencesAutosaveRetryPayload=null;
_setPreferencesAutosaveStatus('saved');
// Only clear the global dirty flag and hide the unsaved-changes bar when
@@ -5680,6 +5686,17 @@ async function loadSettingsPanel(){
_schedulePreferencesAutosave();
},{once:false});
}
const hideSuggestionsCb=$('settingsHideSuggestions');
if(hideSuggestionsCb){
hideSuggestionsCb.checked=settings.hide_empty_state_suggestions===true;
window._hideEmptyStateSuggestions=hideSuggestionsCb.checked;
if(typeof applyEmptyStateSuggestionPref==='function') applyEmptyStateSuggestionPref();
hideSuggestionsCb.addEventListener('change',()=>{
window._hideEmptyStateSuggestions=hideSuggestionsCb.checked;
if(typeof applyEmptyStateSuggestionPref==='function') applyEmptyStateSuggestionPref();
_schedulePreferencesAutosave();
},{once:false});
}
const showTpsCb=$('settingsShowTps');
if(showTpsCb){showTpsCb.checked=!!settings.show_tps;showTpsCb.addEventListener('change',_schedulePreferencesAutosave,{once:false});}
const fadeTextCb=$('settingsFadeTextEffect');
+1
View File
@@ -1283,6 +1283,7 @@
.dot:nth-child(2){animation-delay:.22s;}.dot:nth-child(3){animation-delay:.44s;}
@keyframes pulse{0%,80%,100%{opacity:.2;transform:scale(.8)}40%{opacity:.8;transform:scale(1)}}
.empty-state{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:40px;color:var(--muted);}
.empty-state.no-suggestions .suggestion-grid{display:none}
.empty-logo{width:64px;height:64px;border-radius:20px;background:linear-gradient(145deg,var(--accent-bg),var(--accent-bg));border:1px solid var(--accent-bg);display:flex;align-items:center;justify-content:center;font-size:28px;font-weight:700;color:var(--accent-text);margin-bottom:4px;box-shadow:0 4px 20px var(--accent-bg);}
.empty-state h2{font-size:20px;color:var(--text);font-weight:700;letter-spacing:-.02em;}
.empty-state p{font-size:14px;text-align:center;max-width:320px;}
+57
View File
@@ -0,0 +1,57 @@
"""Regression coverage for #2679: optional hiding of empty-chat suggestions."""
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent
INDEX = REPO_ROOT / "static" / "index.html"
STYLE = REPO_ROOT / "static" / "style.css"
PANELS = REPO_ROOT / "static" / "panels.js"
BOOT = REPO_ROOT / "static" / "boot.js"
I18N = REPO_ROOT / "static" / "i18n.js"
CONFIG = REPO_ROOT / "api" / "config.py"
CHANGELOG = REPO_ROOT / "CHANGELOG.md"
def test_hide_suggestions_setting_is_default_off_and_allowed():
src = CONFIG.read_text(encoding="utf-8")
assert '"hide_empty_state_suggestions": False' in src
assert '"hide_empty_state_suggestions",' in src
def test_settings_preferences_expose_hide_suggestions_toggle():
html = INDEX.read_text(encoding="utf-8")
assert 'id="settingsHideSuggestions"' in html
assert 'data-i18n="settings_label_hide_suggestions"' in html
assert 'data-i18n="settings_desc_hide_suggestions"' in html
def test_empty_state_has_hideable_suggestions_hook_and_css():
html = INDEX.read_text(encoding="utf-8")
css = STYLE.read_text(encoding="utf-8")
assert 'class="suggestion-grid"' in html
assert '.empty-state.no-suggestions .suggestion-grid{display:none}' in css
def test_boot_applies_saved_hide_suggestions_preference():
js = BOOT.read_text(encoding="utf-8")
assert "function applyEmptyStateSuggestionPref()" in js
assert "window._hideEmptyStateSuggestions=s.hide_empty_state_suggestions===true" in js
assert "window._hideEmptyStateSuggestions=false" in js
assert "$('emptyState').classList.toggle('no-suggestions',window._hideEmptyStateSuggestions===true)" in js
def test_panels_round_trip_and_hot_apply_hide_suggestions():
js = PANELS.read_text(encoding="utf-8")
assert "const hideSuggestionsCb=$('settingsHideSuggestions');" in js
assert "payload.hide_empty_state_suggestions=hideSuggestionsCb.checked;" in js
assert "hideSuggestionsCb.checked=settings.hide_empty_state_suggestions===true;" in js
assert "window._hideEmptyStateSuggestions=hideSuggestionsCb.checked;" in js
assert "if(typeof applyEmptyStateSuggestionPref==='function') applyEmptyStateSuggestionPref();" in js
def test_hide_suggestions_i18n_all_locales_and_changelog():
js = I18N.read_text(encoding="utf-8")
assert js.count("settings_label_hide_suggestions:") == 11
assert js.count("settings_desc_hide_suggestions:") == 11
changelog = CHANGELOG.read_text(encoding="utf-8")
assert "#2679" in changelog
assert "hide_empty_state_suggestions" in changelog