Created
August 17, 2026 07:42
-
-
Save luisramirezdev/43c16f9c766f48ca1fbf242da9311f86 to your computer and use it in GitHub Desktop.
gridstack canvas demo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>gridstack canvas demo — click "Edit" to see the grid</title> | |
| <!-- gridstack from CDN (v13, latest) --> | |
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gridstack@13.0.2/dist/gridstack.min.css" /> | |
| <script src="https://cdn.jsdelivr.net/npm/gridstack@13.0.2/dist/gridstack-all.js"></script> | |
| <style> | |
| * { box-sizing: border-box; } | |
| body { | |
| margin: 0; | |
| font-family: system-ui, sans-serif; | |
| background: #0a0a0a; | |
| color: #e4e4e7; | |
| } | |
| /* Toolbar */ | |
| .bar { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| padding: 10px 16px; | |
| background: #18181b; | |
| border-bottom: 1px solid #27272a; | |
| font-size: 14px; | |
| } | |
| .bar button { | |
| padding: 6px 14px; | |
| border: 1px solid #3f3f46; | |
| border-radius: 8px; | |
| background: #27272a; | |
| color: #e4e4e7; | |
| cursor: pointer; | |
| font-size: 14px; | |
| } | |
| .bar button:hover { background: #3f3f46; } | |
| .bar button.active { background: #16a34a; border-color: #16a34a; color: #fff; } | |
| .hint { color: #a1a1aa; font-size: 13px; } | |
| /* The grid container — fills the window. minRow forces a full canvas. */ | |
| .wrap { | |
| height: calc(100vh - 49px); | |
| overflow: auto; | |
| padding: 12px; | |
| } | |
| .grid-stack { | |
| /* THE CANVAS: draw the cell grid aligned to gridstack's live CSS vars. | |
| Two repeating-linear-gradients (vertical + horizontal lines) sized | |
| by --gs-column-width / --gs-cell-height. When gridstack recalculates | |
| those vars, the background follows automatically. */ | |
| background-image: | |
| repeating-linear-gradient( | |
| to right, | |
| rgba(255, 255, 255, 0.06) 0, | |
| rgba(255, 255, 255, 0.06) calc(var(--gs-column-width) - 1px), | |
| transparent calc(var(--gs-column-width) - 1px), | |
| transparent var(--gs-column-width) | |
| ), | |
| repeating-linear-gradient( | |
| to bottom, | |
| rgba(255, 255, 255, 0.06) 0, | |
| rgba(255, 255, 255, 0.06) calc(var(--gs-cell-height) - 1px), | |
| transparent calc(var(--gs-cell-height) - 1px), | |
| transparent var(--gs-cell-height) | |
| ); | |
| } | |
| /* Show the canvas lines more strongly while editing */ | |
| .grid-stack.editing { | |
| background-image: | |
| repeating-linear-gradient( | |
| to right, | |
| rgba(255, 255, 255, 0.14) 0, | |
| rgba(255, 255, 255, 0.14) calc(var(--gs-column-width) - 1px), | |
| transparent calc(var(--gs-column-width) - 1px), | |
| transparent var(--gs-column-width) | |
| ), | |
| repeating-linear-gradient( | |
| to bottom, | |
| rgba(255, 255, 255, 0.14) 0, | |
| rgba(255, 255, 255, 0.14) calc(var(--gs-cell-height) - 1px), | |
| transparent calc(var(--gs-cell-height) - 1px), | |
| transparent var(--gs-cell-height) | |
| ); | |
| } | |
| /* Widget cards */ | |
| .grid-stack-item-content { | |
| border-radius: 12px; | |
| border: 1px solid #3f3f46; | |
| background: #18181b; | |
| padding: 14px; | |
| font-size: 13px; | |
| color: #a1a1aa; | |
| } | |
| .grid-stack-item-content strong { | |
| display: block; | |
| color: #fafafa; | |
| font-size: 15px; | |
| margin-bottom: 4px; | |
| } | |
| .grid-stack-item[gs-id="a"] .grid-stack-item-content { background: #1c1917; } | |
| .grid-stack-item[gs-id="b"] .grid-stack-item-content { background: #1a2e05; } | |
| .grid-stack-item[gs-id="c"] .grid-stack-item-content { background: #082032; } | |
| .grid-stack-item[gs-id="d"] .grid-stack-item-content { background: #2d1a05; } | |
| .grid-stack-item[gs-id="e"] .grid-stack-item-content { background: #160d2d; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="bar"> | |
| <button id="toggle-edit">✏️ Edit</button> | |
| <span class="hint">Arrastra los widgets · redimensiona desde la esquina · observa el lienzo de celdas</span> | |
| </div> | |
| <div class="wrap"> | |
| <!-- minRow: el lienzo SIEMPRE ocupa toda la ventana aunque haya pocos widgets --> | |
| <div class="grid-stack" id="grid"></div> | |
| </div> | |
| <script> | |
| const WIDGETS = [ | |
| { id: 'a', w: 6, h: 4, title: 'Stint Planner', body: 'Parar ahora / Estirar 3 vueltas / Estirar al máximo' }, | |
| { id: 'b', w: 6, h: 4, title: 'Weather', body: '21°C aire · 34°C pista · viento 2.3 m/s' }, | |
| { id: 'c', w: 6, h: 4, title: 'Forecast', body: 'START → NODE 25 → NODE 50 → NODE 75 → FINISH' }, | |
| { id: 'd', w: 3, h: 4, title: 'Damage', body: 'Aero 12% · Body 37% · Susp 50%' }, | |
| { id: 'e', w: 3, h: 4, title: 'Pit Stop', body: 'Damage +2.1s · Fuel +8.4s · Total +14.2s' } | |
| ]; | |
| const grid = GridStack.init({ | |
| column: 12, | |
| cellHeight: 60, | |
| margin: 8, | |
| float: false, // compaction: sin huecos | |
| minRow: 10, // lienzo siempre presente | |
| staticGrid: true, // read-only hasta pulsar Edit | |
| resizable: { handles: 'se', autoHide: true } | |
| }, document.getElementById('grid')); | |
| for (const w of WIDGETS) { | |
| grid.addWidget({ | |
| id: w.id, | |
| w: w.w, | |
| h: w.h, | |
| content: `<strong>${w.title}</strong>${w.body}` | |
| }); | |
| } | |
| grid.compact(); | |
| // Toggle edit: muestra el lienzo + habilita drag/resize | |
| const btn = document.getElementById('toggle-edit'); | |
| let editing = false; | |
| btn.addEventListener('click', () => { | |
| editing = !editing; | |
| btn.textContent = editing ? '✔ Done' : '✏️ Edit'; | |
| btn.classList.toggle('active', editing); | |
| document.getElementById('grid').classList.toggle('editing', editing); | |
| grid.setStatic(!editing); | |
| }); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment