fix: tab folder visibility controlled by Tall Tabs setting + cache busting

- Renamed "Two-Row Tabs" to "Tall Tabs (Name + Folder)" for clarity
- Tab folder path now only rendered in JS when setting is ON (not just CSS hidden)
- CSS specificity fix: mobile.css now matches .tabs-two-rows specificity (0,2,0)
- Server settings sync: display keys seed from server on fresh localStorage
- Bumped cache buster versions to 0.1534 to force browser reload

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
arkon
2026-02-18 11:15:15 +01:00
co-authored by Claude Opus 4.6
parent 6fd6ff770f
commit d5a3806aa3
7 changed files with 437 additions and 24 deletions
+28 -9
View File
@@ -3721,9 +3721,10 @@ class ClaudemanApp {
const minimizedCount = minimizedAgents?.size || 0;
const subagentBadge = minimizedCount > 0 ? this.renderSubagentTabBadge(id, minimizedAgents) : '';
// Show folder name if session has a custom name (to still show the directory context)
// Show folder name if session has a custom name AND tall tabs setting is enabled
const folderName = session.workingDir ? session.workingDir.split('/').pop() || '' : '';
const showFolder = session.name && folderName && folderName !== name;
const tallTabsEnabled = this._tallTabsEnabled ?? false;
const showFolder = tallTabsEnabled && session.name && folderName && folderName !== name;
parts.push(`<div class="session-tab ${isActive ? 'active' : ''}${alertClass}" data-id="${id}" data-color="${color}" onclick="app.selectSession('${this.escapeHtml(id)}')" oncontextmenu="event.preventDefault(); app.startInlineRename('${this.escapeHtml(id)}')" tabindex="0" role="tab" aria-selected="${isActive ? 'true' : 'false'}" aria-label="${this.escapeHtml(name)} session" ${session.workingDir ? `title="${this.escapeHtml(session.workingDir)}"` : ''}>
<span class="tab-status ${status}" aria-hidden="true"></span>
@@ -9821,10 +9822,21 @@ class ClaudemanApp {
applyTabWrapSettings() {
const settings = this.loadAppSettingsFromStorage();
const defaults = this.getDefaultSettings();
const twoRows = settings.tabTwoRows ?? defaults.tabTwoRows ?? false;
const deviceType = MobileDetection.getDeviceType();
// Two-row tabs disabled on mobile/tablet — not enough screen space
const twoRows = deviceType === 'desktop'
? (settings.tabTwoRows ?? defaults.tabTwoRows ?? false)
: false;
const prevTallTabs = this._tallTabsEnabled;
this._tallTabsEnabled = twoRows;
const tabsEl = document.getElementById('sessionTabs');
if (tabsEl) {
tabsEl.classList.toggle('tabs-two-rows', twoRows);
tabsEl.classList.toggle('tabs-show-folder', twoRows);
}
// Re-render tabs if folder visibility changed (folder spans are generated in JS)
if (prevTallTabs !== undefined && prevTallTabs !== twoRows) {
this._fullRenderSessionTabs();
}
}
@@ -9970,15 +9982,22 @@ class ClaudemanApp {
'subagentTrackingEnabled', 'subagentActiveTabOnly',
'imageWatcherEnabled', 'ralphTrackerEnabled', 'tabTwoRows',
]);
const filteredAppSettings = {};
// Merge settings: non-display keys always sync from server,
// display keys only seed from server when localStorage has no value
// (prevents cross-device overwrite while fixing settings re-enabling on fresh loads)
const localSettings = this.loadAppSettingsFromStorage();
const merged = { ...localSettings };
for (const [key, value] of Object.entries(appSettings)) {
if (!displayKeys.has(key)) {
filteredAppSettings[key] = value;
if (displayKeys.has(key)) {
// Display keys: only use server value as initial seed
if (!(key in localSettings)) {
merged[key] = value;
}
} else {
// Non-display keys: server always wins
merged[key] = value;
}
}
// Merge non-display settings with localStorage (server takes precedence)
const localSettings = this.loadAppSettingsFromStorage();
const merged = { ...localSettings, ...filteredAppSettings };
this.saveAppSettingsToStorage(merged);
// Apply notification prefs from server if present (only if localStorage has none)
+5 -5
View File
@@ -10,8 +10,8 @@
<!-- DNS preconnect for CDN — saves ~100ms on first load -->
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
<link rel="dns-prefetch" href="https://cdn.jsdelivr.net">
<link rel="stylesheet" href="styles.css?v=0.1533">
<link rel="stylesheet" href="mobile.css?v=0.1533">
<link rel="stylesheet" href="styles.css?v=0.1534">
<link rel="stylesheet" href="mobile.css?v=0.1534">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css">
<!-- Defer CDN scripts — they no longer block initial HTML parsing/paint.
'defer' preserves execution order (xterm loads before fit addon). -->
@@ -792,8 +792,8 @@
<!-- Tab Bar Section -->
<div class="settings-section-header">Tab Bar</div>
<div class="settings-item" title="Allow tabs to wrap into two rows when there are many sessions">
<span class="settings-item-label">Two-Row Tabs</span>
<div class="settings-item" title="Show folder path below tab name and allow tab bar to wrap into multiple rows">
<span class="settings-item-label">Tall Tabs (Name + Folder)</span>
<label class="switch switch-sm">
<input type="checkbox" id="appSettingsTabTwoRows">
<span class="slider"></span>
@@ -1474,6 +1474,6 @@
<!-- Lines drawn dynamically -->
</svg>
<script defer src="app.js?v=0.1533"></script>
<script defer src="app.js?v=0.1534"></script>
</body>
</html>
+10 -4
View File
@@ -77,10 +77,13 @@ html.mobile-init .file-browser-panel {
gap: 0.35rem;
}
/* Compact session tabs */
.session-tabs {
/* Compact session tabs — .tabs-two-rows override needed to match
specificity of .session-tabs.tabs-two-rows in styles.css (0,2,0) */
.session-tabs,
.session-tabs.tabs-two-rows {
flex-wrap: nowrap;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
max-height: 52px;
@@ -344,11 +347,14 @@ html.mobile-init .file-browser-panel {
position: relative;
}
/* Ultra-compact session tabs */
.session-tabs {
/* Ultra-compact session tabs — .tabs-two-rows override needed to match
specificity of .session-tabs.tabs-two-rows in styles.css (0,2,0) */
.session-tabs,
.session-tabs.tabs-two-rows {
flex: 1;
flex-wrap: nowrap;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
max-height: 36px;
+4 -4
View File
@@ -309,6 +309,7 @@ body {
text-overflow: ellipsis;
}
/* Tab folder path — hidden by default, shown via .tabs-show-folder on container */
.session-tab .tab-folder {
font-size: 0.6rem;
color: var(--text-muted);
@@ -316,12 +317,11 @@ body {
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.2;
display: none;
}
@media (max-width: 768px) {
.session-tab .tab-folder {
display: none;
}
.tabs-show-folder .session-tab .tab-folder {
display: block;
}
.session-tab .tab-close {