feat(dev): add spacing base step control to theme adapter panel
Adds a "Spacing" section with a Base slider (0.10–0.50 rem) that live-updates all --size-1 through --size-16 CSS variables. The value persists in localStorage, resets with the Reset button, and is included in the Copy EDN output.
This commit is contained in:
@@ -45,9 +45,13 @@
|
||||
{ name: 'Emerald', grayHue: 165, graySat: 0.5, accentHue: 165, accentSat: 0.75 },
|
||||
];
|
||||
|
||||
// ── Spacing scale ───────────────────────────────────────────────
|
||||
var SIZE_STEPS = 16; // --size-1 through --size-16
|
||||
var DEFAULT_SIZE_BASE = 0.25; // rem
|
||||
|
||||
// ── State ──────────────────────────────────────────────────────
|
||||
var STORAGE_KEY = 'ui-fw-theme-adapter-v2';
|
||||
var DEFAULT = { grayHue: 285, graySat: 1.0, accentHue: 286, accentSat: 1.0, open: false };
|
||||
var DEFAULT = { grayHue: 285, graySat: 1.0, accentHue: 286, accentSat: 1.0, sizeBase: DEFAULT_SIZE_BASE, open: false };
|
||||
var state = assign({}, DEFAULT);
|
||||
try {
|
||||
var saved = JSON.parse(localStorage.getItem(STORAGE_KEY));
|
||||
@@ -76,9 +80,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
function applySpacing() {
|
||||
var root = document.documentElement.style;
|
||||
for (var n = 1; n <= SIZE_STEPS; n++) {
|
||||
var val = (state.sizeBase * n);
|
||||
// Format: strip trailing zeros, max 3 decimal places
|
||||
var s = val.toFixed(3).replace(/0+$/, '').replace(/\.$/, '');
|
||||
root.setProperty('--size-' + n, s + 'rem');
|
||||
}
|
||||
}
|
||||
|
||||
function apply() {
|
||||
applyScale('gray', state.grayHue, GRAY_STEPS, state.graySat);
|
||||
applyScale('accent', state.accentHue, ACCENT_STEPS, state.accentSat);
|
||||
applySpacing();
|
||||
save();
|
||||
updateUI();
|
||||
}
|
||||
@@ -88,6 +103,7 @@
|
||||
var root = document.documentElement.style;
|
||||
GRAY_STEPS.forEach(function(s) { root.removeProperty('--gray-' + s[0]); });
|
||||
ACCENT_STEPS.forEach(function(s) { root.removeProperty('--accent-' + s[0]); });
|
||||
for (var n = 1; n <= SIZE_STEPS; n++) { root.removeProperty('--size-' + n); }
|
||||
save();
|
||||
updateUI();
|
||||
}
|
||||
@@ -102,11 +118,14 @@
|
||||
}
|
||||
var grayChroma = Math.min(0.4, 0.025 * state.graySat);
|
||||
var accentChroma = Math.min(0.4, 0.23 * state.accentSat);
|
||||
return ':color\n' +
|
||||
var sizeBase = state.sizeBase.toFixed(3).replace(/0+$/, '').replace(/\.$/, '');
|
||||
return ':scales\n' +
|
||||
' {:size {:base ' + sizeBase + ' :unit "rem" :steps ' + SIZE_STEPS + '}\n\n' +
|
||||
' :color\n' +
|
||||
' {:gray {:hue ' + state.grayHue + ' :chroma ' + grayChroma.toFixed(3) + '\n' +
|
||||
' :steps [' + fmtSteps(GRAY_STEPS, state.graySat).trimStart() + ']}\n\n' +
|
||||
' :accent {:hue ' + state.accentHue + ' :chroma ' + accentChroma.toFixed(2) + '\n' +
|
||||
' :steps [' + fmtSteps(ACCENT_STEPS, state.accentSat).trimStart() + ']}}';
|
||||
' :steps [' + fmtSteps(ACCENT_STEPS, state.accentSat).trimStart() + ']}}}';
|
||||
}
|
||||
|
||||
// ── DOM helpers ────────────────────────────────────────────────
|
||||
@@ -234,9 +253,15 @@
|
||||
swatchAccent = accentSwatches.items;
|
||||
accentSection.appendChild(accentSwatches.row);
|
||||
|
||||
// Spacing section
|
||||
var spacingSection = el('div', 'vstack gap-2');
|
||||
spacingSection.appendChild(el('div', 'text-xs text-faint uppercase tracking-wide font-semibold', 'Spacing'));
|
||||
spacingSection.appendChild(makeSlider('sizeBase', 'Base', 10, 50, 1));
|
||||
|
||||
body.appendChild(presetRow);
|
||||
body.appendChild(graySection);
|
||||
body.appendChild(accentSection);
|
||||
body.appendChild(spacingSection);
|
||||
|
||||
// ─ Footer section ─
|
||||
var footer = el('div', 'card-section');
|
||||
@@ -271,6 +296,9 @@
|
||||
inputs.accentSat.input.addEventListener('input', function(e) {
|
||||
state.accentSat = parseInt(e.target.value) / 100; apply();
|
||||
});
|
||||
inputs.sizeBase.input.addEventListener('input', function(e) {
|
||||
state.sizeBase = parseInt(e.target.value) / 100; apply();
|
||||
});
|
||||
}
|
||||
|
||||
// ── Update UI ─────────────────────────────────────────────────
|
||||
@@ -293,6 +321,10 @@
|
||||
inputs.accentSat.value.textContent = Math.round(state.accentSat * 100) + '%';
|
||||
inputs.accentSat.input.style.background = chromaGradient(state.accentHue);
|
||||
|
||||
// Sync spacing slider
|
||||
inputs.sizeBase.input.value = Math.round(state.sizeBase * 100);
|
||||
inputs.sizeBase.value.textContent = state.sizeBase.toFixed(2);
|
||||
|
||||
// Preset active states — uses .chip / .chip-active
|
||||
presetBtns.forEach(function(item) {
|
||||
var p = item.preset;
|
||||
@@ -320,7 +352,8 @@
|
||||
function init() {
|
||||
buildPanel();
|
||||
if (state.grayHue !== DEFAULT.grayHue || state.graySat !== DEFAULT.graySat ||
|
||||
state.accentHue !== DEFAULT.accentHue || state.accentSat !== DEFAULT.accentSat) {
|
||||
state.accentHue !== DEFAULT.accentHue || state.accentSat !== DEFAULT.accentSat ||
|
||||
state.sizeBase !== DEFAULT.sizeBase) {
|
||||
apply();
|
||||
} else {
|
||||
updateUI();
|
||||
|
||||
Reference in New Issue
Block a user