diff --git a/ui/src/styles/config.css b/ui/src/styles/config.css index aff3e88b4..641617b30 100644 --- a/ui/src/styles/config.css +++ b/ui/src/styles/config.css @@ -5,7 +5,7 @@ /* Layout Container */ .config-layout { display: grid; - grid-template-columns: 260px minmax(0, 1fr); + grid-template-columns: 240px minmax(0, 1fr); gap: 0; min-height: calc(100vh - 140px); margin: -16px; @@ -15,16 +15,18 @@ background: var(--panel); } -/* Sidebar */ +/* =========================================== + Sidebar + =========================================== */ .config-sidebar { display: flex; flex-direction: column; - background: linear-gradient(180deg, rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0.25)); + background: rgba(0, 0, 0, 0.2); border-right: 1px solid var(--border); } :root[data-theme="light"] .config-sidebar { - background: linear-gradient(180deg, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.6)); + background: rgba(0, 0, 0, 0.03); } .config-sidebar__header { @@ -36,11 +38,9 @@ } .config-sidebar__title { - font-family: var(--font-display); - font-size: 14px; font-weight: 600; - letter-spacing: 0.5px; - text-transform: uppercase; + font-size: 14px; + letter-spacing: 0.3px; } .config-sidebar__footer { @@ -53,11 +53,12 @@ .config-search { position: relative; padding: 12px; + border-bottom: 1px solid var(--border); } .config-search__icon { position: absolute; - left: 22px; + left: 24px; top: 50%; transform: translateY(-50%); width: 16px; @@ -68,22 +69,31 @@ .config-search__input { width: 100%; - padding: 10px 12px 10px 38px; + padding: 10px 32px 10px 40px; border: 1px solid var(--border); - border-radius: 10px; - background: rgba(0, 0, 0, 0.2); + border-radius: 8px; + background: rgba(0, 0, 0, 0.15); font-size: 13px; outline: none; - transition: border-color 150ms ease, box-shadow 150ms ease; + transition: border-color 150ms ease, box-shadow 150ms ease, background 150ms ease; +} + +.config-search__input::placeholder { + color: var(--muted); } .config-search__input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--focus); + background: rgba(0, 0, 0, 0.2); } :root[data-theme="light"] .config-search__input { - background: rgba(255, 255, 255, 0.9); + background: rgba(255, 255, 255, 0.8); +} + +:root[data-theme="light"] .config-search__input:focus { + background: #fff; } .config-search__clear { @@ -97,7 +107,8 @@ border-radius: 50%; background: rgba(255, 255, 255, 0.1); color: var(--muted); - font-size: 14px; + font-size: 16px; + line-height: 1; cursor: pointer; display: flex; align-items: center; @@ -120,21 +131,23 @@ .config-nav__item { display: flex; align-items: center; - gap: 10px; + gap: 12px; width: 100%; padding: 10px 12px; border: none; - border-radius: 10px; + border-radius: 8px; background: transparent; - color: var(--text); + color: var(--muted); font-size: 13px; + font-weight: 500; text-align: left; cursor: pointer; - transition: background 150ms ease, transform 100ms ease; + transition: background 150ms ease, color 150ms ease; } .config-nav__item:hover { - background: rgba(255, 255, 255, 0.06); + background: rgba(255, 255, 255, 0.05); + color: var(--text); } :root[data-theme="light"] .config-nav__item:hover { @@ -142,18 +155,24 @@ } .config-nav__item.active { - background: rgba(245, 159, 74, 0.15); + background: rgba(245, 159, 74, 0.12); color: var(--accent); } -.config-nav__item:active { - transform: scale(0.98); +.config-nav__icon { + width: 20px; + height: 20px; + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; } -.config-nav__icon { - font-size: 16px; - width: 24px; - text-align: center; +.config-nav__icon svg { + width: 18px; + height: 18px; + stroke: currentColor; + fill: none; } .config-nav__label { @@ -166,27 +185,27 @@ /* Mode Toggle */ .config-mode-toggle { display: flex; - gap: 4px; - padding: 4px; + padding: 3px; background: rgba(0, 0, 0, 0.2); - border-radius: 10px; + border-radius: 8px; + border: 1px solid var(--border); } :root[data-theme="light"] .config-mode-toggle { - background: rgba(0, 0, 0, 0.08); + background: rgba(0, 0, 0, 0.06); } .config-mode-toggle__btn { flex: 1; padding: 8px 12px; border: none; - border-radius: 8px; + border-radius: 6px; background: transparent; color: var(--muted); font-size: 12px; - font-weight: 500; + font-weight: 600; cursor: pointer; - transition: background 150ms ease, color 150ms ease; + transition: background 150ms ease, color 150ms ease, box-shadow 150ms ease; } .config-mode-toggle__btn:hover { @@ -196,15 +215,17 @@ .config-mode-toggle__btn.active { background: rgba(255, 255, 255, 0.1); color: var(--text); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); } :root[data-theme="light"] .config-mode-toggle__btn.active { - background: rgba(255, 255, 255, 0.9); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + background: #fff; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } -/* Main Content */ +/* =========================================== + Main Content + =========================================== */ .config-main { display: flex; flex-direction: column; @@ -218,13 +239,13 @@ align-items: center; justify-content: space-between; gap: 12px; - padding: 12px 16px; - background: rgba(0, 0, 0, 0.1); + padding: 12px 20px; + background: rgba(0, 0, 0, 0.08); border-bottom: 1px solid var(--border); } :root[data-theme="light"] .config-actions { - background: rgba(0, 0, 0, 0.03); + background: rgba(0, 0, 0, 0.02); } .config-actions__left, @@ -235,40 +256,37 @@ } .config-changes-badge { - padding: 4px 10px; + padding: 5px 12px; border-radius: 999px; - background: rgba(245, 159, 74, 0.2); - border: 1px solid rgba(245, 159, 74, 0.4); + background: rgba(245, 159, 74, 0.15); + border: 1px solid rgba(245, 159, 74, 0.3); color: var(--accent); font-size: 12px; - font-weight: 500; + font-weight: 600; } .config-status { - font-size: 12px; + font-size: 13px; + color: var(--muted); } /* Diff Panel */ .config-diff { - margin: 12px 16px; - border: 1px solid var(--border); - border-radius: 12px; - background: rgba(0, 0, 0, 0.15); - overflow: hidden; -} - -:root[data-theme="light"] .config-diff { + margin: 16px 20px 0; + border: 1px solid rgba(245, 159, 74, 0.3); + border-radius: 10px; background: rgba(245, 159, 74, 0.05); + overflow: hidden; } .config-diff__summary { display: flex; align-items: center; justify-content: space-between; - padding: 10px 14px; + padding: 12px 16px; cursor: pointer; font-size: 13px; - font-weight: 500; + font-weight: 600; color: var(--accent); list-style: none; } @@ -283,46 +301,53 @@ transition: transform 200ms ease; } +.config-diff__chevron svg { + width: 100%; + height: 100%; +} + .config-diff[open] .config-diff__chevron { transform: rotate(180deg); } .config-diff__content { - padding: 0 14px 14px; + padding: 0 16px 16px; display: grid; gap: 8px; } .config-diff__item { - padding: 8px 10px; - border-radius: 8px; - background: rgba(0, 0, 0, 0.15); + display: flex; + align-items: baseline; + gap: 12px; + padding: 8px 12px; + border-radius: 6px; + background: rgba(0, 0, 0, 0.1); font-size: 12px; + font-family: var(--mono); } :root[data-theme="light"] .config-diff__item { - background: rgba(255, 255, 255, 0.8); + background: rgba(255, 255, 255, 0.6); } .config-diff__path { - font-family: var(--mono); font-weight: 600; - margin-bottom: 4px; color: var(--text); + flex-shrink: 0; } .config-diff__values { display: flex; - align-items: center; + align-items: baseline; gap: 8px; - font-family: var(--mono); - color: var(--muted); + min-width: 0; + flex-wrap: wrap; } .config-diff__from { color: var(--danger); - text-decoration: line-through; - opacity: 0.7; + opacity: 0.8; } .config-diff__arrow { @@ -337,13 +362,14 @@ .config-content { flex: 1; overflow-y: auto; - padding: 16px; + padding: 20px; } .config-raw-field textarea { - min-height: 400px; + min-height: 500px; font-family: var(--mono); font-size: 13px; + line-height: 1.5; } /* Loading State */ @@ -352,14 +378,14 @@ flex-direction: column; align-items: center; justify-content: center; - gap: 12px; - padding: 60px 20px; + gap: 16px; + padding: 80px 20px; color: var(--muted); } .config-loading__spinner { - width: 32px; - height: 32px; + width: 36px; + height: 36px; border: 3px solid var(--border); border-top-color: var(--accent); border-radius: 50%; @@ -376,45 +402,46 @@ flex-direction: column; align-items: center; justify-content: center; - gap: 12px; - padding: 60px 20px; + gap: 16px; + padding: 80px 20px; text-align: center; } .config-empty__icon { - font-size: 48px; - opacity: 0.5; + font-size: 56px; + opacity: 0.4; } .config-empty__text { color: var(--muted); - font-size: 14px; + font-size: 15px; } -/* Section Cards */ +/* =========================================== + Section Cards + =========================================== */ .config-form--modern { display: grid; - gap: 16px; + gap: 24px; } .config-section-card { border: 1px solid var(--border); - border-radius: 14px; - background: linear-gradient(160deg, rgba(255, 255, 255, 0.03), transparent 70%), - rgba(0, 0, 0, 0.12); + border-radius: 12px; + background: rgba(255, 255, 255, 0.02); overflow: hidden; } :root[data-theme="light"] .config-section-card { - background: linear-gradient(160deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.7) 70%); + background: rgba(255, 255, 255, 0.5); } .config-section-card__header { display: flex; align-items: flex-start; - gap: 12px; - padding: 16px; - background: rgba(255, 255, 255, 0.02); + gap: 14px; + padding: 18px 20px; + background: rgba(0, 0, 0, 0.06); border-bottom: 1px solid var(--border); } @@ -423,9 +450,15 @@ } .config-section-card__icon { - font-size: 24px; - line-height: 1; - padding-top: 2px; + width: 32px; + height: 32px; + color: var(--accent); + flex-shrink: 0; +} + +.config-section-card__icon svg { + width: 100%; + height: 100%; } .config-section-card__titles { @@ -435,9 +468,8 @@ .config-section-card__title { margin: 0; - font-size: 16px; + font-size: 17px; font-weight: 600; - letter-spacing: 0.2px; } .config-section-card__desc { @@ -448,99 +480,312 @@ } .config-section-card__content { - padding: 16px; + padding: 20px; } -/* Toggle Switch */ -.toggle-switch { - position: relative; - display: inline-flex; - cursor: pointer; +/* =========================================== + Form Fields + =========================================== */ +.cfg-fields { + display: grid; + gap: 20px; } -.toggle-switch input { - position: absolute; - opacity: 0; - width: 0; - height: 0; +.cfg-field { + display: grid; + gap: 6px; } -.toggle-switch__track { - position: relative; - width: 44px; - height: 24px; - background: rgba(255, 255, 255, 0.15); +.cfg-field--error { + padding: 12px; + border-radius: 8px; + background: rgba(255, 92, 92, 0.1); + border: 1px solid rgba(255, 92, 92, 0.3); +} + +.cfg-field__label { + font-size: 13px; + font-weight: 600; + color: var(--text); +} + +.cfg-field__help { + font-size: 12px; + color: var(--muted); + line-height: 1.4; +} + +.cfg-field__error { + font-size: 12px; + color: var(--danger); +} + +/* Text Input */ +.cfg-input-wrap { + display: flex; + gap: 8px; +} + +.cfg-input { + flex: 1; + padding: 10px 12px; border: 1px solid var(--border); - border-radius: 999px; - transition: background 200ms ease, border-color 200ms ease; + border-radius: 8px; + background: rgba(0, 0, 0, 0.12); + font-size: 14px; + outline: none; + transition: border-color 150ms ease, box-shadow 150ms ease, background 150ms ease; } -:root[data-theme="light"] .toggle-switch__track { - background: rgba(0, 0, 0, 0.1); +.cfg-input::placeholder { + color: var(--muted); + opacity: 0.7; } -.toggle-switch__thumb { - position: absolute; - top: 2px; - left: 2px; - width: 18px; - height: 18px; - background: var(--text); - border-radius: 50%; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); - transition: transform 200ms ease, background 200ms ease; -} - -.toggle-switch input:checked + .toggle-switch__track { - background: rgba(43, 217, 127, 0.3); - border-color: rgba(43, 217, 127, 0.5); -} - -.toggle-switch input:checked + .toggle-switch__track .toggle-switch__thumb { - transform: translateX(20px); - background: var(--ok); -} - -.toggle-switch input:focus + .toggle-switch__track { +.cfg-input:focus { + border-color: var(--accent); box-shadow: 0 0 0 3px var(--focus); + background: rgba(0, 0, 0, 0.18); } -.toggle-switch input:disabled + .toggle-switch__track { +:root[data-theme="light"] .cfg-input { + background: #fff; +} + +:root[data-theme="light"] .cfg-input:focus { + background: #fff; +} + +.cfg-input--sm { + padding: 8px 10px; + font-size: 13px; +} + +.cfg-input__reset { + padding: 8px 12px; + border: 1px solid var(--border); + border-radius: 8px; + background: rgba(255, 255, 255, 0.05); + color: var(--muted); + font-size: 14px; + cursor: pointer; + transition: background 150ms ease, color 150ms ease; +} + +.cfg-input__reset:hover:not(:disabled) { + background: rgba(255, 255, 255, 0.1); + color: var(--text); +} + +.cfg-input__reset:disabled { opacity: 0.5; cursor: not-allowed; } -/* Field Row (for toggles) */ -.field-row { +/* Textarea */ +.cfg-textarea { + width: 100%; + padding: 10px 12px; + border: 1px solid var(--border); + border-radius: 8px; + background: rgba(0, 0, 0, 0.12); + font-family: var(--mono); + font-size: 13px; + line-height: 1.5; + resize: vertical; + outline: none; + transition: border-color 150ms ease, box-shadow 150ms ease; +} + +.cfg-textarea:focus { + border-color: var(--accent); + box-shadow: 0 0 0 3px var(--focus); +} + +:root[data-theme="light"] .cfg-textarea { + background: #fff; +} + +.cfg-textarea--sm { + padding: 8px 10px; + font-size: 12px; +} + +/* Number Input */ +.cfg-number { + display: inline-flex; + border: 1px solid var(--border); + border-radius: 8px; + overflow: hidden; + background: rgba(0, 0, 0, 0.12); +} + +:root[data-theme="light"] .cfg-number { + background: #fff; +} + +.cfg-number__btn { + width: 40px; + border: none; + background: rgba(255, 255, 255, 0.05); + color: var(--text); + font-size: 18px; + font-weight: 300; + cursor: pointer; + transition: background 150ms ease; +} + +.cfg-number__btn:hover:not(:disabled) { + background: rgba(255, 255, 255, 0.1); +} + +.cfg-number__btn:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +:root[data-theme="light"] .cfg-number__btn { + background: rgba(0, 0, 0, 0.03); +} + +:root[data-theme="light"] .cfg-number__btn:hover:not(:disabled) { + background: rgba(0, 0, 0, 0.06); +} + +.cfg-number__input { + width: 80px; + padding: 10px; + border: none; + border-left: 1px solid var(--border); + border-right: 1px solid var(--border); + background: transparent; + font-size: 14px; + text-align: center; + outline: none; + -moz-appearance: textfield; +} + +.cfg-number__input::-webkit-outer-spin-button, +.cfg-number__input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +/* Select */ +.cfg-select { + padding: 10px 36px 10px 12px; + border: 1px solid var(--border); + border-radius: 8px; + background-color: rgba(0, 0, 0, 0.12); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 10px center; + font-size: 14px; + cursor: pointer; + outline: none; + appearance: none; + transition: border-color 150ms ease, box-shadow 150ms ease; +} + +.cfg-select:focus { + border-color: var(--accent); + box-shadow: 0 0 0 3px var(--focus); +} + +:root[data-theme="light"] .cfg-select { + background-color: #fff; +} + +/* Segmented Control */ +.cfg-segmented { + display: inline-flex; + padding: 3px; + border: 1px solid var(--border); + border-radius: 8px; + background: rgba(0, 0, 0, 0.12); +} + +:root[data-theme="light"] .cfg-segmented { + background: rgba(0, 0, 0, 0.04); +} + +.cfg-segmented__btn { + padding: 8px 16px; + border: none; + border-radius: 6px; + background: transparent; + color: var(--muted); + font-size: 13px; + font-weight: 500; + cursor: pointer; + transition: background 150ms ease, color 150ms ease, box-shadow 150ms ease; +} + +.cfg-segmented__btn:hover:not(:disabled):not(.active) { + color: var(--text); +} + +.cfg-segmented__btn.active { + background: rgba(255, 255, 255, 0.12); + color: var(--text); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); +} + +:root[data-theme="light"] .cfg-segmented__btn.active { + background: #fff; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} + +.cfg-segmented__btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +/* Toggle Row */ +.cfg-toggle-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; - padding: 12px 0; - border-bottom: 1px solid rgba(255, 255, 255, 0.06); + padding: 14px 16px; + border: 1px solid var(--border); + border-radius: 10px; + background: rgba(0, 0, 0, 0.06); + cursor: pointer; + transition: background 150ms ease, border-color 150ms ease; } -:root[data-theme="light"] .field-row { - border-bottom-color: rgba(0, 0, 0, 0.06); +.cfg-toggle-row:hover:not(.disabled) { + background: rgba(0, 0, 0, 0.1); + border-color: var(--border-strong); } -.field-row:last-child { - border-bottom: none; +.cfg-toggle-row.disabled { + opacity: 0.6; + cursor: not-allowed; } -.field-row__info { +:root[data-theme="light"] .cfg-toggle-row { + background: rgba(255, 255, 255, 0.5); +} + +:root[data-theme="light"] .cfg-toggle-row:hover:not(.disabled) { + background: rgba(255, 255, 255, 0.8); +} + +.cfg-toggle-row__content { flex: 1; min-width: 0; } -.field-row__label { +.cfg-toggle-row__label { display: block; font-size: 14px; font-weight: 500; color: var(--text); } -.field-row__help { +.cfg-toggle-row__help { display: block; margin-top: 2px; font-size: 12px; @@ -548,89 +793,411 @@ line-height: 1.4; } -/* Pills */ -.pill--sm { +/* Toggle Switch */ +.cfg-toggle { + position: relative; + flex-shrink: 0; +} + +.cfg-toggle input { + position: absolute; + opacity: 0; + width: 0; + height: 0; +} + +.cfg-toggle__track { + display: block; + width: 48px; + height: 28px; + background: rgba(255, 255, 255, 0.12); + border: 1px solid var(--border); + border-radius: 999px; + position: relative; + transition: background 200ms ease, border-color 200ms ease; +} + +:root[data-theme="light"] .cfg-toggle__track { + background: rgba(0, 0, 0, 0.1); +} + +.cfg-toggle__track::after { + content: ""; + position: absolute; + top: 3px; + left: 3px; + width: 20px; + height: 20px; + background: var(--text); + border-radius: 50%; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); + transition: transform 200ms ease, background 200ms ease; +} + +.cfg-toggle input:checked + .cfg-toggle__track { + background: rgba(43, 217, 127, 0.25); + border-color: rgba(43, 217, 127, 0.5); +} + +.cfg-toggle input:checked + .cfg-toggle__track::after { + transform: translateX(20px); + background: var(--ok); +} + +.cfg-toggle input:focus + .cfg-toggle__track { + box-shadow: 0 0 0 3px var(--focus); +} + +/* Object (collapsible) */ +.cfg-object { + border: 1px solid var(--border); + border-radius: 10px; + background: rgba(0, 0, 0, 0.04); + overflow: hidden; +} + +:root[data-theme="light"] .cfg-object { + background: rgba(255, 255, 255, 0.4); +} + +.cfg-object__header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 12px 16px; + cursor: pointer; + list-style: none; + transition: background 150ms ease; +} + +.cfg-object__header:hover { + background: rgba(255, 255, 255, 0.03); +} + +:root[data-theme="light"] .cfg-object__header:hover { + background: rgba(0, 0, 0, 0.02); +} + +.cfg-object__header::-webkit-details-marker { + display: none; +} + +.cfg-object__title { + font-size: 14px; + font-weight: 600; + color: var(--text); +} + +.cfg-object__chevron { + width: 18px; + height: 18px; + color: var(--muted); + transition: transform 200ms ease; +} + +.cfg-object__chevron svg { + width: 100%; + height: 100%; +} + +.cfg-object[open] .cfg-object__chevron { + transform: rotate(180deg); +} + +.cfg-object__help { + padding: 0 16px 12px; + font-size: 12px; + color: var(--muted); + border-bottom: 1px solid var(--border); +} + +.cfg-object__content { + padding: 16px; + display: grid; + gap: 16px; +} + +/* Array */ +.cfg-array { + border: 1px solid var(--border); + border-radius: 10px; + overflow: hidden; +} + +.cfg-array__header { + display: flex; + align-items: center; + gap: 12px; + padding: 12px 16px; + background: rgba(0, 0, 0, 0.06); + border-bottom: 1px solid var(--border); +} + +:root[data-theme="light"] .cfg-array__header { + background: rgba(0, 0, 0, 0.02); +} + +.cfg-array__label { + flex: 1; + font-size: 14px; + font-weight: 600; + color: var(--text); +} + +.cfg-array__count { + font-size: 12px; + color: var(--muted); padding: 3px 8px; - font-size: 10px; + background: rgba(255, 255, 255, 0.06); + border-radius: 999px; +} + +:root[data-theme="light"] .cfg-array__count { + background: rgba(0, 0, 0, 0.06); +} + +.cfg-array__add { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 6px 12px; + border: 1px solid var(--border); + border-radius: 6px; + background: rgba(255, 255, 255, 0.05); + color: var(--text); + font-size: 12px; + font-weight: 500; + cursor: pointer; + transition: background 150ms ease; +} + +.cfg-array__add:hover:not(:disabled) { + background: rgba(255, 255, 255, 0.1); +} + +.cfg-array__add:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.cfg-array__add-icon { + width: 14px; + height: 14px; +} + +.cfg-array__add-icon svg { + width: 100%; + height: 100%; +} + +.cfg-array__help { + padding: 10px 16px; + font-size: 12px; + color: var(--muted); + border-bottom: 1px solid var(--border); +} + +.cfg-array__empty { + padding: 32px 16px; + text-align: center; + color: var(--muted); + font-size: 13px; +} + +.cfg-array__items { + display: grid; + gap: 1px; + background: var(--border); +} + +.cfg-array__item { + background: var(--panel); +} + +.cfg-array__item-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 16px; + background: rgba(0, 0, 0, 0.04); + border-bottom: 1px solid var(--border); +} + +:root[data-theme="light"] .cfg-array__item-header { + background: rgba(0, 0, 0, 0.02); +} + +.cfg-array__item-index { + font-size: 11px; + font-weight: 600; + color: var(--muted); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.cfg-array__item-remove { + width: 28px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; + border: none; + border-radius: 6px; + background: transparent; + color: var(--muted); + cursor: pointer; + transition: background 150ms ease, color 150ms ease; +} + +.cfg-array__item-remove svg { + width: 16px; + height: 16px; +} + +.cfg-array__item-remove:hover:not(:disabled) { + background: rgba(255, 92, 92, 0.15); + color: var(--danger); +} + +.cfg-array__item-remove:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +.cfg-array__item-content { + padding: 16px; +} + +/* Map (custom entries) */ +.cfg-map { + border: 1px solid var(--border); + border-radius: 10px; + overflow: hidden; +} + +.cfg-map__header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 12px 16px; + background: rgba(0, 0, 0, 0.06); + border-bottom: 1px solid var(--border); +} + +:root[data-theme="light"] .cfg-map__header { + background: rgba(0, 0, 0, 0.02); +} + +.cfg-map__label { + font-size: 13px; + font-weight: 600; + color: var(--muted); +} + +.cfg-map__add { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 6px 12px; + border: 1px solid var(--border); + border-radius: 6px; + background: rgba(255, 255, 255, 0.05); + color: var(--text); + font-size: 12px; + font-weight: 500; + cursor: pointer; + transition: background 150ms ease; +} + +.cfg-map__add:hover:not(:disabled) { + background: rgba(255, 255, 255, 0.1); +} + +.cfg-map__add-icon { + width: 14px; + height: 14px; +} + +.cfg-map__add-icon svg { + width: 100%; + height: 100%; +} + +.cfg-map__empty { + padding: 24px 16px; + text-align: center; + color: var(--muted); + font-size: 13px; +} + +.cfg-map__items { + display: grid; + gap: 8px; + padding: 12px; +} + +.cfg-map__item { + display: grid; + grid-template-columns: 140px 1fr auto; + gap: 8px; + align-items: start; +} + +.cfg-map__item-key { + min-width: 0; +} + +.cfg-map__item-value { + min-width: 0; +} + +.cfg-map__item-remove { + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + border: none; + border-radius: 6px; + background: transparent; + color: var(--muted); + cursor: pointer; + transition: background 150ms ease, color 150ms ease; +} + +.cfg-map__item-remove svg { + width: 16px; + height: 16px; +} + +.cfg-map__item-remove:hover:not(:disabled) { + background: rgba(255, 92, 92, 0.15); + color: var(--danger); +} + +/* Pill variants */ +.pill--sm { + padding: 4px 10px; + font-size: 11px; } .pill--ok { - border-color: rgba(43, 217, 127, 0.5); + border-color: rgba(43, 217, 127, 0.4); color: var(--ok); } .pill--danger { - border-color: rgba(255, 92, 92, 0.5); + border-color: rgba(255, 92, 92, 0.4); color: var(--danger); } -/* Improved Fieldset */ -.config-form--modern .fieldset { - border: 1px solid var(--border); - border-radius: 12px; - padding: 14px; - margin-top: 12px; - background: rgba(0, 0, 0, 0.08); -} - -:root[data-theme="light"] .config-form--modern .fieldset { - background: rgba(255, 255, 255, 0.5); -} - -.config-form--modern .fieldset > .legend { - font-weight: 600; - font-size: 13px; - color: var(--text); - margin-bottom: 12px; - padding-bottom: 10px; - border-bottom: 1px dashed var(--border); -} - -.config-form--modern .field { - margin-bottom: 12px; -} - -.config-form--modern .field:last-child { - margin-bottom: 0; -} - -.config-form--modern .field span { - font-size: 12px; - font-weight: 500; - color: var(--muted); -} - -.config-form--modern .field input, -.config-form--modern .field select, -.config-form--modern .field textarea { - font-size: 14px; -} - -/* Array improvements */ -.config-form--modern .array { - display: grid; - gap: 10px; -} - -.config-form--modern .array-item { - display: flex; - gap: 12px; - align-items: flex-start; - padding: 12px; - border: 1px solid var(--border); - border-radius: 10px; - background: rgba(0, 0, 0, 0.1); -} - -:root[data-theme="light"] .config-form--modern .array-item { - background: rgba(255, 255, 255, 0.6); -} - -/* Mobile Responsiveness */ +/* =========================================== + Mobile Responsiveness + =========================================== */ @media (max-width: 768px) { .config-layout { grid-template-columns: 1fr; - min-height: auto; } .config-sidebar { @@ -638,22 +1205,27 @@ border-bottom: 1px solid var(--border); } + .config-sidebar__header { + padding: 12px 16px; + } + .config-nav { display: flex; - flex-wrap: wrap; - gap: 6px; - padding: 12px; - max-height: none; - overflow: visible; + flex-wrap: nowrap; + gap: 4px; + padding: 8px 12px; + overflow-x: auto; + -webkit-overflow-scrolling: touch; } .config-nav__item { flex: 0 0 auto; padding: 8px 12px; + white-space: nowrap; } - .config-nav__icon { - width: auto; + .config-nav__label { + display: inline; } .config-sidebar__footer { @@ -662,47 +1234,67 @@ .config-actions { flex-wrap: wrap; + padding: 12px 16px; } - .config-actions__left { - width: 100%; - justify-content: center; - } - + .config-actions__left, .config-actions__right { width: 100%; justify-content: center; } - .config-diff__values { - flex-wrap: wrap; + .config-content { + padding: 16px; } - .field-row { - flex-direction: column; - align-items: flex-start; - gap: 10px; + .config-section-card__header { + padding: 14px 16px; } - .config-form--modern .array-item { - flex-direction: column; + .config-section-card__content { + padding: 16px; + } + + .cfg-toggle-row { + padding: 12px 14px; + } + + .cfg-map__item { + grid-template-columns: 1fr; + gap: 8px; + } + + .cfg-map__item-remove { + justify-self: end; } } @media (max-width: 480px) { + .config-nav__icon { + width: 24px; + height: 24px; + font-size: 16px; + } + .config-nav__label { display: none; } - .config-nav__item { - padding: 10px; + .config-section-card__icon { + width: 28px; + height: 28px; } - .config-section-card__header { - padding: 12px; + .config-section-card__title { + font-size: 15px; } - .config-section-card__content { - padding: 12px; + .cfg-segmented { + flex-wrap: wrap; + } + + .cfg-segmented__btn { + flex: 1 0 auto; + min-width: 60px; } } diff --git a/ui/src/ui/views/config-form.node.ts b/ui/src/ui/views/config-form.node.ts index 76a6e6195..6024c2407 100644 --- a/ui/src/ui/views/config-form.node.ts +++ b/ui/src/ui/views/config-form.node.ts @@ -26,6 +26,15 @@ function jsonValue(value: unknown): string { } } +// SVG Icons as template literals +const icons = { + chevronDown: html``, + plus: html``, + minus: html``, + trash: html``, + edit: html``, +}; + export function renderNode(params: { schema: JsonSchema; value: unknown; @@ -44,27 +53,29 @@ export function renderNode(params: { const label = hint?.label ?? schema.title ?? humanize(String(path.at(-1))); const help = hint?.help ?? schema.description; const key = pathKey(path); + const hasDefault = schema.default !== undefined; + const isDefault = hasDefault && JSON.stringify(value) === JSON.stringify(schema.default); + const isEmpty = value === undefined || value === null || value === ""; if (unsupported.has(key)) { - return html`