diff --git a/index.html b/index.html index 05abcb3..ded89dc 100644 --- a/index.html +++ b/index.html @@ -37,10 +37,34 @@
-

Основное поле

-
- - +
+

Основное поле

+ +
+
+ +
+ + +
+
+
+ +
+ + +
diff --git a/script.js b/script.js index 04cef53..38470a2 100644 --- a/script.js +++ b/script.js @@ -286,14 +286,103 @@ $('cssOutput').value = toMatrix3dCSS(H); } - // ===== Input events ===== - $('inpFieldW').addEventListener('input', () => { - const v = parseInt($('inpFieldW').value); - if (v > 0) { state.fieldW = v; updateAll(); } + // ===== Field editing ===== + let fieldEditing = false; + let fieldEditW = state.fieldW; + let fieldEditH = state.fieldH; + let keepAspect = true; + + function updateChainIcon() { + const locked = $('chainLink').querySelectorAll('.chain-locked'); + const unlocked = $('chainLink').querySelectorAll('.chain-unlocked'); + locked.forEach(el => el.style.display = keepAspect ? '' : 'none'); + unlocked.forEach(el => el.style.display = keepAspect ? 'none' : ''); + $('chainLink').classList.toggle('unlocked', !keepAspect); + } + + function setFieldEditing(editing) { + fieldEditing = editing; + const inpW = $('inpFieldW'); + const inpH = $('inpFieldH'); + const options = $('fieldEditOptions'); + const btnEdit = $('btnEditField'); + const chain = $('chainLink'); + + if (editing) { + fieldEditW = state.fieldW; + fieldEditH = state.fieldH; + inpW.disabled = false; + inpH.disabled = false; + options.classList.add('visible'); + btnEdit.style.display = 'none'; + chain.classList.add('visible'); + updateChainIcon(); + } else { + inpW.value = state.fieldW; + inpW.disabled = true; + inpH.value = state.fieldH; + inpH.disabled = true; + options.classList.remove('visible'); + btnEdit.style.display = ''; + chain.classList.remove('visible'); + } + } + + $('chainLink').addEventListener('click', () => { + keepAspect = !keepAspect; + updateChainIcon(); }); + + $('btnEditField').addEventListener('click', () => { + setFieldEditing(true); + $('inpFieldW').focus(); + }); + + $('btnCancelField').addEventListener('click', () => { + setFieldEditing(false); + }); + + $('inpFieldW').addEventListener('input', () => { + if (!fieldEditing) return; + const newW = parseInt($('inpFieldW').value); + if (newW <= 0) return; + if (keepAspect) { + fieldEditH = Math.round(newW * state.fieldH / state.fieldW); + $('inpFieldH').value = fieldEditH; + } + fieldEditW = newW; + }); + $('inpFieldH').addEventListener('input', () => { - const v = parseInt($('inpFieldH').value); - if (v > 0) { state.fieldH = v; updateAll(); } + if (!fieldEditing) return; + const newH = parseInt($('inpFieldH').value); + if (newH <= 0) return; + if (keepAspect) { + fieldEditW = Math.round(newH * state.fieldW / state.fieldH); + $('inpFieldW').value = fieldEditW; + } + fieldEditH = newH; + }); + + $('btnSaveField').addEventListener('click', () => { + const newW = parseInt($('inpFieldW').value); + const newH = parseInt($('inpFieldH').value); + if (newW <= 0 || newH <= 0) return; + + if ($('chkRescaleCoords').checked && (newW !== state.fieldW || newH !== state.fieldH)) { + const sx = newW / state.fieldW; + const sy = newH / state.fieldH; + state.corners.forEach(c => { + c.x = Math.round(c.x * sx); + c.y = Math.round(c.y * sy); + }); + } + + state.fieldW = newW; + state.fieldH = newH; + setFieldEditing(false); + buildCornerInputs(); + updateAll(); }); $('inpWidgetW').addEventListener('input', () => { const v = parseInt($('inpWidgetW').value); @@ -324,6 +413,7 @@ // ===== Reset ===== $('resetBtn').addEventListener('click', () => { + setFieldEditing(false); state.fieldW = defaultState.fieldW; state.fieldH = defaultState.fieldH; state.widgetW = defaultState.widgetW; diff --git a/style.css b/style.css index 0520aa9..dfae87b 100644 --- a/style.css +++ b/style.css @@ -107,6 +107,16 @@ main { margin-bottom: 12px; } +.panel-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 12px; +} +.panel-header h2 { + margin-bottom: 0; +} + .left-col { display: flex; flex-direction: column; @@ -275,6 +285,145 @@ main { background: #484f58; } +.btn-edit-field { + padding: 4px 12px; + border: 1px solid var(--accent); + border-radius: 4px; + background: transparent; + color: var(--accent); + font-size: 12px; + font-weight: 600; + cursor: pointer; + transition: background 0.15s, color 0.15s; +} +.btn-edit-field:hover { + background: rgba(88, 166, 255, 0.1); +} + +.btn-save-field { + padding: 4px 12px; + border: none; + border-radius: 4px; + background: var(--btn-bg); + color: white; + font-size: 12px; + font-weight: 600; + cursor: pointer; + transition: background 0.15s; +} +.btn-save-field:hover { + background: var(--btn-hover); +} + +.btn-cancel-field { + padding: 4px 12px; + border: 1px solid var(--border); + border-radius: 4px; + background: transparent; + color: var(--text); + font-size: 12px; + font-weight: 600; + cursor: pointer; + transition: background 0.15s; +} +.btn-cancel-field:hover { + background: var(--border); +} + +.field-size-stack { + display: flex; + align-items: stretch; + gap: 8px; +} + +.chain-link { + display: none; + align-items: center; + justify-content: center; + width: 32px; + min-height: 56px; + border: 1px solid var(--border); + border-radius: 4px; + background: var(--input-bg); + color: var(--accent); + cursor: pointer; + flex-shrink: 0; + transition: background 0.15s, color 0.15s; +} +.chain-link:hover { + background: rgba(88, 166, 255, 0.1); +} +.chain-link.unlocked { + color: #8b949e; +} +.chain-link.visible { + display: flex; +} + +.field-stack-inputs { + display: flex; + flex-direction: column; + gap: 6px; + flex: 1; +} +.field-stack-inputs label { + display: flex; + align-items: center; + gap: 6px; + font-size: 13px; + color: #8b949e; +} +.field-stack-inputs label span { + min-width: 14px; +} +.field-stack-inputs input { + width: 100%; + padding: 6px 8px; + background: var(--input-bg); + border: 1px solid var(--border); + border-radius: 4px; + color: var(--heading); + font-size: 14px; + font-family: monospace; + outline: none; +} +.field-stack-inputs input:focus { + border-color: var(--accent); +} +.field-stack-inputs input:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.field-edit-options { + display: none; + margin-top: 10px; + flex-direction: column; + gap: 8px; +} +.field-edit-options.visible { + display: flex; +} + +.field-save-row { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 8px; +} + +.checkbox-label { + display: flex; + align-items: center; + gap: 6px; + font-size: 12px; + color: #8b949e; + cursor: pointer; +} +.checkbox-label input[type="checkbox"] { + accent-color: var(--accent); +} + #fieldContainer { width: 100%; overflow: hidden;