vibecoded page and function change in ino
This commit is contained in:
@@ -71,7 +71,7 @@ void drawTextNodes(bool reset_cursor = true)
|
||||
}
|
||||
}
|
||||
|
||||
void scrollAllScrollableTexts()
|
||||
void scrollAllScrollableTexts(split_scroll_mode = false)
|
||||
{
|
||||
for (unsigned char i = 0; i < MAX_TEXT_NODES_COUNT; i++)
|
||||
{
|
||||
@@ -81,10 +81,8 @@ void scrollAllScrollableTexts()
|
||||
short y1 = text_nodes[i].pos_y;
|
||||
short x2 = text_nodes[i].pos_x + text_nodes[i].characterSize.width * text_nodes[i].character_count + text_nodes[i].character_count - 1;
|
||||
short y2 = text_nodes[i].pos_y + text_nodes[i].characterSize.height - 1;
|
||||
// If the text is scrolling on the upper part of the screen, scroll it to the left.
|
||||
if (text_nodes[i].pos_y < 7)
|
||||
if (split_scroll_mode || text_nodes[i].pos_y < 7)
|
||||
{
|
||||
// If the text is completely out of the screen, mark it as deleted.
|
||||
if (x2 < 0)
|
||||
{
|
||||
text_nodes[i].is_deleted = true;
|
||||
@@ -93,10 +91,8 @@ void scrollAllScrollableTexts()
|
||||
shiftGivenRectangleLeft(x1, y1, x2, y2, text_nodes[i].scroll_slowness);
|
||||
text_nodes[i].pos_x -= text_nodes[i].scroll_slowness;
|
||||
}
|
||||
// If the text is scrolling on the lower part of the screen, scroll it to the right.
|
||||
else
|
||||
{
|
||||
// If the text is completely out of the screen, mark it as deleted.
|
||||
if (x1 > PANEL_MAX_X)
|
||||
{
|
||||
text_nodes[i].is_deleted = true;
|
||||
|
||||
+472
-101
@@ -5,31 +5,124 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
font-family: Arial, sans-serif;
|
||||
padding: 20px;
|
||||
max-width: 800px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
background-color: #0d1117;
|
||||
color: #c9d1d9;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: #333;
|
||||
color: #c9d1d9;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
display: inline-grid;
|
||||
grid-template-columns: repeat(5, 25px);
|
||||
gap: 5px;
|
||||
.size-controls {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
margin: 20px 0;
|
||||
padding: 15px;
|
||||
background-color: #161b22;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #30363d;
|
||||
}
|
||||
|
||||
.size-input-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.size-input-group label {
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
color: #c9d1d9;
|
||||
}
|
||||
|
||||
.size-input-group input[type="number"] {
|
||||
width: 80px;
|
||||
padding: 8px;
|
||||
font-size: 16px;
|
||||
border: 1px solid #30363d;
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
background-color: #0d1117;
|
||||
color: #c9d1d9;
|
||||
}
|
||||
|
||||
.size-input-group input[type="number"]:focus {
|
||||
outline: none;
|
||||
border-color: #58a6ff;
|
||||
}
|
||||
|
||||
.color-controls {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
margin: 20px 0;
|
||||
padding: 15px;
|
||||
background-color: #161b22;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #30363d;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.color-picker-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.color-picker-group label {
|
||||
font-weight: bold;
|
||||
color: #c9d1d9;
|
||||
}
|
||||
|
||||
.color-picker-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 5px 10px;
|
||||
background-color: #0d1117;
|
||||
border: 1px solid #30363d;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
input[type="color"] {
|
||||
width: 50px;
|
||||
height: 35px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.color-value {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 14px;
|
||||
color: #c9d1d9;
|
||||
min-width: 70px;
|
||||
}
|
||||
|
||||
.canvas-container {
|
||||
margin: 20px 0;
|
||||
padding: 10px;
|
||||
background-color: #f5f5f5;
|
||||
background-color: #161b22;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #30363d;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.checkbox-cell {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
cursor: pointer;
|
||||
#gridCanvas {
|
||||
cursor: crosshair;
|
||||
display: block;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.controls {
|
||||
@@ -41,138 +134,416 @@
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
background-color: #0969da;
|
||||
color: white;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color: #c9d1d9;
|
||||
border: 1px solid #c9d1d9;
|
||||
border-radius: 6px;
|
||||
margin: 0 5px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #0860ca;
|
||||
background-color: rgba(201, 209, 217, 0.1);
|
||||
border-color: #ffffff;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.json-output {
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
background-color: #f6f8fa;
|
||||
border: 1px solid #d0d7de;
|
||||
.export-section {
|
||||
margin: 20px 0;
|
||||
padding: 20px;
|
||||
background-color: #161b22;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #30363d;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.export-section h3 {
|
||||
margin-top: 0;
|
||||
color: #c9d1d9;
|
||||
}
|
||||
|
||||
.export-options {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
margin: 15px 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.radio-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 15px;
|
||||
background-color: #0d1117;
|
||||
border: 1px solid #30363d;
|
||||
border-radius: 6px;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 12px;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
.radio-group:hover {
|
||||
border-color: #58a6ff;
|
||||
background-color: rgba(88, 166, 255, 0.1);
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
background-color: #2da44e;
|
||||
.radio-group input[type="radio"] {
|
||||
cursor: pointer;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.radio-group label {
|
||||
cursor: pointer;
|
||||
color: #c9d1d9;
|
||||
margin: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.radio-group.selected {
|
||||
border-color: #58a6ff;
|
||||
background-color: rgba(88, 166, 255, 0.15);
|
||||
}
|
||||
|
||||
.format-description {
|
||||
font-size: 13px;
|
||||
color: #8b949e;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.copy-button:hover {
|
||||
background-color: #2c974b;
|
||||
.generate-button {
|
||||
margin-top: 15px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.copied-message {
|
||||
color: #2da44e;
|
||||
color: #3fb950;
|
||||
margin-left: 10px;
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.copied-message.show {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="grid-container" id="checkboxGrid"></div>
|
||||
<h1>Grid Color Generator</h1>
|
||||
|
||||
<div class="controls">
|
||||
<button onclick="generateJSON()">Generate JSON</button>
|
||||
<button onclick="clearGrid()">Clear All</button>
|
||||
<button onclick="checkAll()">Check All</button>
|
||||
<div class="size-controls">
|
||||
<div class="size-input-group">
|
||||
<label for="rowsInput">Rows:</label>
|
||||
<input type="number" id="rowsInput" min="1" max="50" value="16">
|
||||
</div>
|
||||
|
||||
<div id="jsonOutputContainer" class="hidden">
|
||||
<h3>JSON Output:</h3>
|
||||
<div class="json-output" id="jsonOutput"></div>
|
||||
<button class="copy-button" onclick="copyToClipboard()">Copy to Clipboard</button>
|
||||
<span id="copiedMessage" class="copied-message hidden">✓ Copied!</span>
|
||||
<div class="size-input-group">
|
||||
<label for="colsInput">Columns:</label>
|
||||
<input type="number" id="colsInput" min="1" max="50" value="43">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Initialize the 7x5 grid (7 rows, 5 columns)
|
||||
function initializeGrid() {
|
||||
const grid = document.getElementById('checkboxGrid');
|
||||
grid.innerHTML = '';
|
||||
<div class="color-controls">
|
||||
<div class="color-picker-group">
|
||||
<label for="colorPicker">Draw Color:</label>
|
||||
<div class="color-picker-wrapper">
|
||||
<input type="color" id="colorPicker" value="#ffffff">
|
||||
<span class="color-value" id="colorValue">#ffffff</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
for (let i = 0; i < 7; i++) {
|
||||
for (let j = 0; j < 5; j++) {
|
||||
const checkbox = document.createElement('input');
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.className = 'checkbox-cell';
|
||||
checkbox.dataset.row = i;
|
||||
checkbox.dataset.col = j;
|
||||
grid.appendChild(checkbox);
|
||||
}
|
||||
<div class="canvas-container">
|
||||
<canvas id="gridCanvas"></canvas>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<button onclick="clearGrid()">Clear All</button>
|
||||
<button onclick="fillAll()">Fill All</button>
|
||||
</div>
|
||||
|
||||
<div class="export-section">
|
||||
<h3>Export Format</h3>
|
||||
<div class="export-options">
|
||||
<div class="radio-group selected" onclick="selectFormat('boolean')">
|
||||
<input type="radio" id="formatBoolean" name="exportFormat" value="boolean" checked>
|
||||
<label for="formatBoolean">Boolean (true/false)</label>
|
||||
</div>
|
||||
<div class="radio-group" onclick="selectFormat('color')">
|
||||
<input type="radio" id="formatColor" name="exportFormat" value="color">
|
||||
<label for="formatColor">Color (hex codes)</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="format-description">
|
||||
<strong>Boolean:</strong> Exports filled cells as true, empty as false<br>
|
||||
<strong>Color:</strong> Exports actual hex color values, empty cells as null
|
||||
</div>
|
||||
<div class="generate-button">
|
||||
<button onclick="generateAndCopy()">Generate & Copy to Clipboard</button>
|
||||
<span id="copiedMessage" class="copied-message">✓ Copied!</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const canvas = document.getElementById('gridCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
let currentRows = 16;
|
||||
let currentCols = 43;
|
||||
let cellSize = 25;
|
||||
let gridState = []; // Stores color values or null
|
||||
let isDrawing = false;
|
||||
let drawMode = null; // 'fill' or 'erase'
|
||||
let currentColor = '#ffffff';
|
||||
|
||||
// Colors
|
||||
const colors = {
|
||||
background: '#000000',
|
||||
border: '#30363d',
|
||||
borderHover: '#58a6ff'
|
||||
};
|
||||
|
||||
// Select format radio button
|
||||
function selectFormat(format) {
|
||||
// Update radio buttons
|
||||
const booleanRadio = document.getElementById('formatBoolean');
|
||||
const colorRadio = document.getElementById('formatColor');
|
||||
|
||||
if (format === 'boolean') {
|
||||
booleanRadio.checked = true;
|
||||
colorRadio.checked = false;
|
||||
} else {
|
||||
booleanRadio.checked = false;
|
||||
colorRadio.checked = true;
|
||||
}
|
||||
|
||||
// Update visual selection
|
||||
const radioGroups = document.querySelectorAll('.radio-group');
|
||||
radioGroups.forEach(group => group.classList.remove('selected'));
|
||||
event.currentTarget.classList.add('selected');
|
||||
}
|
||||
|
||||
// Initialize grid state
|
||||
function initializeGrid() {
|
||||
gridState = [];
|
||||
for (let i = 0; i < currentRows; i++) {
|
||||
gridState[i] = [];
|
||||
for (let j = 0; j < currentCols; j++) {
|
||||
gridState[i][j] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate JSON from checkbox states
|
||||
function generateJSON() {
|
||||
const checkboxes = document.querySelectorAll('.checkbox-cell');
|
||||
const grid = [];
|
||||
// Resize canvas
|
||||
canvas.width = currentCols * cellSize;
|
||||
canvas.height = currentRows * cellSize;
|
||||
|
||||
// Create 2D array (7 rows x 5 columns)
|
||||
for (let i = 0; i < 7; i++) {
|
||||
grid[i] = [];
|
||||
for (let j = 0; j < 5; j++) {
|
||||
const checkbox = document.querySelector(`[data-row="${i}"][data-col="${j}"]`);
|
||||
grid[i][j] = checkbox.checked;
|
||||
drawGrid();
|
||||
}
|
||||
|
||||
// Draw the grid
|
||||
function drawGrid() {
|
||||
// Clear canvas with black background
|
||||
ctx.fillStyle = colors.background;
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// Draw cells
|
||||
for (let i = 0; i < currentRows; i++) {
|
||||
for (let j = 0; j < currentCols; j++) {
|
||||
drawCell(i, j, gridState[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw individual cell
|
||||
function drawCell(row, col, colorValue) {
|
||||
const x = col * cellSize;
|
||||
const y = row * cellSize;
|
||||
|
||||
// Draw cell background (black)
|
||||
ctx.fillStyle = colors.background;
|
||||
ctx.fillRect(x, y, cellSize, cellSize);
|
||||
|
||||
// Draw cell border
|
||||
ctx.strokeStyle = colors.border;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.strokeRect(x + 0.5, y + 0.5, cellSize - 1, cellSize - 1);
|
||||
|
||||
// Draw filled state with color
|
||||
if (colorValue !== null) {
|
||||
ctx.fillStyle = colorValue;
|
||||
const padding = 3;
|
||||
ctx.fillRect(
|
||||
x + padding,
|
||||
y + padding,
|
||||
cellSize - padding * 2,
|
||||
cellSize - padding * 2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Get cell coordinates from mouse position
|
||||
function getCellFromMouse(e) {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const mouseX = e.clientX - rect.left;
|
||||
const mouseY = e.clientY - rect.top;
|
||||
|
||||
const col = Math.floor(mouseX / cellSize);
|
||||
const row = Math.floor(mouseY / cellSize);
|
||||
|
||||
if (row >= 0 && row < currentRows && col >= 0 && col < currentCols) {
|
||||
return { row, col };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Mouse down event
|
||||
canvas.addEventListener('mousedown', function(e) {
|
||||
e.preventDefault();
|
||||
isDrawing = true;
|
||||
|
||||
const cell = getCellFromMouse(e);
|
||||
if (cell) {
|
||||
if (e.button === 0) { // Left click
|
||||
drawMode = 'fill';
|
||||
gridState[cell.row][cell.col] = currentColor;
|
||||
} else if (e.button === 2) { // Right click
|
||||
drawMode = 'erase';
|
||||
gridState[cell.row][cell.col] = null;
|
||||
}
|
||||
drawCell(cell.row, cell.col, gridState[cell.row][cell.col]);
|
||||
}
|
||||
});
|
||||
|
||||
// Mouse move event
|
||||
canvas.addEventListener('mousemove', function(e) {
|
||||
if (!isDrawing) return;
|
||||
|
||||
const cell = getCellFromMouse(e);
|
||||
if (cell) {
|
||||
if (drawMode === 'fill') {
|
||||
gridState[cell.row][cell.col] = currentColor;
|
||||
} else if (drawMode === 'erase') {
|
||||
gridState[cell.row][cell.col] = null;
|
||||
}
|
||||
drawCell(cell.row, cell.col, gridState[cell.row][cell.col]);
|
||||
}
|
||||
});
|
||||
|
||||
// Mouse up event
|
||||
canvas.addEventListener('mouseup', function(e) {
|
||||
isDrawing = false;
|
||||
drawMode = null;
|
||||
});
|
||||
|
||||
// Mouse leave event
|
||||
canvas.addEventListener('mouseleave', function(e) {
|
||||
isDrawing = false;
|
||||
drawMode = null;
|
||||
});
|
||||
|
||||
// Prevent context menu
|
||||
canvas.addEventListener('contextmenu', function(e) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
});
|
||||
|
||||
// Color picker change
|
||||
document.getElementById('colorPicker').addEventListener('input', function(e) {
|
||||
currentColor = e.target.value;
|
||||
document.getElementById('colorValue').textContent = currentColor;
|
||||
});
|
||||
|
||||
// Update grid size
|
||||
function updateGridSize() {
|
||||
const rowsInput = document.getElementById('rowsInput');
|
||||
const colsInput = document.getElementById('colsInput');
|
||||
|
||||
currentRows = parseInt(rowsInput.value) || 1;
|
||||
currentCols = parseInt(colsInput.value) || 1;
|
||||
|
||||
if (currentRows < 1) currentRows = 1;
|
||||
if (currentCols < 1) currentCols = 1;
|
||||
|
||||
initializeGrid();
|
||||
}
|
||||
|
||||
// Generate JSON and copy to clipboard
|
||||
function generateAndCopy() {
|
||||
const formatRadios = document.getElementsByName('exportFormat');
|
||||
let selectedFormat = 'boolean';
|
||||
|
||||
for (const radio of formatRadios) {
|
||||
if (radio.checked) {
|
||||
selectedFormat = radio.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let outputData = [];
|
||||
|
||||
if (selectedFormat === 'boolean') {
|
||||
// Convert to boolean: filled = true, empty = false
|
||||
for (let i = 0; i < currentRows; i++) {
|
||||
outputData[i] = [];
|
||||
for (let j = 0; j < currentCols; j++) {
|
||||
outputData[i][j] = gridState[i][j] !== null;
|
||||
}
|
||||
}
|
||||
|
||||
// Display JSON
|
||||
const jsonOutput = document.getElementById('jsonOutput');
|
||||
const jsonOutputContainer = document.getElementById('jsonOutputContainer');
|
||||
jsonOutput.textContent = JSON.stringify(grid, null, 2);
|
||||
jsonOutputContainer.classList.remove('hidden');
|
||||
|
||||
// Hide copied message
|
||||
document.getElementById('copiedMessage').classList.add('hidden');
|
||||
} else {
|
||||
// Keep color values: hex codes or null
|
||||
outputData = JSON.parse(JSON.stringify(gridState)); // Deep copy
|
||||
}
|
||||
|
||||
// Clear all checkboxes
|
||||
function clearGrid() {
|
||||
const checkboxes = document.querySelectorAll('.checkbox-cell');
|
||||
checkboxes.forEach(cb => cb.checked = false);
|
||||
}
|
||||
// Generate JSON string
|
||||
const jsonText = JSON.stringify(outputData, null, 2);
|
||||
|
||||
// Check all checkboxes
|
||||
function checkAll() {
|
||||
const checkboxes = document.querySelectorAll('.checkbox-cell');
|
||||
checkboxes.forEach(cb => cb.checked = true);
|
||||
}
|
||||
// Copy to clipboard
|
||||
navigator.clipboard.writeText(jsonText).then(() => {
|
||||
const message = document.getElementById('copiedMessage');
|
||||
message.classList.add('show');
|
||||
setTimeout(() => {
|
||||
message.classList.remove('show');
|
||||
}, 2000);
|
||||
}).catch(err => {
|
||||
alert('Failed to copy to clipboard');
|
||||
console.error('Copy failed:', err);
|
||||
});
|
||||
}
|
||||
|
||||
// Copy JSON to clipboard
|
||||
function copyToClipboard() {
|
||||
const jsonText = document.getElementById('jsonOutput').textContent;
|
||||
navigator.clipboard.writeText(jsonText).then(() => {
|
||||
const message = document.getElementById('copiedMessage');
|
||||
message.classList.remove('hidden');
|
||||
setTimeout(() => {
|
||||
message.classList.add('hidden');
|
||||
}, 2000);
|
||||
}).catch(err => {
|
||||
alert('Failed to copy to clipboard');
|
||||
console.error('Copy failed:', err);
|
||||
});
|
||||
// Clear all cells
|
||||
function clearGrid() {
|
||||
for (let i = 0; i < currentRows; i++) {
|
||||
for (let j = 0; j < currentCols; j++) {
|
||||
gridState[i][j] = null;
|
||||
}
|
||||
}
|
||||
drawGrid();
|
||||
}
|
||||
|
||||
// Fill all cells
|
||||
function fillAll() {
|
||||
for (let i = 0; i < currentRows; i++) {
|
||||
for (let j = 0; j < currentCols; j++) {
|
||||
gridState[i][j] = currentColor;
|
||||
}
|
||||
}
|
||||
drawGrid();
|
||||
}
|
||||
|
||||
// Add event listeners to inputs
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const rowsInput = document.getElementById('rowsInput');
|
||||
const colsInput = document.getElementById('colsInput');
|
||||
|
||||
rowsInput.addEventListener('input', updateGridSize);
|
||||
colsInput.addEventListener('input', updateGridSize);
|
||||
|
||||
// Initialize grid on page load
|
||||
initializeGrid();
|
||||
</script>
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user