<script src="https://cdn.jsdelivr.net/npm/baseline-status@1.0.8/baseline-status.min.js" type="module"></script>
<div class="grid-wrapper" id="grid">
<div class="grid"></div>
<div class="actions">
<div class="button">
<label for="add">Add new Element</label>
<button id="add" onclick="add()">+</button>
</div>
<div class="button">
<label for="clear">Clear Grid</label>
<button id="clear" onclick="clearGrid()">!</button>
</div>
<div class="grid-size">
<input type="number" value="" min="1" placeholder="rows" onchange="changeRows(this)" />
<input type="number" value="" min="1" placeholder="columns" onchange="changeCols(this)" />
</div>
</div>
</div>
<baseline-status featureId="registered-custom-properties"></baseline-status>
<baseline-status featureId="cascade-layers"></baseline-status>
<baseline-status featureId="starting-style"></baseline-status>
<baseline-status featureId="relative-color"></baseline-status>
<baseline-status featureId="logical-properties"></baseline-status>
<baseline-status featureId="container-queries"></baseline-status>
<baseline-status featureId="currentcolor"></baseline-status>
<baseline-status featureId="line-clamp"></baseline-status>
<baseline-status featureId="transition-behavior"></baseline-status>
@layer reset, overrides;
@property --color {
syntax: "<color>";
inherits: true;
initial-value: white;
}
@property --accent-color {
syntax: "<color>";
inherits: true;
initial-value: skyblue;
}
@property --primary-bg-color {
syntax: "<color>";
inherits: true;
initial-value: #141422;
}
@property --grid-cols {
syntax: "<integer>";
inherits: false;
initial-value: 12;
}
@property --grid-rows {
syntax: "<integer>";
inherits: false;
initial-value: 12;
}
@property --grid-gap {
syntax: "<length>";
inherits: true;
initial-value: 4px;
}
@property --row-span {
syntax: "<integer>";
inherits: false;
initial-value: 2;
}
@property --col-span {
syntax: "<integer>";
inherits: false;
initial-value: 2;
}
@layer reset {
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
}
:root {
font-family: "Roboto", sans-serif;
}
body {
background-color: var(--primary-bg-color);
color: var(--color);
padding-block-end: 5rem;
}
.actions {
display: flex;
justify-content: center;
align-items: center;
width: fit-content;
margin-inline: auto;
gap: 2rem;
}
.button {
margin-inline: auto;
margin-block: 2rem;
width: fit-content;
button {
appearance: none;
background-color: transparent;
color: var(--color);
border: solid 2px var(--color);
padding: 0.25rem 1rem;
cursor: pointer;
border-radius: 5px;
&:hover {
background-color: lch(from var(--color) calc(l - 25) c h / 25%);
}
&:active {
background-color: lch(from var(--color) calc(l - 5) c h / 34%);
}
}
}
.grid {
--grid-gap: 1.25rem;
width: 95cqw;
height: 90cqh;
padding: 1.5rem;
border: 3px solid lch(from var(--color) calc(l - 5) c h / 34%);
border-radius: 15px;
margin-block-end: 1rem;
margin-inline: auto;
display: grid;
grid-template-columns: repeat(var(--grid-cols), 1fr);
grid-template-rows: repeat(var(--grid-rows), 1fr);
gap: var(--grid-gap);
.grid-element {
width: 100%;
height: 100%;
background-color: lch(from var(--color) calc(l - 5) c h / 10%);
border-radius: 1rem;
display: block;
text-align: left;
align-content: flex-end;
padding: 1rem;
position: relative;
transition: background 0.5s ease, display 0.5s ease allow-discrete;
grid-row: span var(--row-span);
grid-column: span var(--col-span);
@starting-style {
background-color: transparent;
}
.drag-handle {
position: absolute;
right: 0;
bottom: 0;
width: 20px;
height: 20px;
background-color: var(--accent-color);
border-radius: 55px;
cursor: nwse-resize;
}
.content {
overflow: hidden;
display: box;
line-clamp: 1;
box-orient: vertical;
text-overflow: ellipsis;
}
}
}
@layer overrides {
baseline-status {
margin-inline: auto;
padding: 1rem 1rem 0 1rem;
}
}
function load() {
for (let i = 0; i < 12; i++) add();
}
function randomSize(min, max) {
return Math.round(Math.random(max) * (max - min) + min);
}
function add() {
const grid = document.querySelector("#grid .grid");
const div = document.createElement("div");
div.classList.add("grid-element");
div.classList.add("resizable");
div.style.setProperty("--col-span", randomSize(1, 4));
div.style.setProperty("--row-span", randomSize(1, 4));
const handle = document.createElement("div");
handle.classList.add("drag-handle");
const content = document.createElement("span");
content.classList.add("content");
content.textContent = (grid.childNodes.length + 1) + " - Lorem Ipsum";
addResizeCallback(handle, div, grid);
div.append(content, handle);
grid.appendChild(div);
}
function clearGrid() {
const grid = document.querySelector("#grid .grid");
[grid.childNodes].forEach((x) => x.remove());
}
function changeRows(e) {
const grid = document.querySelector("#grid .grid");
grid.style.setProperty("--grid-rows", e.value);
}
function changeCols(e) {
const grid = document.querySelector("#grid .grid");
grid.style.setProperty("--grid-cols", e.value);
}
function addResizeCallback(dragHandle, resizableItem, gridContainer) {
let startX, startY, startWidth, startHeight;
const columnNum = 0;
const colNum = gridContainer.style.getPropertyValue("--grid-cols");
const rowNum = gridContainer.style.getPropertyValue("--grid-rows");
const gridWidth = gridContainer.getBoundingClientRect();
const columnWidth = gridWidth.width / (colNum.length ? colNum : 12); // Assuming 12 columns
const rowHeight = gridWidth.height / (rowNum.length ? rowNum : 12); // Assuming 12 Rows
dragHandle.addEventListener("mousedown", (e) => {
e.preventDefault();
startX = e.clientX;
startY = e.clientY;
const itemRect = resizableItem.getBoundingClientRect();
const styles = window.getComputedStyle(resizableItem);
startWidth = Math.round(itemRect.width / columnWidth);
startHeight = Math.round(itemRect.height / rowHeight);
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
});
function handleMouseMove(e) {
const deltaX = e.clientX - startX;
const deltaY = e.clientY - startY;
const newSpanX = Math.max(
1,
Math.round((startWidth * columnWidth + deltaX) / columnWidth)
);
const newSpanY = Math.max(
1,
Math.round((startHeight * rowHeight + deltaY) / rowHeight)
);
resizeElement(dragHandle.parentElement, newSpanX, newSpanY);
}
function handleMouseUp() {
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
}
}
function resizeElement(elem, newSpanX, newSpanY) {
elem.style.setProperty("--col-span", newSpanX);
elem.style.setProperty("--row-span", newSpanY);
}
load();
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.