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:
+78
-25
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user