Loading editor/html/css/editor.css +143 −0 Changes for editor/html/css/editor.css: 143 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -1162,3 +1162,146 @@ dialog label { .media-browse-field button { white-space: nowrap; } /* Color Var / Custom Picker */ .color-mode-toggle { display: flex; border: 1px solid var(--border); border-radius: 3px; overflow: hidden; margin-bottom: 4px; } .color-mode-btn { flex: 1; padding: 3px 6px; background: var(--bg-tertiary); color: var(--text-secondary); border: none; cursor: pointer; font-size: 11px; font-weight: 500; font-family: inherit; transition: background 0.15s, color 0.15s; } .color-mode-btn:hover { background: var(--bg-hover); color: var(--text-primary); } .color-mode-btn.active { background: var(--accent); color: var(--bg-primary); } .color-var-panel { display: flex; flex-direction: column; gap: 4px; } .color-var-select { width: 100%; padding: 5px 8px; background: var(--bg-tertiary); color: var(--text-primary); border: 1px solid var(--border); border-radius: 3px; font-size: 12px; font-family: inherit; } .color-var-manual { width: 100%; padding: 5px 8px; background: var(--bg-tertiary); color: var(--text-primary); border: 1px solid var(--border); border-radius: 3px; font-size: 11px; font-family: monospace; box-sizing: border-box; } .color-var-manual:focus, .color-var-select:focus { outline: none; border-color: var(--accent); } .color-custom-panel { display: flex; flex-direction: column; gap: 4px; } .color-custom-row { display: flex; gap: 6px; align-items: center; } .color-hex-input { width: 36px; height: 28px; padding: 1px 2px; border: 1px solid var(--border); border-radius: 3px; cursor: pointer; background: none; flex-shrink: 0; } .color-alpha-wrap { flex: 1; display: flex; align-items: center; gap: 5px; } .color-alpha-input { flex: 1; cursor: pointer; accent-color: var(--accent); height: 4px; } .color-alpha-label { font-size: 11px; color: var(--text-muted); min-width: 32px; text-align: right; } .color-preview-swatch { width: 28px; height: 28px; border-radius: 3px; border: 1px solid var(--border); flex-shrink: 0; position: relative; overflow: hidden; background-color: #fff; background-image: linear-gradient(45deg, #bbb 25%, transparent 25%), linear-gradient(-45deg, #bbb 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #bbb 75%), linear-gradient(-45deg, transparent 75%, #bbb 75%); background-size: 8px 8px; background-position: 0 0, 0 4px, 4px -4px, -4px 0px; } .color-preview-swatch-inner { position: absolute; inset: 0; border-radius: 2px; } .color-preview-value { font-size: 10px; color: var(--text-muted); font-family: monospace; word-break: break-all; line-height: 1.3; } editor/html/js/properties.js +170 −5 Changes for editor/html/js/properties.js: 170 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -157,6 +157,173 @@ var PropertiesPanel = (function() { container.appendChild(form); } var BLOGI_THEME_VARS = [ { label: '-- Theme-Variable wählen --', value: '' }, { label: '--blogi-accent', value: 'var(--blogi-accent)' }, { label: '--blogi-accent-dark', value: 'var(--blogi-accent-dark)' }, { label: '--blogi-text', value: 'var(--blogi-text)' }, { label: '--blogi-text-muted', value: 'var(--blogi-text-muted)' }, { label: '--blogi-bg', value: 'var(--blogi-bg)' }, { label: '--blogi-bg-alt', value: 'var(--blogi-bg-alt)' }, { label: '--blogi-surface', value: 'var(--blogi-surface)' }, { label: '--blogi-border', value: 'var(--blogi-border)' }, { label: '--blogi-error', value: 'var(--blogi-error)' }, { label: '--blogi-nav-active', value: 'var(--blogi-nav-active)' }, { label: 'transparent', value: 'transparent' } ]; function _parseRgba(v) { if (!v) return { hex: '#000000', alpha: 100 }; var m = v.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d.]+))?\s*\)/); if (m) { var r = parseInt(m[1]), g = parseInt(m[2]), b = parseInt(m[3]); var a = m[4] !== undefined ? Math.round(parseFloat(m[4]) * 100) : 100; return { hex: '#' + ('0'+r.toString(16)).slice(-2) + ('0'+g.toString(16)).slice(-2) + ('0'+b.toString(16)).slice(-2), alpha: Math.max(0, Math.min(100, a)) }; } if (/^#[0-9a-fA-F]{6}/.test(v)) return { hex: v.slice(0, 7), alpha: 100 }; if (/^#[0-9a-fA-F]{3}$/.test(v)) { var c = v.slice(1); return { hex: '#'+c[0]+c[0]+c[1]+c[1]+c[2]+c[2], alpha: 100 }; } return { hex: '#000000', alpha: 100 }; } function _hexAlphaToString(hex, alpha) { var r = parseInt(hex.slice(1,3), 16), g = parseInt(hex.slice(3,5), 16), b = parseInt(hex.slice(5,7), 16); if (alpha >= 100) return 'rgb(' + r + ', ' + g + ', ' + b + ')'; return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + (alpha / 100).toFixed(2) + ')'; } function _renderColorField(group, field, value) { var isVarMode = !value || value.indexOf('var(') === 0 || value.slice(0,2) === '--' || value === 'transparent'; var mode = isVarMode ? 'var' : 'custom'; var parsed = _parseRgba(value); var hiddenInput = document.createElement('input'); hiddenInput.type = 'hidden'; hiddenInput.name = field.key; hiddenInput.value = value || ''; var toggle = document.createElement('div'); toggle.className = 'color-mode-toggle'; var varBtn = document.createElement('button'); varBtn.type = 'button'; varBtn.className = 'color-mode-btn' + (mode === 'var' ? ' active' : ''); varBtn.textContent = 'Theme Var'; var customBtn = document.createElement('button'); customBtn.type = 'button'; customBtn.className = 'color-mode-btn' + (mode === 'custom' ? ' active' : ''); customBtn.textContent = 'Custom'; toggle.appendChild(varBtn); toggle.appendChild(customBtn); // --- Var panel --- var varPanel = document.createElement('div'); varPanel.className = 'color-var-panel'; varPanel.style.display = mode === 'var' ? '' : 'none'; var varSelect = document.createElement('select'); varSelect.className = 'color-var-select'; var inPredefined = false; for (var vi = 0; vi < BLOGI_THEME_VARS.length; vi++) { var tvOpt = document.createElement('option'); tvOpt.value = BLOGI_THEME_VARS[vi].value; tvOpt.textContent = BLOGI_THEME_VARS[vi].label; if (value && value === BLOGI_THEME_VARS[vi].value) { tvOpt.selected = true; inPredefined = true; } varSelect.appendChild(tvOpt); } varPanel.appendChild(varSelect); var varManual = document.createElement('input'); varManual.type = 'text'; varManual.className = 'color-var-manual'; varManual.placeholder = 'var(--eigene-variable)'; if (isVarMode && !inPredefined && value) varManual.value = value; varPanel.appendChild(varManual); // --- Custom panel --- var customPanel = document.createElement('div'); customPanel.className = 'color-custom-panel'; customPanel.style.display = mode === 'custom' ? '' : 'none'; var customRow = document.createElement('div'); customRow.className = 'color-custom-row'; var hexInput = document.createElement('input'); hexInput.type = 'color'; hexInput.className = 'color-hex-input'; hexInput.value = parsed.hex; var alphaWrap = document.createElement('div'); alphaWrap.className = 'color-alpha-wrap'; var alphaInput = document.createElement('input'); alphaInput.type = 'range'; alphaInput.className = 'color-alpha-input'; alphaInput.min = '0'; alphaInput.max = '100'; alphaInput.value = String(parsed.alpha); var alphaLabel = document.createElement('span'); alphaLabel.className = 'color-alpha-label'; alphaLabel.textContent = parsed.alpha + '%'; alphaWrap.appendChild(alphaInput); alphaWrap.appendChild(alphaLabel); var swatch = document.createElement('div'); swatch.className = 'color-preview-swatch'; var swatchInner = document.createElement('div'); swatchInner.className = 'color-preview-swatch-inner'; swatchInner.style.background = (!isVarMode && value) ? value : _hexAlphaToString(parsed.hex, parsed.alpha); swatch.appendChild(swatchInner); customRow.appendChild(hexInput); customRow.appendChild(alphaWrap); customRow.appendChild(swatch); customPanel.appendChild(customRow); var previewVal = document.createElement('div'); previewVal.className = 'color-preview-value'; previewVal.textContent = value || ''; customPanel.appendChild(previewVal); function updateValue() { var newVal; if (mode === 'var') { newVal = varSelect.value || varManual.value.trim() || ''; } else { newVal = _hexAlphaToString(hexInput.value, parseInt(alphaInput.value, 10)); } hiddenInput.value = newVal; previewVal.textContent = newVal; alphaLabel.textContent = alphaInput.value + '%'; try { swatchInner.style.background = newVal; } catch(e) {} hiddenInput.dispatchEvent(new Event('change', { bubbles: true })); } function switchMode(newMode) { mode = newMode; varBtn.classList.toggle('active', mode === 'var'); customBtn.classList.toggle('active', mode === 'custom'); varPanel.style.display = mode === 'var' ? '' : 'none'; customPanel.style.display = mode === 'custom' ? '' : 'none'; updateValue(); } varBtn.addEventListener('click', function() { switchMode('var'); }); customBtn.addEventListener('click', function() { switchMode('custom'); }); varSelect.addEventListener('change', function() { varManual.value = ''; updateValue(); }); varManual.addEventListener('input', function() { if (varManual.value.trim()) varSelect.value = ''; updateValue(); }); hexInput.addEventListener('input', updateValue); alphaInput.addEventListener('input', updateValue); group.appendChild(hiddenInput); group.appendChild(toggle); group.appendChild(varPanel); group.appendChild(customPanel); } function _renderFieldsInto(panel, fields, properties, form) { for (var i = 0; i < fields.length; i++) { var field = fields[i]; Loading Loading @@ -196,11 +363,9 @@ var PropertiesPanel = (function() { input.appendChild(opt); } } else if (field.type === 'color' || field.type === 'color_var') { input = document.createElement('input'); input.type = 'text'; input.name = field.key; input.value = value; input.placeholder = field.placeholder || '#000000 oder var(--name)'; _renderColorField(group, field, value); panel.appendChild(group); continue; } else if (field.type === 'html' || field.type === 'richtext') { var rteWrap = document.createElement('div'); rteWrap.className = 'rte-wrap'; Loading editor/widgets/popup/popup.cpp +18 −0 Changes for editor/widgets/popup/popup.cpp: 18 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -625,6 +625,24 @@ extern "C" { mediaCSS += " }"; } // Mobile + Light mode overrides std::string mobileLightBtnCSS; if (validCss(ml_buttonBgColor)) mobileLightBtnCSS += " background-color: " + ml_buttonBgColor + " !important;"; if (validCss(ml_buttonTextColor)) mobileLightBtnCSS += " color: " + ml_buttonTextColor + " !important;"; std::string mobileLightPopupCSS; if (validCss(ml_popupBgColor)) mobileLightPopupCSS += " background: " + ml_popupBgColor + " !important;"; if (validCss(ml_popupTextColor)) mobileLightPopupCSS += " color: " + ml_popupTextColor + " !important;"; if (!mobileLightBtnCSS.empty() || !mobileLightPopupCSS.empty()) { mediaCSS += "@media (max-width: 768px) and (prefers-color-scheme: light) {"; if (!mobileLightBtnCSS.empty()) mediaCSS += " ." + responsiveClass + "-btn {" + mobileLightBtnCSS + " }"; if (!mobileLightPopupCSS.empty()) mediaCSS += " ." + responsiveClass + "-dialog {" + mobileLightPopupCSS + " }"; mediaCSS += " }"; } // Escape key listener mediaCSS += " "; // spacer before script Loading Loading
editor/html/css/editor.css +143 −0 Changes for editor/html/css/editor.css: 143 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -1162,3 +1162,146 @@ dialog label { .media-browse-field button { white-space: nowrap; } /* Color Var / Custom Picker */ .color-mode-toggle { display: flex; border: 1px solid var(--border); border-radius: 3px; overflow: hidden; margin-bottom: 4px; } .color-mode-btn { flex: 1; padding: 3px 6px; background: var(--bg-tertiary); color: var(--text-secondary); border: none; cursor: pointer; font-size: 11px; font-weight: 500; font-family: inherit; transition: background 0.15s, color 0.15s; } .color-mode-btn:hover { background: var(--bg-hover); color: var(--text-primary); } .color-mode-btn.active { background: var(--accent); color: var(--bg-primary); } .color-var-panel { display: flex; flex-direction: column; gap: 4px; } .color-var-select { width: 100%; padding: 5px 8px; background: var(--bg-tertiary); color: var(--text-primary); border: 1px solid var(--border); border-radius: 3px; font-size: 12px; font-family: inherit; } .color-var-manual { width: 100%; padding: 5px 8px; background: var(--bg-tertiary); color: var(--text-primary); border: 1px solid var(--border); border-radius: 3px; font-size: 11px; font-family: monospace; box-sizing: border-box; } .color-var-manual:focus, .color-var-select:focus { outline: none; border-color: var(--accent); } .color-custom-panel { display: flex; flex-direction: column; gap: 4px; } .color-custom-row { display: flex; gap: 6px; align-items: center; } .color-hex-input { width: 36px; height: 28px; padding: 1px 2px; border: 1px solid var(--border); border-radius: 3px; cursor: pointer; background: none; flex-shrink: 0; } .color-alpha-wrap { flex: 1; display: flex; align-items: center; gap: 5px; } .color-alpha-input { flex: 1; cursor: pointer; accent-color: var(--accent); height: 4px; } .color-alpha-label { font-size: 11px; color: var(--text-muted); min-width: 32px; text-align: right; } .color-preview-swatch { width: 28px; height: 28px; border-radius: 3px; border: 1px solid var(--border); flex-shrink: 0; position: relative; overflow: hidden; background-color: #fff; background-image: linear-gradient(45deg, #bbb 25%, transparent 25%), linear-gradient(-45deg, #bbb 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #bbb 75%), linear-gradient(-45deg, transparent 75%, #bbb 75%); background-size: 8px 8px; background-position: 0 0, 0 4px, 4px -4px, -4px 0px; } .color-preview-swatch-inner { position: absolute; inset: 0; border-radius: 2px; } .color-preview-value { font-size: 10px; color: var(--text-muted); font-family: monospace; word-break: break-all; line-height: 1.3; }
editor/html/js/properties.js +170 −5 Changes for editor/html/js/properties.js: 170 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -157,6 +157,173 @@ var PropertiesPanel = (function() { container.appendChild(form); } var BLOGI_THEME_VARS = [ { label: '-- Theme-Variable wählen --', value: '' }, { label: '--blogi-accent', value: 'var(--blogi-accent)' }, { label: '--blogi-accent-dark', value: 'var(--blogi-accent-dark)' }, { label: '--blogi-text', value: 'var(--blogi-text)' }, { label: '--blogi-text-muted', value: 'var(--blogi-text-muted)' }, { label: '--blogi-bg', value: 'var(--blogi-bg)' }, { label: '--blogi-bg-alt', value: 'var(--blogi-bg-alt)' }, { label: '--blogi-surface', value: 'var(--blogi-surface)' }, { label: '--blogi-border', value: 'var(--blogi-border)' }, { label: '--blogi-error', value: 'var(--blogi-error)' }, { label: '--blogi-nav-active', value: 'var(--blogi-nav-active)' }, { label: 'transparent', value: 'transparent' } ]; function _parseRgba(v) { if (!v) return { hex: '#000000', alpha: 100 }; var m = v.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d.]+))?\s*\)/); if (m) { var r = parseInt(m[1]), g = parseInt(m[2]), b = parseInt(m[3]); var a = m[4] !== undefined ? Math.round(parseFloat(m[4]) * 100) : 100; return { hex: '#' + ('0'+r.toString(16)).slice(-2) + ('0'+g.toString(16)).slice(-2) + ('0'+b.toString(16)).slice(-2), alpha: Math.max(0, Math.min(100, a)) }; } if (/^#[0-9a-fA-F]{6}/.test(v)) return { hex: v.slice(0, 7), alpha: 100 }; if (/^#[0-9a-fA-F]{3}$/.test(v)) { var c = v.slice(1); return { hex: '#'+c[0]+c[0]+c[1]+c[1]+c[2]+c[2], alpha: 100 }; } return { hex: '#000000', alpha: 100 }; } function _hexAlphaToString(hex, alpha) { var r = parseInt(hex.slice(1,3), 16), g = parseInt(hex.slice(3,5), 16), b = parseInt(hex.slice(5,7), 16); if (alpha >= 100) return 'rgb(' + r + ', ' + g + ', ' + b + ')'; return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + (alpha / 100).toFixed(2) + ')'; } function _renderColorField(group, field, value) { var isVarMode = !value || value.indexOf('var(') === 0 || value.slice(0,2) === '--' || value === 'transparent'; var mode = isVarMode ? 'var' : 'custom'; var parsed = _parseRgba(value); var hiddenInput = document.createElement('input'); hiddenInput.type = 'hidden'; hiddenInput.name = field.key; hiddenInput.value = value || ''; var toggle = document.createElement('div'); toggle.className = 'color-mode-toggle'; var varBtn = document.createElement('button'); varBtn.type = 'button'; varBtn.className = 'color-mode-btn' + (mode === 'var' ? ' active' : ''); varBtn.textContent = 'Theme Var'; var customBtn = document.createElement('button'); customBtn.type = 'button'; customBtn.className = 'color-mode-btn' + (mode === 'custom' ? ' active' : ''); customBtn.textContent = 'Custom'; toggle.appendChild(varBtn); toggle.appendChild(customBtn); // --- Var panel --- var varPanel = document.createElement('div'); varPanel.className = 'color-var-panel'; varPanel.style.display = mode === 'var' ? '' : 'none'; var varSelect = document.createElement('select'); varSelect.className = 'color-var-select'; var inPredefined = false; for (var vi = 0; vi < BLOGI_THEME_VARS.length; vi++) { var tvOpt = document.createElement('option'); tvOpt.value = BLOGI_THEME_VARS[vi].value; tvOpt.textContent = BLOGI_THEME_VARS[vi].label; if (value && value === BLOGI_THEME_VARS[vi].value) { tvOpt.selected = true; inPredefined = true; } varSelect.appendChild(tvOpt); } varPanel.appendChild(varSelect); var varManual = document.createElement('input'); varManual.type = 'text'; varManual.className = 'color-var-manual'; varManual.placeholder = 'var(--eigene-variable)'; if (isVarMode && !inPredefined && value) varManual.value = value; varPanel.appendChild(varManual); // --- Custom panel --- var customPanel = document.createElement('div'); customPanel.className = 'color-custom-panel'; customPanel.style.display = mode === 'custom' ? '' : 'none'; var customRow = document.createElement('div'); customRow.className = 'color-custom-row'; var hexInput = document.createElement('input'); hexInput.type = 'color'; hexInput.className = 'color-hex-input'; hexInput.value = parsed.hex; var alphaWrap = document.createElement('div'); alphaWrap.className = 'color-alpha-wrap'; var alphaInput = document.createElement('input'); alphaInput.type = 'range'; alphaInput.className = 'color-alpha-input'; alphaInput.min = '0'; alphaInput.max = '100'; alphaInput.value = String(parsed.alpha); var alphaLabel = document.createElement('span'); alphaLabel.className = 'color-alpha-label'; alphaLabel.textContent = parsed.alpha + '%'; alphaWrap.appendChild(alphaInput); alphaWrap.appendChild(alphaLabel); var swatch = document.createElement('div'); swatch.className = 'color-preview-swatch'; var swatchInner = document.createElement('div'); swatchInner.className = 'color-preview-swatch-inner'; swatchInner.style.background = (!isVarMode && value) ? value : _hexAlphaToString(parsed.hex, parsed.alpha); swatch.appendChild(swatchInner); customRow.appendChild(hexInput); customRow.appendChild(alphaWrap); customRow.appendChild(swatch); customPanel.appendChild(customRow); var previewVal = document.createElement('div'); previewVal.className = 'color-preview-value'; previewVal.textContent = value || ''; customPanel.appendChild(previewVal); function updateValue() { var newVal; if (mode === 'var') { newVal = varSelect.value || varManual.value.trim() || ''; } else { newVal = _hexAlphaToString(hexInput.value, parseInt(alphaInput.value, 10)); } hiddenInput.value = newVal; previewVal.textContent = newVal; alphaLabel.textContent = alphaInput.value + '%'; try { swatchInner.style.background = newVal; } catch(e) {} hiddenInput.dispatchEvent(new Event('change', { bubbles: true })); } function switchMode(newMode) { mode = newMode; varBtn.classList.toggle('active', mode === 'var'); customBtn.classList.toggle('active', mode === 'custom'); varPanel.style.display = mode === 'var' ? '' : 'none'; customPanel.style.display = mode === 'custom' ? '' : 'none'; updateValue(); } varBtn.addEventListener('click', function() { switchMode('var'); }); customBtn.addEventListener('click', function() { switchMode('custom'); }); varSelect.addEventListener('change', function() { varManual.value = ''; updateValue(); }); varManual.addEventListener('input', function() { if (varManual.value.trim()) varSelect.value = ''; updateValue(); }); hexInput.addEventListener('input', updateValue); alphaInput.addEventListener('input', updateValue); group.appendChild(hiddenInput); group.appendChild(toggle); group.appendChild(varPanel); group.appendChild(customPanel); } function _renderFieldsInto(panel, fields, properties, form) { for (var i = 0; i < fields.length; i++) { var field = fields[i]; Loading Loading @@ -196,11 +363,9 @@ var PropertiesPanel = (function() { input.appendChild(opt); } } else if (field.type === 'color' || field.type === 'color_var') { input = document.createElement('input'); input.type = 'text'; input.name = field.key; input.value = value; input.placeholder = field.placeholder || '#000000 oder var(--name)'; _renderColorField(group, field, value); panel.appendChild(group); continue; } else if (field.type === 'html' || field.type === 'richtext') { var rteWrap = document.createElement('div'); rteWrap.className = 'rte-wrap'; Loading
editor/widgets/popup/popup.cpp +18 −0 Changes for editor/widgets/popup/popup.cpp: 18 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -625,6 +625,24 @@ extern "C" { mediaCSS += " }"; } // Mobile + Light mode overrides std::string mobileLightBtnCSS; if (validCss(ml_buttonBgColor)) mobileLightBtnCSS += " background-color: " + ml_buttonBgColor + " !important;"; if (validCss(ml_buttonTextColor)) mobileLightBtnCSS += " color: " + ml_buttonTextColor + " !important;"; std::string mobileLightPopupCSS; if (validCss(ml_popupBgColor)) mobileLightPopupCSS += " background: " + ml_popupBgColor + " !important;"; if (validCss(ml_popupTextColor)) mobileLightPopupCSS += " color: " + ml_popupTextColor + " !important;"; if (!mobileLightBtnCSS.empty() || !mobileLightPopupCSS.empty()) { mediaCSS += "@media (max-width: 768px) and (prefers-color-scheme: light) {"; if (!mobileLightBtnCSS.empty()) mediaCSS += " ." + responsiveClass + "-btn {" + mobileLightBtnCSS + " }"; if (!mobileLightPopupCSS.empty()) mediaCSS += " ." + responsiveClass + "-dialog {" + mobileLightPopupCSS + " }"; mediaCSS += " }"; } // Escape key listener mediaCSS += " "; // spacer before script Loading