Files
HuangYuChuh-ComfyUI-LLMs-To…/web/css/provider_manager.css
T
科林_Cyril Pilgrim f6d72ef002 feat(ui): refine save button style and add ESC key listener to close manager
Motivation:
The save button's style was originally an overly bright gradient, making it feel out of place compared to the frosted glass aesthetics. Additionally, the user requested the ability to close the modal using the Escape key.

Implementation:
1. Updated '.llm-pm-actions-right button:last-child' CSS to use a restrained translucent background similar to the sidebar items, keeping it cohesive with the glassmorphism design.
2. Added a global 'keydown' listener on 'Escape' inside 'ProviderManager.show()' which correctly triggers 'closeModal()' (also checking for unsaved changes) and automatically removes itself when closed.
2026-03-05 09:34:16 +08:00

660 lines
17 KiB
CSS

/* ============================================================
LLMs Toolkit Manager — Apple Glassmorphism Design System
Pure Vanilla CSS. No frameworks. No dependencies.
============================================================ */
/* -- Design Tokens -- */
:root {
--glass-bg-base: #0c1015;
--glass-panel-bg: rgba(22, 27, 40, 0.65);
--glass-panel-bg-solid: rgba(18, 22, 34, 0.85);
--glass-sidebar-bg: rgba(16, 20, 32, 0.55);
--glass-input-bg: rgba(0, 0, 0, 0.25);
--glass-accent: #6366f1;
--glass-accent-glow: rgba(99, 102, 241, 0.35);
--glass-accent-hover: #818cf8;
--glass-success: #34d399;
--glass-success-glow: rgba(52, 211, 153, 0.3);
--glass-danger: #f87171;
--glass-text-primary: rgba(255, 255, 255, 0.92);
--glass-text-secondary: rgba(255, 255, 255, 0.45);
--glass-text-tertiary: rgba(255, 255, 255, 0.25);
--glass-border: rgba(255, 255, 255, 0.08);
--glass-border-light: rgba(255, 255, 255, 0.12);
--glass-blur: blur(24px) saturate(180%);
--glass-radius-lg: 20px;
--glass-radius-md: 14px;
--glass-radius-sm: 10px;
--glass-radius-xs: 8px;
--glass-transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
--glass-font: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
/* ============================================================
MODAL CONTAINER
============================================================ */
.llm-pm-modal {
width: 860px;
height: 620px;
padding: 0;
overflow: hidden;
display: flex;
flex-direction: column;
font-family: var(--glass-font);
background: var(--glass-bg-base) !important;
border: 1px solid var(--glass-border-light) !important;
border-radius: var(--glass-radius-lg) !important;
box-shadow:
0 25px 60px -12px rgba(0, 0, 0, 0.7),
0 0 1px 0 rgba(255, 255, 255, 0.1),
inset 0 1px 0 rgba(255, 255, 255, 0.06) !important;
color: var(--glass-text-primary);
}
.llm-pm-modal input,
.llm-pm-modal button,
.llm-pm-modal select {
font-family: inherit;
}
/* ============================================================
HEADER
============================================================ */
.llm-pm-header {
padding: 16px 24px;
border-bottom: 1px solid var(--glass-border);
display: flex;
justify-content: space-between;
align-items: center;
background: var(--glass-panel-bg-solid);
backdrop-filter: var(--glass-blur);
-webkit-backdrop-filter: var(--glass-blur);
flex-shrink: 0;
}
.llm-pm-title {
font-size: 1.05em;
font-weight: 600;
color: var(--glass-text-primary);
margin: 0;
letter-spacing: 0.02em;
}
.llm-pm-close {
cursor: pointer;
font-size: 1.3em;
color: var(--glass-text-secondary);
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: var(--glass-transition);
}
.llm-pm-close:hover {
color: var(--glass-text-primary);
background: rgba(255, 255, 255, 0.08);
}
/* ============================================================
BODY (Sidebar + Content)
============================================================ */
.llm-pm-body {
display: flex;
flex: 1;
overflow: hidden;
background: transparent;
}
/* ============================================================
SIDEBAR
============================================================ */
.llm-pm-sidebar {
width: 240px;
border-right: 1px solid var(--glass-border);
display: flex;
flex-direction: column;
background: var(--glass-sidebar-bg);
backdrop-filter: var(--glass-blur);
-webkit-backdrop-filter: var(--glass-blur);
}
/* -- Search -- */
.llm-pm-search {
padding: 12px 14px;
border-bottom: 1px solid var(--glass-border);
}
.llm-pm-search input {
width: 100%;
box-sizing: border-box;
background: var(--glass-input-bg);
color: var(--glass-text-primary);
border: 1px solid var(--glass-border);
padding: 8px 12px;
border-radius: var(--glass-radius-sm);
font-size: 0.85em;
transition: var(--glass-transition);
}
.llm-pm-search input::placeholder {
color: var(--glass-text-tertiary);
}
.llm-pm-search input:focus {
outline: none;
border-color: var(--glass-accent);
box-shadow: 0 0 0 3px var(--glass-accent-glow),
inset 0 1px 2px rgba(0, 0, 0, 0.2);
}
/* -- Provider List -- */
.llm-pm-list {
flex: 1;
overflow-y: auto;
padding: 8px;
scrollbar-width: thin;
scrollbar-color: rgba(255, 255, 255, 0.1) transparent;
}
.llm-pm-list::-webkit-scrollbar {
width: 4px;
}
.llm-pm-list::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.12);
border-radius: 4px;
}
.llm-pm-item {
padding: 10px 12px;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
color: var(--glass-text-primary);
border-radius: var(--glass-radius-xs);
margin-bottom: 2px;
transition: var(--glass-transition);
font-size: 0.88em;
}
.llm-pm-item:hover:not(.active) {
background: rgba(255, 255, 255, 0.08);
}
.llm-pm-item.active {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, rgba(255, 255, 255, 0.04) 100%);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2), inset 0 1px 1px rgba(255, 255, 255, 0.2);
color: #fff;
font-weight: 500;
}
/* -- Tags -- */
.llm-pm-item-tags {
display: flex;
gap: 4px;
}
.llm-pm-tag {
font-size: 0.65em;
padding: 2px 7px;
border-radius: 20px;
background: rgba(255, 255, 255, 0.06);
color: var(--glass-text-secondary);
border: 1px solid var(--glass-border);
font-weight: 500;
letter-spacing: 0.03em;
text-transform: uppercase;
}
.llm-pm-tag.on {
background: rgba(52, 211, 153, 0.15);
color: var(--glass-success);
border-color: rgba(52, 211, 153, 0.25);
}
/* -- Sidebar Footer -- */
.llm-pm-sidebar-footer {
padding: 12px 14px;
border-top: 1px solid var(--glass-border);
display: flex;
flex-direction: column;
gap: 6px;
}
.llm-pm-add-btn {
width: 100%;
background: linear-gradient(135deg, rgba(99, 102, 241, 0.2) 0%, rgba(99, 102, 241, 0.05) 100%) !important;
color: var(--glass-accent-hover) !important;
border: none !important;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2), inset 0 1px 1px rgba(99, 102, 241, 0.25);
border-radius: var(--glass-radius-xs) !important;
padding: 8px 0 !important;
font-size: 0.85em !important;
font-weight: 500 !important;
cursor: pointer;
transition: var(--glass-transition);
}
.llm-pm-add-btn:hover {
background: linear-gradient(135deg, rgba(99, 102, 241, 0.35) 0%, rgba(99, 102, 241, 0.12) 100%) !important;
box-shadow: 0 2px 8px rgba(99, 102, 241, 0.3), inset 0 1px 1px rgba(255, 255, 255, 0.3);
}
/* ============================================================
CONTENT PANEL
============================================================ */
.llm-pm-content {
flex: 1;
padding: 24px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 20px;
background: var(--glass-panel-bg);
backdrop-filter: var(--glass-blur);
-webkit-backdrop-filter: var(--glass-blur);
scrollbar-width: thin;
scrollbar-color: rgba(255, 255, 255, 0.1) transparent;
}
.llm-pm-content::-webkit-scrollbar {
width: 4px;
}
.llm-pm-content::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.12);
border-radius: 4px;
}
.llm-pm-empty {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: var(--glass-text-tertiary);
font-size: 0.9em;
}
/* -- Fields -- */
.llm-pm-field {
display: flex;
flex-direction: column;
gap: 8px;
}
.llm-pm-field label {
font-size: 0.8em;
font-weight: 600;
color: var(--glass-text-secondary);
display: flex;
justify-content: space-between;
text-transform: uppercase;
letter-spacing: 0.06em;
}
.llm-pm-field input[type="text"],
.llm-pm-field input[type="password"] {
width: 100%;
box-sizing: border-box;
background: var(--glass-input-bg);
color: var(--glass-text-primary);
border: 1px solid var(--glass-border);
padding: 10px 14px;
border-radius: var(--glass-radius-sm);
font-size: 0.88em;
transition: var(--glass-transition);
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15);
}
.llm-pm-field input:focus {
outline: none;
border-color: var(--glass-accent);
box-shadow: 0 0 0 3px var(--glass-accent-glow),
inset 0 2px 4px rgba(0, 0, 0, 0.15);
}
.llm-pm-field-hint {
font-size: 0.75em;
color: var(--glass-text-tertiary);
word-break: break-all;
}
.llm-pm-input-group {
display: flex;
gap: 8px;
align-items: center;
}
.llm-pm-input-group input {
flex: 1;
}
@keyframes llm-pm-spin-anim {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.llm-pm-spin {
animation: llm-pm-spin-anim 1s linear infinite;
}
/* ============================================================
MODEL TAGS
============================================================ */
.llm-pm-models {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 8px;
}
.llm-pm-model-tag {
display: inline-flex;
align-items: center;
gap: 6px;
background: rgba(255, 255, 255, 0.05);
color: var(--glass-text-primary);
padding: 5px 12px;
border-radius: 20px;
font-size: 0.82em;
border: 1px solid var(--glass-border);
transition: var(--glass-transition);
}
.llm-pm-model-tag:hover {
background: rgba(255, 255, 255, 0.08);
border-color: var(--glass-border-light);
}
.llm-pm-model-del {
cursor: pointer;
color: var(--glass-text-tertiary);
transition: var(--glass-transition);
font-size: 0.85em;
}
.llm-pm-model-del:hover {
color: var(--glass-danger);
}
.llm-pm-model-add {
display: inline-flex;
align-items: center;
justify-content: center;
background: transparent;
color: var(--glass-text-tertiary);
border: 1px dashed rgba(255, 255, 255, 0.12);
padding: 5px 12px;
border-radius: 20px;
font-size: 0.82em;
cursor: pointer;
transition: var(--glass-transition);
}
.llm-pm-model-add:hover {
color: var(--glass-accent-hover);
border-color: var(--glass-accent);
background: rgba(99, 102, 241, 0.08);
}
/* ============================================================
ACTION BUTTONS (Bottom bar)
============================================================ */
.llm-pm-actions {
margin-top: auto;
display: flex;
justify-content: space-between;
padding-top: 20px;
border-top: 1px solid var(--glass-border);
}
.llm-pm-actions-right {
display: flex;
gap: 10px;
}
/* Override ComfyUI default button styles inside our modal */
.llm-pm-actions button,
.llm-pm-sidebar-footer button {
border-radius: var(--glass-radius-xs) !important;
font-size: 0.85em !important;
font-weight: 500 !important;
padding: 8px 18px !important;
transition: var(--glass-transition);
cursor: pointer;
}
/* Delete button */
.llm-pm-actions button:first-child {
background: rgba(248, 113, 113, 0.1) !important;
color: var(--glass-danger) !important;
border: 1px solid rgba(248, 113, 113, 0.2) !important;
}
.llm-pm-actions button:first-child:hover {
background: rgba(248, 113, 113, 0.2) !important;
box-shadow: 0 0 12px rgba(248, 113, 113, 0.15);
}
/* Save / Test buttons */
.llm-pm-actions-right button {
background: rgba(99, 102, 241, 0.12) !important;
color: var(--glass-accent-hover) !important;
border: 1px solid rgba(99, 102, 241, 0.2) !important;
}
.llm-pm-actions-right button:hover {
background: rgba(99, 102, 241, 0.22) !important;
border-color: rgba(99, 102, 241, 0.4) !important;
box-shadow: 0 0 16px var(--glass-accent-glow);
}
.llm-pm-actions-right button:last-child {
background: rgba(255, 255, 255, 0.08) !important;
color: var(--glass-text-primary) !important;
border: 1px solid rgba(255, 255, 255, 0.15) !important;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2), inset 0 1px 1px rgba(255, 255, 255, 0.1);
}
.llm-pm-actions-right button:last-child:hover {
background: rgba(255, 255, 255, 0.15) !important;
border-color: rgba(255, 255, 255, 0.25) !important;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3), inset 0 1px 1px rgba(255, 255, 255, 0.2);
transform: translateY(-1px);
}
/* ============================================================
SWITCH / TOGGLE
============================================================ */
.llm-pm-switch {
position: relative;
display: inline-block;
width: 42px;
height: 22px;
}
.llm-pm-switch input {
opacity: 0;
width: 0;
height: 0;
}
.llm-pm-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, 0.08);
transition: var(--glass-transition);
border-radius: 22px;
border: 1px solid var(--glass-border);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3);
}
.llm-pm-slider:before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 2px;
bottom: 2px;
background-color: var(--glass-text-secondary);
transition: var(--glass-transition);
border-radius: 50%;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
.llm-pm-switch input:checked+.llm-pm-slider {
background: linear-gradient(135deg, var(--glass-accent), #8b5cf6);
border-color: transparent;
box-shadow: 0 0 12px var(--glass-accent-glow),
inset 0 1px 2px rgba(255, 255, 255, 0.15);
}
.llm-pm-switch input:checked+.llm-pm-slider:before {
transform: translateX(20px);
background-color: white;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
}
/* ============================================================
PROMPT DIALOG (Add Model overlay)
============================================================ */
.llm-pm-prompt-overlay {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
display: flex;
justify-content: center;
align-items: center;
z-index: 20000;
}
.llm-pm-prompt-dialog {
background: var(--glass-panel-bg-solid);
backdrop-filter: var(--glass-blur);
-webkit-backdrop-filter: var(--glass-blur);
border: 1px solid var(--glass-border-light);
border-radius: var(--glass-radius-md);
padding: 24px;
width: 320px;
display: flex;
flex-direction: column;
gap: 16px;
box-shadow:
0 20px 40px rgba(0, 0, 0, 0.5),
inset 0 1px 0 rgba(255, 255, 255, 0.06);
animation: glass-dialog-in 0.2s ease-out;
}
@keyframes glass-dialog-in {
from {
opacity: 0;
transform: scale(0.95) translateY(8px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
.llm-pm-prompt-dialog h3 {
margin: 0;
font-size: 1em;
font-weight: 600;
color: var(--glass-text-primary);
}
.llm-pm-prompt-dialog input {
width: 100%;
box-sizing: border-box;
background: var(--glass-input-bg);
color: var(--glass-text-primary);
border: 1px solid var(--glass-border);
padding: 10px 14px;
border-radius: var(--glass-radius-sm);
font-size: 0.88em;
transition: var(--glass-transition);
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15);
}
.llm-pm-prompt-dialog input:focus {
outline: none;
border-color: var(--glass-accent);
box-shadow: 0 0 0 3px var(--glass-accent-glow),
inset 0 2px 4px rgba(0, 0, 0, 0.15);
}
.llm-pm-prompt-actions {
display: flex;
justify-content: flex-end;
gap: 10px;
}
.llm-pm-prompt-actions button {
padding: 8px 18px;
border-radius: var(--glass-radius-xs);
cursor: pointer;
font-weight: 500;
font-size: 0.85em;
transition: var(--glass-transition);
}
.llm-pm-prompt-actions .cancel {
background: rgba(255, 255, 255, 0.06);
color: var(--glass-text-secondary);
border: 1px solid var(--glass-border);
}
.llm-pm-prompt-actions .cancel:hover {
background: rgba(255, 255, 255, 0.1);
color: var(--glass-text-primary);
}
.llm-pm-prompt-actions .confirm {
background: linear-gradient(135deg, var(--glass-accent), #8b5cf6);
color: white;
border: none;
box-shadow: 0 4px 14px var(--glass-accent-glow);
}
.llm-pm-prompt-actions .confirm:hover {
box-shadow: 0 6px 20px rgba(99, 102, 241, 0.45);
transform: translateY(-1px);
}
/* ============================================================
USAGE STATS SPECIFIC STYLES
============================================================ */
/* Style the usage stats button in sidebar footer */
.llm-pm-sidebar-footer button[style*="dashed"] {
background: transparent !important;
color: var(--glass-text-secondary) !important;
border: 1px dashed var(--glass-border-light) !important;
border-radius: var(--glass-radius-xs) !important;
font-size: 0.82em !important;
}
.llm-pm-sidebar-footer button[style*="dashed"]:hover {
color: var(--glass-text-primary) !important;
border-color: var(--glass-text-secondary) !important;
background: rgba(255, 255, 255, 0.04) !important;
}