- Removed duplicate files (index2/3/4.html, symbols.js duplicates) - Kept index4.html as the main index.html (modular version) - Removed old text-generator.js (replaced by modular version) - Fixed ID mismatch in ui-bindings.js to match HTML - Added square and circle shape support in svg-generator.js - Added legend preview with copy functionality - Removed 580 lines of obsolete text-generator v4 code from app.js - Added addTextToLegend and addStandaloneArrowToLegend to export.js Still TODO: Split large files to comply with 300 line limit - app.js: 1219 lines - styles.css: 1319 lines - symbols.js: 870 lines 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
349 lines
15 KiB
JavaScript
349 lines
15 KiB
JavaScript
/**
|
|
* UI Bindings - Verbindet HTML-Elemente mit dem State
|
|
*/
|
|
|
|
var UiBindings = {
|
|
elements: {},
|
|
|
|
init: function() {
|
|
this.cacheElements();
|
|
this.bindEvents();
|
|
this.syncFromState();
|
|
this.updateVisibility();
|
|
this.updatePreview();
|
|
this.updateStandaloneArrowPreview();
|
|
},
|
|
|
|
cacheElements: function() {
|
|
var e = this.elements;
|
|
|
|
// Text & Farben
|
|
e.textInput = document.getElementById('customText');
|
|
e.fontSizeInput = document.getElementById('fontSize');
|
|
e.fontSizeValue = document.getElementById('fontSizeValue');
|
|
e.textColorInput = document.getElementById('textColor');
|
|
e.textColorValue = document.getElementById('textColorValue');
|
|
e.frameColorInput = document.getElementById('frameColor');
|
|
e.frameColorValue = document.getElementById('frameColorValue');
|
|
|
|
// Rahmen
|
|
e.frameScaleInput = document.getElementById('frameScale');
|
|
e.frameScaleValue = document.getElementById('frameScaleValue');
|
|
e.frameScaleRow = document.getElementById('frameScaleRow');
|
|
|
|
// Padding
|
|
e.paddingAllInput = document.getElementById('paddingAll');
|
|
e.paddingAllValue = document.getElementById('paddingAllValue');
|
|
e.paddingTopInput = document.getElementById('paddingTop');
|
|
e.paddingTopValue = document.getElementById('paddingTopValue');
|
|
e.paddingRightInput = document.getElementById('paddingRight');
|
|
e.paddingRightValue = document.getElementById('paddingRightValue');
|
|
e.paddingBottomInput = document.getElementById('paddingBottom');
|
|
e.paddingBottomValue = document.getElementById('paddingBottomValue');
|
|
e.paddingLeftInput = document.getElementById('paddingLeft');
|
|
e.paddingLeftValue = document.getElementById('paddingLeftValue');
|
|
e.paddingAllRow = document.getElementById('framePaddingAllRow');
|
|
e.paddingRow = document.getElementById('framePaddingRow');
|
|
|
|
// Pfeil
|
|
e.arrowLengthInput = document.getElementById('arrowLength');
|
|
e.arrowLengthValue = document.getElementById('arrowLengthValue');
|
|
e.arrowAngleInput = document.getElementById('arrowAngle');
|
|
e.arrowAngleValue = document.getElementById('arrowAngleValue');
|
|
e.arrowBendInput = document.getElementById('arrowBend');
|
|
e.arrowBendValue = document.getElementById('arrowBendValue');
|
|
e.arrowSizeInput = document.getElementById('arrowSize');
|
|
e.arrowSizeValue = document.getElementById('arrowSizeValue');
|
|
e.arrowTipLengthInput = document.getElementById('arrowTipLength');
|
|
e.arrowTipLengthValue = document.getElementById('arrowTipLengthValue');
|
|
e.arrowDetailsRow = document.getElementById('arrowDetailsRow');
|
|
e.arrowDetailsRow2 = document.getElementById('arrowDetailsRow2');
|
|
|
|
// Vorschau
|
|
e.textPreview = document.getElementById('textPreview');
|
|
e.standaloneArrowPreview = document.getElementById('standaloneArrowPreview');
|
|
|
|
// Buttons
|
|
e.shapeButtons = document.querySelectorAll('.shape-btn');
|
|
e.arrowButtons = document.querySelectorAll('.arrow-btn');
|
|
e.lineStyleButtons = document.querySelectorAll('.line-btn');
|
|
e.lineWeightButtons = document.querySelectorAll('.weight-btn');
|
|
},
|
|
|
|
bindEvents: function() {
|
|
var self = this;
|
|
var e = this.elements;
|
|
var state = window.TextGenState;
|
|
|
|
// Text-Input
|
|
if (e.textInput) {
|
|
e.textInput.addEventListener('input', function(ev) {
|
|
state.set('text', ev.target.value);
|
|
self.updatePreview();
|
|
});
|
|
}
|
|
|
|
// Schriftgroesse
|
|
if (e.fontSizeInput) {
|
|
e.fontSizeInput.addEventListener('input', function(ev) {
|
|
var val = parseInt(ev.target.value);
|
|
state.set('fontSize', val);
|
|
if (e.fontSizeValue) e.fontSizeValue.textContent = val + 'px';
|
|
self.updatePreview();
|
|
});
|
|
}
|
|
|
|
// Farben
|
|
if (e.textColorInput) {
|
|
e.textColorInput.addEventListener('input', function(ev) {
|
|
state.set('textColor', ev.target.value);
|
|
if (e.textColorValue) e.textColorValue.textContent = ev.target.value;
|
|
self.updatePreview();
|
|
});
|
|
}
|
|
if (e.frameColorInput) {
|
|
e.frameColorInput.addEventListener('input', function(ev) {
|
|
state.set('frameColor', ev.target.value);
|
|
if (e.frameColorValue) e.frameColorValue.textContent = ev.target.value;
|
|
self.updatePreview();
|
|
});
|
|
}
|
|
|
|
// Rahmen-Skalierung
|
|
if (e.frameScaleInput) {
|
|
e.frameScaleInput.addEventListener('input', function(ev) {
|
|
var val = parseInt(ev.target.value);
|
|
state.set('frameScale', val);
|
|
if (e.frameScaleValue) e.frameScaleValue.textContent = val + '%';
|
|
self.updatePreview();
|
|
});
|
|
}
|
|
|
|
// Gesamt-Padding
|
|
if (e.paddingAllInput) {
|
|
e.paddingAllInput.addEventListener('input', function(ev) {
|
|
var val = parseInt(ev.target.value);
|
|
state.setMultiple({
|
|
paddingTop: val,
|
|
paddingRight: val,
|
|
paddingBottom: val,
|
|
paddingLeft: val
|
|
});
|
|
if (e.paddingAllValue) e.paddingAllValue.textContent = val + 'px';
|
|
// Einzelne Slider synchronisieren
|
|
if (e.paddingTopInput) e.paddingTopInput.value = val;
|
|
if (e.paddingTopValue) e.paddingTopValue.textContent = val + 'px';
|
|
if (e.paddingRightInput) e.paddingRightInput.value = val;
|
|
if (e.paddingRightValue) e.paddingRightValue.textContent = val + 'px';
|
|
if (e.paddingBottomInput) e.paddingBottomInput.value = val;
|
|
if (e.paddingBottomValue) e.paddingBottomValue.textContent = val + 'px';
|
|
if (e.paddingLeftInput) e.paddingLeftInput.value = val;
|
|
if (e.paddingLeftValue) e.paddingLeftValue.textContent = val + 'px';
|
|
self.updatePreview();
|
|
});
|
|
}
|
|
|
|
// Einzelne Paddings
|
|
this.bindPaddingSlider('paddingTopInput', 'paddingTopValue', 'paddingTop');
|
|
this.bindPaddingSlider('paddingRightInput', 'paddingRightValue', 'paddingRight');
|
|
this.bindPaddingSlider('paddingBottomInput', 'paddingBottomValue', 'paddingBottom');
|
|
this.bindPaddingSlider('paddingLeftInput', 'paddingLeftValue', 'paddingLeft');
|
|
|
|
// Pfeil-Slider
|
|
this.bindSlider('arrowLengthInput', 'arrowLengthValue', 'arrowLength', 'px');
|
|
this.bindSlider('arrowAngleInput', 'arrowAngleValue', 'arrowAngle', '\u00B0');
|
|
this.bindSlider('arrowBendInput', 'arrowBendValue', 'arrowBend', '%');
|
|
this.bindSlider('arrowSizeInput', 'arrowSizeValue', 'arrowSize', 'px');
|
|
this.bindSlider('arrowTipLengthInput', 'arrowTipLengthValue', 'arrowTipLength', 'px');
|
|
|
|
// Shape-Buttons
|
|
e.shapeButtons.forEach(function(btn) {
|
|
btn.addEventListener('click', function() {
|
|
e.shapeButtons.forEach(function(b) { b.classList.remove('active'); });
|
|
btn.classList.add('active');
|
|
state.set('shape', btn.dataset.shape);
|
|
self.updateVisibility();
|
|
self.updatePreview();
|
|
});
|
|
});
|
|
|
|
// Arrow-Buttons
|
|
e.arrowButtons.forEach(function(btn) {
|
|
btn.addEventListener('click', function() {
|
|
e.arrowButtons.forEach(function(b) { b.classList.remove('active'); });
|
|
btn.classList.add('active');
|
|
state.set('arrow', btn.dataset.arrow);
|
|
self.updateVisibility();
|
|
self.updatePreview();
|
|
self.updateStandaloneArrowPreview();
|
|
});
|
|
});
|
|
|
|
// Line-Style-Buttons
|
|
e.lineStyleButtons.forEach(function(btn) {
|
|
btn.addEventListener('click', function() {
|
|
e.lineStyleButtons.forEach(function(b) { b.classList.remove('active'); });
|
|
btn.classList.add('active');
|
|
state.set('lineStyle', btn.dataset.style);
|
|
self.updatePreview();
|
|
});
|
|
});
|
|
|
|
// Line-Weight-Buttons
|
|
e.lineWeightButtons.forEach(function(btn) {
|
|
btn.addEventListener('click', function() {
|
|
e.lineWeightButtons.forEach(function(b) { b.classList.remove('active'); });
|
|
btn.classList.add('active');
|
|
state.set('lineWeight', parseInt(btn.dataset.weight));
|
|
self.updatePreview();
|
|
});
|
|
});
|
|
},
|
|
|
|
bindSlider: function(inputKey, valueKey, stateKey, unit) {
|
|
var self = this;
|
|
var input = this.elements[inputKey];
|
|
var valueEl = this.elements[valueKey];
|
|
var state = window.TextGenState;
|
|
|
|
if (input) {
|
|
input.addEventListener('input', function(ev) {
|
|
var val = parseInt(ev.target.value);
|
|
state.set(stateKey, val);
|
|
if (valueEl) valueEl.textContent = val + unit;
|
|
self.updatePreview();
|
|
if (stateKey.indexOf('arrow') === 0) {
|
|
self.updateStandaloneArrowPreview();
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
bindPaddingSlider: function(inputKey, valueKey, stateKey) {
|
|
var self = this;
|
|
var input = this.elements[inputKey];
|
|
var valueEl = this.elements[valueKey];
|
|
var state = window.TextGenState;
|
|
|
|
if (input) {
|
|
input.addEventListener('input', function(ev) {
|
|
var val = parseInt(ev.target.value);
|
|
state.set(stateKey, val);
|
|
if (valueEl) valueEl.textContent = val + 'px';
|
|
self.updatePreview();
|
|
});
|
|
}
|
|
},
|
|
|
|
syncFromState: function() {
|
|
var e = this.elements;
|
|
var s = window.TextGenState.current;
|
|
|
|
if (e.textInput) e.textInput.value = s.text;
|
|
if (e.fontSizeInput) e.fontSizeInput.value = s.fontSize;
|
|
if (e.fontSizeValue) e.fontSizeValue.textContent = s.fontSize + 'px';
|
|
if (e.textColorInput) e.textColorInput.value = s.textColor;
|
|
if (e.frameColorInput) e.frameColorInput.value = s.frameColor;
|
|
if (e.frameScaleInput) e.frameScaleInput.value = s.frameScale;
|
|
if (e.frameScaleValue) e.frameScaleValue.textContent = s.frameScale + '%';
|
|
|
|
// Padding
|
|
if (e.paddingAllInput) e.paddingAllInput.value = s.paddingTop;
|
|
if (e.paddingAllValue) e.paddingAllValue.textContent = s.paddingTop + 'px';
|
|
if (e.paddingTopInput) e.paddingTopInput.value = s.paddingTop;
|
|
if (e.paddingTopValue) e.paddingTopValue.textContent = s.paddingTop + 'px';
|
|
if (e.paddingRightInput) e.paddingRightInput.value = s.paddingRight;
|
|
if (e.paddingRightValue) e.paddingRightValue.textContent = s.paddingRight + 'px';
|
|
if (e.paddingBottomInput) e.paddingBottomInput.value = s.paddingBottom;
|
|
if (e.paddingBottomValue) e.paddingBottomValue.textContent = s.paddingBottom + 'px';
|
|
if (e.paddingLeftInput) e.paddingLeftInput.value = s.paddingLeft;
|
|
if (e.paddingLeftValue) e.paddingLeftValue.textContent = s.paddingLeft + 'px';
|
|
|
|
// Pfeil
|
|
if (e.arrowLengthInput) e.arrowLengthInput.value = s.arrowLength;
|
|
if (e.arrowLengthValue) e.arrowLengthValue.textContent = s.arrowLength + 'px';
|
|
if (e.arrowAngleInput) e.arrowAngleInput.value = s.arrowAngle;
|
|
if (e.arrowAngleValue) e.arrowAngleValue.textContent = s.arrowAngle + '\u00B0';
|
|
if (e.arrowBendInput) e.arrowBendInput.value = s.arrowBend;
|
|
if (e.arrowBendValue) e.arrowBendValue.textContent = s.arrowBend + '%';
|
|
if (e.arrowSizeInput) e.arrowSizeInput.value = s.arrowSize;
|
|
if (e.arrowSizeValue) e.arrowSizeValue.textContent = s.arrowSize + 'px';
|
|
if (e.arrowTipLengthInput) e.arrowTipLengthInput.value = s.arrowTipLength;
|
|
if (e.arrowTipLengthValue) e.arrowTipLengthValue.textContent = s.arrowTipLength + 'px';
|
|
|
|
// Buttons aktivieren
|
|
this.activateButton(e.shapeButtons, 'shape', s.shape);
|
|
this.activateButton(e.arrowButtons, 'arrow', s.arrow);
|
|
this.activateButton(e.lineStyleButtons, 'style', s.lineStyle);
|
|
this.activateButtonByValue(e.lineWeightButtons, 'weight', s.lineWeight);
|
|
},
|
|
|
|
activateButton: function(buttons, dataAttr, value) {
|
|
buttons.forEach(function(btn) {
|
|
btn.classList.remove('active');
|
|
if (btn.dataset[dataAttr] === value) {
|
|
btn.classList.add('active');
|
|
}
|
|
});
|
|
},
|
|
|
|
activateButtonByValue: function(buttons, dataAttr, value) {
|
|
buttons.forEach(function(btn) {
|
|
btn.classList.remove('active');
|
|
if (parseInt(btn.dataset[dataAttr]) === value) {
|
|
btn.classList.add('active');
|
|
}
|
|
});
|
|
},
|
|
|
|
updateVisibility: function() {
|
|
var e = this.elements;
|
|
var s = window.TextGenState.current;
|
|
var hasShape = s.shape !== 'none';
|
|
var hasArrow = s.arrow !== 'none';
|
|
|
|
if (e.frameScaleRow) e.frameScaleRow.style.display = hasShape ? 'flex' : 'none';
|
|
if (e.paddingAllRow) e.paddingAllRow.style.display = hasShape ? 'flex' : 'none';
|
|
if (e.paddingRow) e.paddingRow.style.display = hasShape ? 'flex' : 'none';
|
|
if (e.arrowDetailsRow) e.arrowDetailsRow.style.display = hasArrow ? 'flex' : 'none';
|
|
if (e.arrowDetailsRow2) e.arrowDetailsRow2.style.display = hasArrow ? 'flex' : 'none';
|
|
},
|
|
|
|
updatePreview: function() {
|
|
var e = this.elements;
|
|
if (e.textPreview && window.SvgGenerator) {
|
|
var svg = window.SvgGenerator.generate(window.TextGenState.current);
|
|
e.textPreview.innerHTML = svg;
|
|
}
|
|
},
|
|
|
|
updateStandaloneArrowPreview: function() {
|
|
var e = this.elements;
|
|
var s = window.TextGenState.current;
|
|
|
|
if (!e.standaloneArrowPreview) return;
|
|
|
|
if (s.arrow === 'none') {
|
|
e.standaloneArrowPreview.innerHTML = '<p style="color: #9ca3af; font-size: 0.9rem;">Waehle einen Pfeil aus</p>';
|
|
return;
|
|
}
|
|
|
|
if (window.SvgGenerator) {
|
|
var svg = window.SvgGenerator.generateArrowOnly(s);
|
|
if (svg) {
|
|
e.standaloneArrowPreview.innerHTML = svg;
|
|
}
|
|
}
|
|
},
|
|
|
|
resetToDefaults: function() {
|
|
window.TextGenState.reset();
|
|
this.syncFromState();
|
|
this.updateVisibility();
|
|
this.updatePreview();
|
|
this.updateStandaloneArrowPreview();
|
|
}
|
|
};
|
|
|
|
window.UiBindings = UiBindings;
|