// Settings Configuration
const SETTINGS = {
animations: {
panelTransition: 400,
selectionDelay: 200,
deleteAnimation: 300,
slideInDuration: 400,
hoverTransition: 300
},
panel: {
width: 400,
headerHeight: 85,
contentPadding: 30,
scrollbarWidth: 8
},
sliders: {
width: {
px: { min: 80, max: 800, default: 120 },
percent: { min: 5, max: 100, default: 100 }
},
height: {
px: { min: 60, max: 600, default: 80 },
percent: { min: 5, max: 100, default: 15 }
},
padding: {
px: { min: 0, max: 100, default: 20 },
percent: { min: 0, max: 10, default: 2 }
},
position: {
px: { min: 0, maxOffset: 80, default: 100 },
percent: { min: 0, max: 95, default: 10 }
}
},
visual: {
borderRadius: 12,
blurIntensity: 10,
shadowIntensity: 0.2,
hoverLift: 2,
selectionGlow: 20
},
colors: [
'linear-gradient(135deg, #667eea, #764ba2)',
'linear-gradient(135deg, #f093fb, #f5576c)',
'linear-gradient(135deg, #4facfe, #00f2fe)',
'linear-gradient(135deg, #43e97b, #38f9d7)',
'linear-gradient(135deg, #fa709a, #fee140)',
'linear-gradient(135deg, #a8edea, #fed6e3)',
'linear-gradient(135deg, #ff9a9e, #fecfef)',
'linear-gradient(135deg, #ffecd2, #fcb69f)',
'linear-gradient(135deg, #89f7fe, #66a6ff)',
'linear-gradient(135deg, #fdbb2d, #22c1c3)',
'linear-gradient(135deg, #ff758c, #ff7eb3)',
'linear-gradient(135deg, #84fab0, #8fd3f4)',
'linear-gradient(135deg, #a18cd1, #fbc2eb)',
'linear-gradient(135deg, #fad0c4, #ffd1ff)',
'linear-gradient(135deg, #ff9a8b, #a8e6cf)',
'linear-gradient(135deg, #d299c2, #fef9d7)'
],
sortable: {
animation: 150,
delay: 100,
delayOnTouchStart: true,
ghostOpacity: 0.4,
dragRotation: 5,
dragShadow: '0 10px 30px rgba(0, 0, 0, 0.3)'
},
drag: {
threshold: 5,
timeThreshold: 150,
clickTimeLimit: 200,
zIndexActive: 1001
},
typography: {
headerSize: 18,
sectionSize: 15,
labelSize: 13,
inputSize: 14,
displaySize: 11
},
layout: {
toolbarSpacing: 20,
canvasPadding: 20,
flowGap: 15,
controlsMaxWidth: 280,
minDivWidth: 120,
minDivHeight: 80
}
};
// Export settings globally
window.LAYOUT_SETTINGS = SETTINGS;
// Global state variables - shared across files
window.AppState = {
currentUnit: '%',
selectedDiv: null,
divProperties: new Map(),
colors: SETTINGS.colors
};
function initColorGrid() {
const colorGrid = document.getElementById('colorGrid');
if (!colorGrid) {
console.error('Color grid element not found!');
return;
}
colorGrid.innerHTML = '';
window.AppState.colors.forEach((color, index) => {
const colorOption = document.createElement('div');
colorOption.className = 'color-option';
colorOption.style.background = color;
colorOption.onclick = () => changeColor(index);
colorGrid.appendChild(colorOption);
});
}
function setUnit(unit) {
window.AppState.currentUnit = unit;
document.getElementById('pxBtn').classList.toggle('active', unit === 'px');
document.getElementById('percentBtn').classList.toggle('active', unit === '%');
updateSliderRanges();
if (window.AppState.selectedDiv) {
updateSliderValues();
}
}
function updateSliderRanges() {
const widthSlider = document.getElementById('widthSlider');
const heightSlider = document.getElementById('heightSlider');
const xSlider = document.getElementById('xSlider');
const ySlider = document.getElementById('ySlider');
const paddingSlider = document.getElementById('paddingSlider');
if (window.AppState.currentUnit === 'px') {
const w = SETTINGS.sliders.width.px;
const h = SETTINGS.sliders.height.px;
const p = SETTINGS.sliders.padding.px;
const pos = SETTINGS.sliders.position.px;
widthSlider.min = w.min;
widthSlider.max = w.max;
heightSlider.min = h.min;
heightSlider.max = h.max;
xSlider.min = pos.min;
xSlider.max = window.innerWidth - pos.maxOffset;
ySlider.min = pos.min;
ySlider.max = window.innerHeight - pos.maxOffset;
paddingSlider.min = p.min;
paddingSlider.max = p.max;
} else {
const w = SETTINGS.sliders.width.percent;
const h = SETTINGS.sliders.height.percent;
const p = SETTINGS.sliders.padding.percent;
const pos = SETTINGS.sliders.position.percent;
widthSlider.min = w.min;
widthSlider.max = w.max;
heightSlider.min = h.min;
heightSlider.max = h.max;
xSlider.min = pos.min;
xSlider.max = pos.max;
ySlider.min = pos.min;
ySlider.max = pos.max;
paddingSlider.min = p.min;
paddingSlider.max = p.max;
}
}
function updateSliderValues() {
if (!window.AppState.selectedDiv) return;
const divId = window.AppState.selectedDiv.id;
const props = window.AppState.divProperties.get(divId);
if (!props) return;
let widthValue, heightValue, paddingValue;
if (window.AppState.currentUnit === 'px') {
widthValue = props.width.px;
heightValue = props.height.px;
paddingValue = props.padding.px;
} else {
widthValue = props.width.percent;
heightValue = props.height.percent;
paddingValue = props.padding.percent;
}
document.getElementById('widthSlider').value = widthValue;
document.getElementById('heightSlider').value = heightValue;
document.getElementById('paddingSlider').value = paddingValue;
document.getElementById('widthDisplay').textContent = Math.round(widthValue * 10) / 10 + window.AppState.currentUnit;
document.getElementById('heightDisplay').textContent = Math.round(heightValue * 10) / 10 + window.AppState.currentUnit;
document.getElementById('paddingDisplay').textContent = Math.round(paddingValue * 10) / 10 + window.AppState.currentUnit;
document.getElementById('divNameInput').value = props.name || '';
if (props.positioning === 'absolute') {
updatePositionSliders();
}
}
function updatePositionSliders() {
if (!window.AppState.selectedDiv || !window.AppState.selectedDiv.classList.contains('absolute')) return;
const divId = window.AppState.selectedDiv.id;
const props = window.AppState.divProperties.get(divId);
let xValue, yValue;
if (window.AppState.currentUnit === 'px') {
xValue = props.x.px;
yValue = props.y.px;
} else {
xValue = props.x.percent;
yValue = props.y.percent;
}
document.getElementById('xSlider').value = xValue;
document.getElementById('ySlider').value = yValue;
document.getElementById('xDisplay').textContent = Math.round(xValue * 10) / 10 + window.AppState.currentUnit;
document.getElementById('yDisplay').textContent = Math.round(yValue * 10) / 10 + window.AppState.currentUnit;
}
function closeProperties() {
if (window.AppState.selectedDiv) {
window.AppState.selectedDiv.classList.remove('selected');
window.AppState.selectedDiv = null;
}
document.getElementById('propertiesPanel').classList.remove('visible');
}
function updateColorSelection(div) {
const colorOptions = document.querySelectorAll('.color-option');
colorOptions.forEach(option => option.classList.remove('selected'));
const currentBg = div.style.background;
window.AppState.colors.forEach((color, index) => {
if (currentBg === color) {
colorOptions[index].classList.add('selected');
}
});
}
function updateDivName() {
if (!window.AppState.selectedDiv) return;
const newName = document.getElementById('divNameInput').value;
const divId = window.AppState.selectedDiv.id;
const props = window.AppState.divProperties.get(divId);
props.name = newName;
const textSpan = window.AppState.selectedDiv.querySelector('span');
if (textSpan) {
if (newName.trim()) {
textSpan.textContent = newName;
} else {
const divNumber = divId.split('-')[1];
textSpan.textContent = `Div ${divNumber}`;
}
}
}
function updatePadding() {
if (!window.AppState.selectedDiv) return;
const padding = parseFloat(document.getElementById('paddingSlider').value);
const divId = window.AppState.selectedDiv.id;
const props = window.AppState.divProperties.get(divId);
let actualPadding;
if (window.AppState.currentUnit === 'px') {
actualPadding = padding;
props.padding.px = padding;
props.padding.percent = (padding / Math.min(window.innerWidth, window.innerHeight)) * 100;
} else {
actualPadding = (padding / 100) * Math.min(window.innerWidth, window.innerHeight);
props.padding.percent = padding;
props.padding.px = actualPadding;
}
window.AppState.selectedDiv.style.padding = actualPadding + 'px';
document.getElementById('paddingDisplay').textContent = Math.round(padding * 10) / 10 + window.AppState.currentUnit;
}
function updateSize() {
if (!window.AppState.selectedDiv) return;
const width = parseFloat(document.getElementById('widthSlider').value);
const height = parseFloat(document.getElementById('heightSlider').value);
const divId = window.AppState.selectedDiv.id;
const props = window.AppState.divProperties.get(divId);
let actualWidth, actualHeight;
if (window.AppState.currentUnit === 'px') {
actualWidth = width;
actualHeight = height;
const availableWidth = window.innerWidth - 40;
props.width.px = width;
props.width.percent = (width / availableWidth) * 100;
props.height.px = height;
props.height.percent = (height / window.innerHeight) * 100;
} else {
const availableWidth = window.innerWidth - 40;
actualWidth = (width / 100) * availableWidth;
actualHeight = (height / 100) * window.innerHeight;
props.width.percent = width;
props.width.px = actualWidth;
props.height.percent = height;
props.height.px = actualHeight;
}
window.AppState.selectedDiv.style.width = actualWidth + 'px';
window.AppState.selectedDiv.style.height = actualHeight + 'px';
document.getElementById('widthDisplay').textContent = Math.round(width * 10) / 10 + window.AppState.currentUnit;
document.getElementById('heightDisplay').textContent = Math.round(height * 10) / 10 + window.AppState.currentUnit;
}
function updatePosition() {
if (!window.AppState.selectedDiv || !window.AppState.selectedDiv.classList.contains('absolute')) return;
const x = parseFloat(document.getElementById('xSlider').value);
const y = parseFloat(document.getElementById('ySlider').value);
const divId = window.AppState.selectedDiv.id;
const props = window.AppState.divProperties.get(divId);
let actualX, actualY;
if (window.AppState.currentUnit === 'px') {
actualX = x;
actualY = y;
props.x.px = x;
props.x.percent = (x / window.innerWidth) * 100;
props.y.px = y;
props.y.percent = (y / window.innerHeight) * 100;
} else {
actualX = (x / 100) * window.innerWidth;
actualY = (y / 100) * window.innerHeight;
props.x.percent = x;
props.x.px = actualX;
props.y.percent = y;
props.y.px = actualY;
}
window.AppState.selectedDiv.style.left = actualX + 'px';
window.AppState.selectedDiv.style.top = actualY + 'px';
document.getElementById('xDisplay').textContent = Math.round(x * 10) / 10 + window.AppState.currentUnit;
document.getElementById('yDisplay').textContent = Math.round(y * 10) / 10 + window.AppState.currentUnit;
}
function setLayoutType(type) {
if (!window.AppState.selectedDiv) return;
const divId = window.AppState.selectedDiv.id;
const props = window.AppState.divProperties.get(divId);
const layoutControls = document.getElementById('layoutControls');
const layoutLabel = document.getElementById('layoutLabel');
// Update button states
document.getElementById('noneBtn').classList.toggle('active', type === 'none');
document.getElementById('columnsBtn').classList.toggle('active', type === 'columns');
document.getElementById('rowsBtn').classList.toggle('active', type === 'rows');
if (type === 'none') {
layoutControls.style.display = 'none';
clearLayout();
props.layoutType = 'none';
props.layoutCount = 0;
} else {
layoutControls.style.display = 'block';
layoutLabel.textContent = type === 'columns' ? 'Columns' : 'Rows';
props.layoutType = type;
props.layoutCount = parseInt(document.getElementById('layoutSlider').value);
updateLayout();
}
}
function clearLayout() {
if (!window.AppState.selectedDiv) return;
// Remove all layout children
const layoutChildren = window.AppState.selectedDiv.querySelectorAll('.layout-child');
layoutChildren.forEach(child => child.remove());
// Reset div styles
window.AppState.selectedDiv.style.display = 'flex';
window.AppState.selectedDiv.style.flexDirection = '';
window.AppState.selectedDiv.style.gap = '';
// Restore original content
const span = window.AppState.selectedDiv.querySelector('span');
if (span) {
span.style.display = 'block';
}
}
function updateLayout() {
if (!window.AppState.selectedDiv) return;
const divId = window.AppState.selectedDiv.id;
const props = window.AppState.divProperties.get(divId);
const count = parseInt(document.getElementById('layoutSlider').value);
const type = props.layoutType;
if (!type || type === 'none') return;
// Update display
document.getElementById('layoutDisplay').textContent = count;
props.layoutCount = count;
// Clear existing layout children
const existingChildren = window.AppState.selectedDiv.querySelectorAll('.layout-child');
existingChildren.forEach(child => child.remove());
// Hide the original span content when we have layout
const span = window.AppState.selectedDiv.querySelector('span');
if (span) {
span.style.display = 'none';
}
// Set up container styles
window.AppState.selectedDiv.style.display = 'flex';
window.AppState.selectedDiv.style.flexDirection = type === 'columns' ? 'row' : 'column';
window.AppState.selectedDiv.style.gap = '2px';
window.AppState.selectedDiv.style.padding = '2px';
// Create layout children
for (let i = 0; i < count; i++) {
const child = document.createElement('div');
child.className = 'layout-child';
child.style.flex = '1';
child.style.border = '1px solid rgba(255, 255, 255, 0.3)';
child.style.borderRadius = '4px';
child.style.minHeight = type === 'columns' ? '30px' : '20px';
child.style.minWidth = type === 'rows' ? '30px' : '20px';
child.style.background = 'transparent';
child.style.display = 'flex';
child.style.alignItems = 'center';
child.style.justifyContent = 'center';
child.style.fontSize = '10px';
child.style.color = 'rgba(255, 255, 255, 0.5)';
child.textContent = `${type === 'columns' ? 'Col' : 'Row'} ${i + 1}`;
window.AppState.selectedDiv.appendChild(child);
}
}
function changeColor(colorIndex) {
if (!window.AppState.selectedDiv) return;
window.AppState.selectedDiv.style.background = window.AppState.colors[colorIndex];
const colorOptions = document.querySelectorAll('.color-option');
colorOptions.forEach(option => option.classList.remove('selected'));
colorOptions[colorIndex].classList.add('selected');
}
// Export functions to global scope
window.setUnit = setUnit;
window.closeProperties = closeProperties;
window.updateDivName = updateDivName;
window.updatePadding = updatePadding;
window.updateSize = updateSize;
window.updatePosition = updatePosition;
window.changeColor = changeColor;
window.initColorGrid = initColorGrid;
window.updateColorSelection = updateColorSelection;
window.updateSliderRanges = updateSliderRanges;
window.updateSliderValues = updateSliderValues;
window.updatePositionSliders = updatePositionSliders;
window.setLayoutType = setLayoutType;
window.updateLayout = updateLayout;