Polish modals and add settings save button feedback
Release rolling / release (push) Has been cancelled
Release rolling / release (push) Has been cancelled
Replace stock Bootstrap modal chrome with a dark teal panel system, and give Settings Save all a Saving… / Saved state with motion-aware styles.
This commit is contained in:
+2
-2
@@ -2995,8 +2995,8 @@ services:
|
|||||||
</div><!-- /.settings-page-scroll -->
|
</div><!-- /.settings-page-scroll -->
|
||||||
|
|
||||||
<div class="settings-footer" role="toolbar" aria-label="Settings actions">
|
<div class="settings-footer" role="toolbar" aria-label="Settings actions">
|
||||||
<button type="button" class="btn btn-primary settings-save-btn" id="settings-save-btn">
|
<button type="button" class="btn btn-primary settings-save-btn" id="settings-save-btn" aria-live="polite">
|
||||||
<i class="fas fa-floppy-disk me-1" aria-hidden="true"></i>Save all
|
<i class="fas fa-floppy-disk me-1" aria-hidden="true"></i><span class="settings-save-label">Save all</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+543
-30
@@ -2909,27 +2909,535 @@ table.pd-col-table td.pd-col-hidden {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card,
|
.card {
|
||||||
.modal-content {
|
|
||||||
background: var(--bg-elevated) !important;
|
background: var(--bg-elevated) !important;
|
||||||
border: 1px solid var(--border-color) !important;
|
border: 1px solid var(--border-color) !important;
|
||||||
border-radius: var(--border-radius) !important;
|
border-radius: var(--border-radius) !important;
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header {
|
/* ═══════════════════════════════════════════════════════════
|
||||||
border-bottom-color: var(--border-color) !important;
|
Modal design system — polished panels matching app chrome
|
||||||
padding: 16px 20px;
|
═══════════════════════════════════════════════════════════ */
|
||||||
|
|
||||||
|
.modal-backdrop {
|
||||||
|
background: rgba(2, 6, 23, 0.78) !important;
|
||||||
|
backdrop-filter: blur(12px) saturate(1.15);
|
||||||
|
-webkit-backdrop-filter: blur(12px) saturate(1.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-footer {
|
.modal-backdrop.show {
|
||||||
border-top-color: var(--border-color) !important;
|
opacity: 1 !important;
|
||||||
padding: 14px 20px;
|
}
|
||||||
|
|
||||||
|
/* Entrance: soft rise + scale (pairs with Bootstrap fade) */
|
||||||
|
.modal.fade .modal-dialog {
|
||||||
|
transform: translateY(14px) scale(0.97);
|
||||||
|
transition:
|
||||||
|
transform 0.22s cubic-bezier(0.22, 1, 0.36, 1),
|
||||||
|
opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal.show .modal-dialog {
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog {
|
||||||
|
margin-top: max(1.25rem, calc(var(--titlebar-h, 42px) + 0.65rem));
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog-centered {
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
--pd-modal-pad-x: 1.35rem;
|
||||||
|
background:
|
||||||
|
radial-gradient(900px 280px at 12% -20%, rgba(52, 211, 153, 0.1), transparent 55%),
|
||||||
|
radial-gradient(700px 240px at 100% 0%, rgba(45, 212, 191, 0.06), transparent 50%),
|
||||||
|
linear-gradient(168deg, #1a2433 0%, #121a24 48%, #0d131c 100%) !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.09) !important;
|
||||||
|
border-radius: 16px !important;
|
||||||
|
color: var(--text-primary) !important;
|
||||||
|
box-shadow:
|
||||||
|
0 28px 64px rgba(0, 0, 0, 0.58),
|
||||||
|
0 0 0 1px rgba(52, 211, 153, 0.07),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.045);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content.bg-dark {
|
||||||
|
background:
|
||||||
|
radial-gradient(900px 280px at 12% -20%, rgba(52, 211, 153, 0.1), transparent 55%),
|
||||||
|
radial-gradient(700px 240px at 100% 0%, rgba(45, 212, 191, 0.06), transparent 50%),
|
||||||
|
linear-gradient(168deg, #1a2433 0%, #121a24 48%, #0d131c 100%) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Header ── */
|
||||||
|
.modal-header {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
background: transparent !important;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.06) !important;
|
||||||
|
padding: 1.15rem var(--pd-modal-pad-x, 1.35rem) 1rem !important;
|
||||||
|
min-height: 3.65rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header.border-secondary,
|
||||||
|
.modal-footer.border-secondary {
|
||||||
|
border-color: rgba(255, 255, 255, 0.06) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: var(--pd-modal-pad-x, 1.35rem);
|
||||||
|
right: var(--pd-modal-pad-x, 1.35rem);
|
||||||
|
bottom: -1px;
|
||||||
|
height: 1px;
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
rgba(52, 211, 153, 0.5) 0%,
|
||||||
|
rgba(52, 211, 153, 0.12) 42%,
|
||||||
|
transparent 88%
|
||||||
|
);
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-title {
|
.modal-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.55rem;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.05rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.025em;
|
||||||
|
line-height: 1.3;
|
||||||
|
color: var(--text-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icon chip in titles — matches page-header accent treatment */
|
||||||
|
.modal-title > i,
|
||||||
|
.modal-title > .fas,
|
||||||
|
.modal-title > .far,
|
||||||
|
.modal-title > .fab,
|
||||||
|
.modal-title > .fa {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: 1.85rem;
|
||||||
|
height: 1.85rem;
|
||||||
|
margin: 0 !important;
|
||||||
|
display: inline-grid;
|
||||||
|
place-items: center;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
border-radius: 9px;
|
||||||
|
color: var(--accent-primary) !important;
|
||||||
|
background: rgba(52, 211, 153, 0.12);
|
||||||
|
border: 1px solid rgba(52, 211, 153, 0.2);
|
||||||
|
box-shadow: 0 0 0 1px rgba(52, 211, 153, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Close control ── */
|
||||||
|
.modal-header .btn-close,
|
||||||
|
.modal-header .btn-close-white {
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 0 0 auto;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
opacity: 0.72;
|
||||||
|
background-color: rgba(255, 255, 255, 0.04);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
background-size: 0.62em;
|
||||||
|
transition:
|
||||||
|
opacity 0.15s ease,
|
||||||
|
background-color 0.15s ease,
|
||||||
|
border-color 0.15s ease,
|
||||||
|
transform 0.12s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header .btn-close-white {
|
||||||
|
filter: invert(1) grayscale(100%) brightness(200%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header .btn-close:hover,
|
||||||
|
.modal-header .btn-close-white:hover,
|
||||||
|
.modal-header .btn-close:focus {
|
||||||
|
opacity: 1;
|
||||||
|
background-color: rgba(248, 113, 113, 0.12) !important;
|
||||||
|
border-color: rgba(248, 113, 113, 0.28);
|
||||||
|
box-shadow: none;
|
||||||
|
transform: scale(1.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header .btn-close:focus-visible {
|
||||||
|
outline: 2px solid rgba(52, 211, 153, 0.45);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Body ── */
|
||||||
|
.modal-body {
|
||||||
|
background: transparent !important;
|
||||||
|
color: var(--text-secondary) !important;
|
||||||
|
padding: 1.2rem var(--pd-modal-pad-x, 1.35rem) 1.05rem !important;
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body > p:last-child,
|
||||||
|
.modal-body > .mb-0:last-child {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .text-muted,
|
||||||
|
.modal-body small,
|
||||||
|
.modal-body .form-text,
|
||||||
|
.modal-content .form-text {
|
||||||
|
color: var(--text-muted) !important;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
line-height: 1.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body code {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.82em;
|
||||||
|
padding: 0.1em 0.35em;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: var(--accent-secondary);
|
||||||
|
background: rgba(45, 212, 191, 0.08);
|
||||||
|
border: 1px solid rgba(45, 212, 191, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Form labels — refined, not Bootstrap default */
|
||||||
|
.modal-body .form-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.4rem;
|
||||||
|
margin-bottom: 0.4rem;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
color: var(--text-secondary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .form-label .text-danger {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .form-label .text-muted {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.78em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inputs sit slightly recessed in the panel */
|
||||||
|
.modal-body .form-control,
|
||||||
|
.modal-body .form-select,
|
||||||
|
.modal-content .form-control,
|
||||||
|
.modal-content .form-select {
|
||||||
|
background: rgba(0, 0, 0, 0.28) !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.09) !important;
|
||||||
|
border-radius: 10px !important;
|
||||||
|
color: var(--text-primary) !important;
|
||||||
|
min-height: 2.45rem;
|
||||||
|
padding: 0.55rem 0.8rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.02);
|
||||||
|
transition:
|
||||||
|
border-color 0.15s ease,
|
||||||
|
box-shadow 0.15s ease,
|
||||||
|
background 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body textarea.form-control {
|
||||||
|
min-height: 5rem;
|
||||||
|
line-height: 1.45;
|
||||||
|
padding-top: 0.65rem;
|
||||||
|
padding-bottom: 0.65rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .form-control:hover,
|
||||||
|
.modal-body .form-select:hover,
|
||||||
|
.modal-content .form-control:hover,
|
||||||
|
.modal-content .form-select:hover {
|
||||||
|
border-color: rgba(52, 211, 153, 0.28) !important;
|
||||||
|
background: rgba(0, 0, 0, 0.34) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .form-control:focus,
|
||||||
|
.modal-body .form-select:focus,
|
||||||
|
.modal-content .form-control:focus,
|
||||||
|
.modal-content .form-select:focus {
|
||||||
|
border-color: rgba(52, 211, 153, 0.55) !important;
|
||||||
|
background: rgba(0, 0, 0, 0.36) !important;
|
||||||
|
box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.14) !important;
|
||||||
|
color: var(--text-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .form-control::placeholder {
|
||||||
|
color: var(--text-faint);
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .form-control.font-monospace,
|
||||||
|
.modal-body .form-select.font-monospace {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.84rem;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .input-group .form-control {
|
||||||
|
border-top-right-radius: 0 !important;
|
||||||
|
border-bottom-right-radius: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .input-group .btn {
|
||||||
|
font-weight: 600;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .form-check-input {
|
||||||
|
background-color: rgba(255, 255, 255, 0.08);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .form-switch .form-check-input {
|
||||||
|
width: 2.4rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
margin-top: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .form-check-input:checked {
|
||||||
|
background-color: var(--accent-primary);
|
||||||
|
border-color: var(--accent-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .form-check-input:focus {
|
||||||
|
box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.18);
|
||||||
|
border-color: rgba(52, 211, 153, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .form-check-label {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Section titles inside large forms (duplicate / deploy) */
|
||||||
|
.modal-body h6 {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin: 0.35rem 0 0.95rem;
|
||||||
|
padding-bottom: 0.65rem;
|
||||||
|
font-size: 0.88rem;
|
||||||
font-weight: 650;
|
font-weight: 650;
|
||||||
letter-spacing: -0.02em;
|
letter-spacing: -0.015em;
|
||||||
|
color: var(--text-primary) !important;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body h6 i {
|
||||||
|
color: var(--accent-primary);
|
||||||
|
font-size: 0.85em;
|
||||||
|
opacity: 0.95;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body h6.text-primary {
|
||||||
|
color: var(--text-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grouped form sections (h6 + fields) read as soft cards */
|
||||||
|
.modal-body .mb-3 {
|
||||||
|
margin-bottom: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body > form > .mb-4,
|
||||||
|
.modal-body > .mb-4 {
|
||||||
|
margin-bottom: 1.15rem !important;
|
||||||
|
padding: 0.9rem 1rem;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: rgba(255, 255, 255, 0.018);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body > form > .mb-4 > h6,
|
||||||
|
.modal-body > .mb-4 > h6 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Footer ── */
|
||||||
|
.modal-footer {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 0.55rem;
|
||||||
|
background: linear-gradient(180deg, rgba(0, 0, 0, 0.12) 0%, rgba(0, 0, 0, 0.28) 100%) !important;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.06) !important;
|
||||||
|
padding: 0.9rem var(--pd-modal-pad-x, 1.35rem) !important;
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer > * {
|
||||||
|
margin: 0 !important; /* kill Bootstrap .btn + .btn spacing */
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer .btn {
|
||||||
|
border-radius: 10px;
|
||||||
|
min-height: 2.4rem;
|
||||||
|
padding: 0.45rem 1.05rem;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cancel / secondary CTAs read as quiet companions to primary */
|
||||||
|
.modal-footer .btn-secondary {
|
||||||
|
background: transparent !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12) !important;
|
||||||
|
color: var(--text-secondary) !important;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer .btn-secondary:hover,
|
||||||
|
.modal-footer .btn-secondary:focus {
|
||||||
|
background: rgba(255, 255, 255, 0.06) !important;
|
||||||
|
border-color: rgba(255, 255, 255, 0.2) !important;
|
||||||
|
color: var(--text-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer .btn-primary {
|
||||||
|
box-shadow: 0 4px 16px rgba(52, 211, 153, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer .btn-primary:hover {
|
||||||
|
box-shadow: 0 6px 20px rgba(52, 211, 153, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer .btn-danger {
|
||||||
|
box-shadow: 0 4px 14px rgba(248, 113, 113, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compact / large variants */
|
||||||
|
.modal-sm .modal-content {
|
||||||
|
border-radius: 14px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-sm .modal-header,
|
||||||
|
.modal-sm .modal-body,
|
||||||
|
.modal-sm .modal-footer {
|
||||||
|
--pd-modal-pad-x: 1.15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-lg .modal-content,
|
||||||
|
.modal-xl .modal-content {
|
||||||
|
--pd-modal-pad-x: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scrollable bodies keep header/footer chrome intact */
|
||||||
|
.modal-dialog-scrollable .modal-content {
|
||||||
|
max-height: calc(100vh - var(--titlebar-h, 42px) - 2.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog-scrollable .modal-body {
|
||||||
|
overscroll-behavior: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Accordion inside modals (duplicate form etc.) */
|
||||||
|
.modal-body .accordion-item {
|
||||||
|
background: rgba(0, 0, 0, 0.18) !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.06) !important;
|
||||||
|
border-radius: 10px !important;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .accordion-button {
|
||||||
|
background: rgba(255, 255, 255, 0.02) !important;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .accordion-body {
|
||||||
|
background: transparent;
|
||||||
|
padding: 0.85rem 1rem 1rem;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Suggested badges in smart forms */
|
||||||
|
.modal-body .pd-suggested {
|
||||||
|
font-size: 0.68rem;
|
||||||
|
font-weight: 650;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding: 0.15rem 0.45rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
color: var(--accent-primary);
|
||||||
|
background: rgba(52, 211, 153, 0.12);
|
||||||
|
border: 1px solid rgba(52, 211, 153, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* List groups in modals (Hub search) */
|
||||||
|
.modal-body .list-group-item {
|
||||||
|
background: rgba(0, 0, 0, 0.2) !important;
|
||||||
|
border-color: rgba(255, 255, 255, 0.06) !important;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body .list-group-item-action:hover {
|
||||||
|
background: rgba(52, 211, 153, 0.08) !important;
|
||||||
|
color: var(--text-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Terminal toolbar strip under header */
|
||||||
|
.modal-content > .terminal-toolbar {
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
||||||
|
background: rgba(0, 0, 0, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quiet scrollbars in modal bodies */
|
||||||
|
.modal-body::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(255, 255, 255, 0.12);
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
background-clip: padding-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: rgba(52, 211, 153, 0.35);
|
||||||
|
background-clip: padding-box;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inspect modals: pre blocks feel like code panels */
|
||||||
|
.modal-body pre {
|
||||||
|
background: rgba(0, 0, 0, 0.35) !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.07);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 0.85rem 1rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.accordion-item {
|
.accordion-item {
|
||||||
@@ -3377,16 +3885,22 @@ table.pd-col-table td.pd-col-hidden {
|
|||||||
|
|
||||||
/* ── Container more-actions modal ── */
|
/* ── Container more-actions modal ── */
|
||||||
.cam-modal {
|
.cam-modal {
|
||||||
border: 1px solid var(--border-strong);
|
/* inherits modal design system surface; only layout overrides here */
|
||||||
border-radius: 16px;
|
border-radius: 16px !important;
|
||||||
background: var(--bg-elevated) !important;
|
|
||||||
box-shadow: var(--shadow-lg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.cam-header {
|
.cam-header {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cam-header::after {
|
||||||
|
display: none; /* subtitle sits under title; no accent line needed */
|
||||||
|
}
|
||||||
|
|
||||||
|
.cam-modal .modal-body.cam-body {
|
||||||
|
padding-top: 0.85rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
.cam-header-text {
|
.cam-header-text {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding-right: 0.5rem;
|
padding-right: 0.5rem;
|
||||||
@@ -4161,18 +4675,13 @@ kbd {
|
|||||||
background-color: var(--bg-hover) !important;
|
background-color: var(--bg-hover) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Accordion / forms in modals */
|
/* Accordion body text (modal body colors owned by modal design system) */
|
||||||
.accordion-body,
|
.accordion-body,
|
||||||
.accordion-body .text-muted,
|
.accordion-body .text-muted {
|
||||||
.modal-body,
|
|
||||||
.modal-body .text-muted,
|
|
||||||
.modal-content .form-text,
|
|
||||||
.modal-content small {
|
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.accordion-body,
|
.accordion-body {
|
||||||
.modal-body {
|
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4603,15 +5112,7 @@ td.image-update-cell {
|
|||||||
box-shadow: 0 4px 14px rgba(52, 211, 153, 0.28);
|
box-shadow: 0 4px 14px rgba(52, 211, 153, 0.28);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Modal footer buttons stay readable on dark modals */
|
/* Close buttons: detailed styles live in the modal design system above */
|
||||||
.modal-content.bg-dark .btn-close-white {
|
|
||||||
filter: invert(1) grayscale(100%) brightness(200%);
|
|
||||||
opacity: 0.75;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content.bg-dark .btn-close-white:hover {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* List-group dark actions used in Hub search / volume browser */
|
/* List-group dark actions used in Hub search / volume browser */
|
||||||
.list-group-item-dark,
|
.list-group-item-dark,
|
||||||
@@ -5092,6 +5593,18 @@ option {
|
|||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-dialog.modal-sm {
|
||||||
|
--bs-modal-width: 380px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog.modal-lg {
|
||||||
|
--bs-modal-width: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog.modal-xl {
|
||||||
|
--bs-modal-width: 1140px;
|
||||||
|
}
|
||||||
|
|
||||||
.modal-content {
|
.modal-content {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
+53
-1
@@ -2195,14 +2195,66 @@ export function initOpsApp({ navigateToView, sendCommand }) {
|
|||||||
showSettingsTab(btn.getAttribute('data-settings-tab'))
|
showSettingsTab(btn.getAttribute('data-settings-tab'))
|
||||||
})
|
})
|
||||||
|
|
||||||
document.getElementById('settings-save-btn')?.addEventListener('click', () => {
|
document.getElementById('settings-save-btn')?.addEventListener('click', (e) => {
|
||||||
|
const btn = e.currentTarget
|
||||||
|
if (btn?.classList.contains('is-saving') || btn?.classList.contains('is-saved')) return
|
||||||
|
|
||||||
|
const idleHtml =
|
||||||
|
btn.dataset.idleHtml ||
|
||||||
|
'<i class="fas fa-floppy-disk me-1" aria-hidden="true"></i><span class="settings-save-label">Save all</span>'
|
||||||
|
if (btn) btn.dataset.idleHtml = idleHtml
|
||||||
|
clearTimeout(btn?._saveFeedbackTimer)
|
||||||
|
|
||||||
|
if (btn) {
|
||||||
|
btn.classList.remove('is-saved', 'is-error')
|
||||||
|
btn.classList.add('is-saving')
|
||||||
|
btn.disabled = true
|
||||||
|
btn.setAttribute('aria-busy', 'true')
|
||||||
|
btn.innerHTML =
|
||||||
|
'<i class="fas fa-circle-notch fa-spin me-1" aria-hidden="true"></i><span class="settings-save-label">Saving…</span>'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Brief saving state so the control always gives tactile feedback (save is local/sync).
|
||||||
|
const finish = (ok, errMsg) => {
|
||||||
|
if (!btn) return
|
||||||
|
btn.classList.remove('is-saving')
|
||||||
|
btn.removeAttribute('aria-busy')
|
||||||
|
if (ok) {
|
||||||
|
btn.classList.add('is-saved')
|
||||||
|
btn.innerHTML =
|
||||||
|
'<i class="fas fa-check me-1 settings-save-check" aria-hidden="true"></i><span class="settings-save-label">Saved</span>'
|
||||||
|
btn._saveFeedbackTimer = setTimeout(() => {
|
||||||
|
btn.classList.remove('is-saved')
|
||||||
|
btn.disabled = false
|
||||||
|
btn.innerHTML = btn.dataset.idleHtml || idleHtml
|
||||||
|
}, 2000)
|
||||||
|
} else {
|
||||||
|
btn.classList.add('is-error')
|
||||||
|
btn.disabled = false
|
||||||
|
btn.innerHTML =
|
||||||
|
'<i class="fas fa-triangle-exclamation me-1" aria-hidden="true"></i><span class="settings-save-label">Failed</span>'
|
||||||
|
btn._saveFeedbackTimer = setTimeout(() => {
|
||||||
|
btn.classList.remove('is-error')
|
||||||
|
btn.innerHTML = btn.dataset.idleHtml || idleHtml
|
||||||
|
}, 2400)
|
||||||
|
if (errMsg) showAlert('danger', errMsg, { badge: false })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.setTimeout(() => {
|
||||||
|
try {
|
||||||
setTemplateListUrls(templateUrlsDraft)
|
setTemplateListUrls(templateUrlsDraft)
|
||||||
const partial = readSettingsForm()
|
const partial = readSettingsForm()
|
||||||
partial.templateListUrls = getTemplateListUrls()
|
partial.templateListUrls = getTemplateListUrls()
|
||||||
const next = saveSettings(partial)
|
const next = saveSettings(partial)
|
||||||
startListAutoRefresh(next.refreshSeconds)
|
startListAutoRefresh(next.refreshSeconds)
|
||||||
if (typeof window !== 'undefined') window.__peardockClearDeployTemplateCache?.()
|
if (typeof window !== 'undefined') window.__peardockClearDeployTemplateCache?.()
|
||||||
|
finish(true)
|
||||||
showAlert('success', 'Preferences saved', { badge: false })
|
showAlert('success', 'Preferences saved', { badge: false })
|
||||||
|
} catch (err) {
|
||||||
|
finish(false, err?.message || 'Could not save preferences')
|
||||||
|
}
|
||||||
|
}, 220)
|
||||||
})
|
})
|
||||||
|
|
||||||
document.getElementById('settings-template-url-add')?.addEventListener('click', () => {
|
document.getElementById('settings-template-url-add')?.addEventListener('click', () => {
|
||||||
|
|||||||
+82
@@ -986,6 +986,16 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
border-radius: 0.55rem;
|
border-radius: 0.55rem;
|
||||||
box-shadow: 0 6px 18px rgba(45, 212, 191, 0.22);
|
box-shadow: 0 6px 18px rgba(45, 212, 191, 0.22);
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.15rem;
|
||||||
|
transition:
|
||||||
|
background-color 0.18s ease,
|
||||||
|
border-color 0.18s ease,
|
||||||
|
box-shadow 0.18s ease,
|
||||||
|
color 0.18s ease,
|
||||||
|
transform 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
#settings-view .settings-footer .settings-save-btn:hover,
|
#settings-view .settings-footer .settings-save-btn:hover,
|
||||||
@@ -993,6 +1003,78 @@
|
|||||||
box-shadow: 0 8px 22px rgba(45, 212, 191, 0.32);
|
box-shadow: 0 8px 22px rgba(45, 212, 191, 0.32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#settings-view .settings-footer .settings-save-btn:disabled {
|
||||||
|
opacity: 1;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Saving… spinner state */
|
||||||
|
#settings-view .settings-footer .settings-save-btn.is-saving {
|
||||||
|
pointer-events: none;
|
||||||
|
background: linear-gradient(135deg, #2dd4bf 0%, #14b8a6 100%) !important;
|
||||||
|
border-color: transparent !important;
|
||||||
|
color: #042f1a !important;
|
||||||
|
box-shadow: 0 4px 14px rgba(45, 212, 191, 0.28);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Saved — success flash */
|
||||||
|
#settings-view .settings-footer .settings-save-btn.is-saved {
|
||||||
|
pointer-events: none;
|
||||||
|
background: linear-gradient(135deg, #4ade80 0%, #22c55e 100%) !important;
|
||||||
|
border-color: transparent !important;
|
||||||
|
color: #052e16 !important;
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 1px rgba(74, 222, 128, 0.35),
|
||||||
|
0 8px 24px rgba(34, 197, 94, 0.35);
|
||||||
|
animation: settings-save-pop 0.35s cubic-bezier(0.22, 1, 0.36, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#settings-view .settings-footer .settings-save-btn.is-saved .settings-save-check {
|
||||||
|
animation: settings-save-check-in 0.35s cubic-bezier(0.22, 1, 0.36, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Failed */
|
||||||
|
#settings-view .settings-footer .settings-save-btn.is-error {
|
||||||
|
background: linear-gradient(135deg, #f87171 0%, #ef4444 100%) !important;
|
||||||
|
border-color: transparent !important;
|
||||||
|
color: #450a0a !important;
|
||||||
|
box-shadow: 0 6px 18px rgba(248, 113, 113, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes settings-save-pop {
|
||||||
|
0% {
|
||||||
|
transform: scale(0.96);
|
||||||
|
}
|
||||||
|
55% {
|
||||||
|
transform: scale(1.04);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes settings-save-check-in {
|
||||||
|
0% {
|
||||||
|
transform: scale(0.4);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
60% {
|
||||||
|
transform: scale(1.15);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
#settings-view .settings-footer .settings-save-btn.is-saved,
|
||||||
|
#settings-view .settings-footer .settings-save-btn.is-saved .settings-save-check {
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Network card disconnect control alignment */
|
/* Network card disconnect control alignment */
|
||||||
.network-card-header {
|
.network-card-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
+23
-18
@@ -2838,39 +2838,44 @@
|
|||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Modal Styling */
|
/* Modal Styling — base layer (modern.css extends the full system) */
|
||||||
.modal-content {
|
.modal-content {
|
||||||
background: var(--bg-secondary);
|
background: linear-gradient(165deg, #1a2332 0%, #121820 50%, #0e141c 100%);
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid rgba(255, 255, 255, 0.09);
|
||||||
border-radius: var(--border-radius);
|
border-radius: 16px;
|
||||||
box-shadow: var(--shadow-xl);
|
box-shadow:
|
||||||
backdrop-filter: blur(10px);
|
0 28px 64px rgba(0, 0, 0, 0.55),
|
||||||
|
0 0 0 1px rgba(45, 212, 191, 0.06),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header {
|
.modal-header {
|
||||||
background: var(--bg-elevated);
|
background: transparent;
|
||||||
border-bottom: 1px solid var(--border-color);
|
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
||||||
border-radius: var(--border-radius) var(--border-radius) 0 0;
|
border-radius: 0;
|
||||||
padding: var(--spacing-lg);
|
padding: 1.15rem 1.35rem 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-title {
|
.modal-title {
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
font-weight: 600;
|
font-weight: 700;
|
||||||
font-size: 1.25rem;
|
font-size: 1.05rem;
|
||||||
|
letter-spacing: -0.025em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-body {
|
.modal-body {
|
||||||
background: var(--bg-secondary);
|
background: transparent;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
padding: var(--spacing-lg);
|
padding: 1.25rem 1.35rem 1.1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-footer {
|
.modal-footer {
|
||||||
background: var(--bg-elevated);
|
background: rgba(0, 0, 0, 0.22);
|
||||||
border-top: 1px solid var(--border-color);
|
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
||||||
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
border-radius: 0;
|
||||||
padding: var(--spacing-lg);
|
padding: 0.9rem 1.35rem;
|
||||||
|
gap: 0.55rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-close-white {
|
.btn-close-white {
|
||||||
|
|||||||
Reference in New Issue
Block a user