Improve tab styling and accessibility in linker UI

- Redesign tabs with new visual styling (active/hover states, separators)
- Add ARIA attributes for tab accessibility (aria-selected, aria-disabled, aria-current)
- Update header styling in linker-shell.css
- Refactor tab switching logic to use centralized state management
This commit is contained in:
Dariusz L
2026-05-28 06:05:21 +02:00
parent 1048b0ace4
commit 5dec88fd15
3 changed files with 120 additions and 40 deletions
+78 -25
View File
@@ -2012,55 +2012,96 @@
/* Tabs */
.ml-tabs {
display: flex;
align-items: center;
gap: 3px;
align-self: stretch;
align-items: flex-end;
gap: 0;
min-width: 0;
height: 100%;
padding: 0;
margin: 0;
background: transparent;
position: relative;
z-index: 2;
--ml-tab-active-bg: var(--ml-bg, #121212);
--ml-tab-hover-bg: rgba(255,255,255,0.045);
--ml-tab-separator: rgba(255,255,255,0.125);
}
.ml-tab {
display: inline-flex;
align-items: center;
justify-content: center;
position: relative;
min-height: 30px;
padding: 0 14px;
background: rgba(255,255,255,0.018);
border: 1px solid rgba(255,255,255,0.065);
border-radius: 6px;
color: var(--ml-text-muted, #888);
align-self: flex-end;
height: 36px;
min-height: 36px;
padding: 0 21px;
margin-bottom: 0;
background: transparent !important;
border: 0;
border-radius: 0;
color: rgba(255,255,255,0.68);
font-size: 12px;
font-weight: 650;
font-weight: 600;
cursor: pointer;
white-space: nowrap;
box-shadow: none;
transform: none;
opacity: 0.82;
transition: opacity 0.16s ease, color 0.16s ease, background 0.16s ease, border-color 0.16s ease;
opacity: 1;
appearance: none;
-webkit-appearance: none;
transition: color 0.16s ease, background 0.16s ease;
}
.ml-tab:hover {
color: var(--ml-text, #eef2f7);
background: rgba(255,255,255,0.028);
border-color: rgba(255,255,255,0.10);
opacity: 1;
background: var(--ml-tab-hover-bg) !important;
border-radius: 9px 9px 0 0;
}
.ml-tab:not(.ml-tab-active) + .ml-tab:not(.ml-tab-active)::before {
content: "";
position: absolute;
left: 0;
top: 11px;
bottom: 11px;
width: 1px;
background: var(--ml-tab-separator);
pointer-events: none;
}
.ml-tab.ml-tab-active {
height: 36px;
min-height: 36px;
padding: 0 24px;
margin-bottom: 0;
color: var(--ml-text, #eef2f7);
background: rgba(255,255,255,0.045);
border-color: rgba(255,255,255,0.14);
box-shadow: none;
background: var(--ml-tab-active-bg) !important;
border-radius: 10px 10px 0 0;
cursor: default;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.07) !important;
transform: none;
opacity: 1;
z-index: 3;
z-index: 4;
}
.ml-tab.ml-tab-active:hover {
color: var(--ml-text, #eef2f7);
background: var(--ml-tab-active-bg) !important;
}
.ml-tab.ml-tab-active::before,
.ml-tab.ml-tab-active::after {
content: "";
position: absolute;
left: 8px;
right: 8px;
bottom: 3px;
height: 1px;
background: rgba(255,255,255,0.58);
bottom: 0;
width: 10px;
height: 10px;
background: transparent;
pointer-events: none;
}
.ml-tab.ml-tab-active::before {
left: -10px;
border-bottom-right-radius: 10px;
box-shadow: 5px 5px 0 5px var(--ml-tab-active-bg);
}
.ml-tab.ml-tab-active::after {
right: -10px;
border-bottom-left-radius: 10px;
box-shadow: -5px 5px 0 5px var(--ml-tab-active-bg);
}
#model-linker-modal .ml-tab,
#model-linker-modal .ml-footer-btn,
@@ -2070,9 +2111,21 @@
outline: none;
}
#model-linker-modal .ml-tab {
border-width: 1px !important;
border-width: 0 !important;
margin: 0 !important;
}
#model-linker-modal .ml-tab:not(.ml-tab-active) {
background: transparent !important;
border-radius: 0 !important;
}
#model-linker-modal .ml-tab:not(.ml-tab-active):hover {
background: var(--ml-tab-hover-bg) !important;
border-radius: 9px 9px 0 0 !important;
}
#model-linker-modal .ml-tab.ml-tab-active {
margin-bottom: 0 !important;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.07) !important;
}
/* Loaded Models Tab */
.ml-loaded-models {
+6 -5
View File
@@ -56,10 +56,10 @@
justify-content: space-between;
align-items: center;
gap: var(--ml-spacing-10);
min-height: 40px;
padding: 5px 10px;
border-bottom: 1px solid rgba(255, 255, 255, 0.09);
background: linear-gradient(180deg, rgba(255,255,255,0.035) 0%, rgba(255,255,255,0.012) 100%);
min-height: 42px;
padding: 6px 10px 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.075);
background: #1f1f1f;
}
.ml-dialog-brand,
@@ -73,13 +73,14 @@
.ml-dialog-brand {
min-width: 0;
flex: 1 1 auto;
align-self: stretch;
}
.ml-dialog-controls {
flex: 0 0 auto;
align-self: stretch;
gap: 0;
margin: -5px -10px -5px 0;
margin: -6px -10px 0 0;
}
#model-linker-drag-handle {
+36 -10
View File
@@ -2027,6 +2027,9 @@ class LinkerManagerDialog extends ComfyDialog {
textContent: "Options",
onclick: () => this.switchTab('options')
});
if (this.activeTab === 'missing') {
this.updateTabButtonStates();
}
const dragHandle = $el("div", {
id: "model-linker-drag-handle",
@@ -2983,19 +2986,48 @@ class LinkerManagerDialog extends ComfyDialog {
}
getTabButton(tab) {
return {
missing: this.missingTab,
loaded: this.loadedTab,
options: this.optionsTab
}[tab] || null;
}
updateTabButtonStates() {
['missing', 'loaded', 'options'].forEach((tab) => {
const button = this.getTabButton(tab);
if (!button) return;
const isActive = tab === this.activeTab;
button.classList.toggle('ml-tab-active', isActive);
button.setAttribute('aria-selected', isActive ? 'true' : 'false');
button.setAttribute('aria-disabled', isActive ? 'true' : 'false');
if (isActive) {
button.setAttribute('aria-current', 'page');
} else {
button.removeAttribute('aria-current');
}
});
}
switchTab(tab) {
this.activeTab = this.getValidTab(tab);
const nextTab = this.getValidTab(tab);
const nextTabButton = this.getTabButton(nextTab);
if (nextTab === this.activeTab && nextTabButton?.classList.contains('ml-tab-active')) {
this.hideTooltip();
return;
}
this.activeTab = nextTab;
this.persistActiveTab(this.activeTab);
this.hideTooltip();
this.animateTabContentTransition();
this.updateTabButtonStates();
if (this.activeTab === 'missing') {
if (this.contentElement) {
this.contentElement.style.overflowY = 'auto';
}
this.missingTab.classList.add('ml-tab-active');
this.loadedTab.classList.remove('ml-tab-active');
this.optionsTab.classList.remove('ml-tab-active');
this.downloadAllButton.style.display = 'inline-flex';
this.autoResolveButton.style.display = 'inline-flex';
this.applyPendingBtn.style.display = 'inline-flex';
@@ -3011,9 +3043,6 @@ class LinkerManagerDialog extends ComfyDialog {
if (this.contentElement) {
this.contentElement.style.overflowY = 'auto';
}
this.missingTab.classList.remove('ml-tab-active');
this.loadedTab.classList.add('ml-tab-active');
this.optionsTab.classList.remove('ml-tab-active');
this.downloadAllButton.style.display = 'none';
this.autoResolveButton.style.display = 'none';
this.applyPendingBtn.style.display = 'none';
@@ -3029,9 +3058,6 @@ class LinkerManagerDialog extends ComfyDialog {
if (this.contentElement) {
this.contentElement.style.overflowY = 'hidden';
}
this.missingTab.classList.remove('ml-tab-active');
this.loadedTab.classList.remove('ml-tab-active');
this.optionsTab.classList.add('ml-tab-active');
this.downloadAllButton.style.display = 'none';
this.autoResolveButton.style.display = 'none';
this.applyPendingBtn.style.display = 'none';