← Components/Layouts

GridLayout

gridlayout-1779379671739.tsx
'use client'
import { useState } from 'react'

interface Block {
  id: number
  label: string
  color: string
  colSpan: number
  rowSpan: number
}

const INITIAL: Block[] = [
  { id: 1, label: 'Header', color: '#C9A84C', colSpan: 12, rowSpan: 1 },
  { id: 2, label: 'Sidebar', color: '#6366f1', colSpan: 3, rowSpan: 3 },
  { id: 3, label: 'Main Content', color: '#22c55e', colSpan: 9, rowSpan: 2 },
  { id: 4, label: 'Aside', color: '#f59e0b', colSpan: 9, rowSpan: 1 },
  { id: 5, label: 'Footer', color: '#ef4444', colSpan: 12, rowSpan: 1 },
]

export default function GridLayout() {
  const [blocks, setBlocks] = useState(INITIAL)
  const [selected, setSelected] = useState<number | null>(1)

  const sel = blocks.find(b => b.id === selected)

  function update(id: number, key: keyof Block, val: number) {
    setBlocks(bs => bs.map(b => b.id === id ? { ...b, [key]: Math.max(1, Math.min(key === 'colSpan' ? 12 : 4, val)) } : b))
  }

  const code = blocks.map(b => `<div style={{ gridColumn: 'span ${b.colSpan}', gridRow: 'span ${b.rowSpan}' }}>
  {/* ${b.label} */}
</div>`).join('\n')

  return (
    <div style={{ background: '#0A0A0A', padding: 24, display: 'flex', flexDirection: 'column', gap: 20 }}>
      {/* Controls */}
      {sel && (
        <div style={{ display: 'flex', gap: 12, alignItems: 'center', flexWrap: 'wrap' }}>
          <span style={{ color: sel.color, fontSize: 13, fontWeight: 700 }}>{sel.label}</span>
          {(['colSpan', 'rowSpan'] as const).map(key => (
            <div key={key} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <span style={{ color: 'rgba(255,255,255,0.4)', fontSize: 12 }}>{key === 'colSpan' ? 'Cols' : 'Rows'}:</span>
              <button onClick={() => update(sel.id, key, sel[key] - 1)} style={{ width: 24, height: 24, borderRadius: 5, border: '1px solid rgba(255,255,255,0.1)', background: 'rgba(255,255,255,0.06)', color: '#F5F5F0', cursor: 'pointer', fontSize: 14 }}>−</button>
              <span style={{ color: '#F5F5F0', fontSize: 13, minWidth: 16, textAlign: 'center' }}>{sel[key]}</span>
              <button onClick={() => update(sel.id, key, sel[key] + 1)} style={{ width: 24, height: 24, borderRadius: 5, border: '1px solid rgba(255,255,255,0.1)', background: 'rgba(255,255,255,0.06)', color: '#F5F5F0', cursor: 'pointer', fontSize: 14 }}>+</button>
            </div>
          ))}
        </div>
      )}

      {/* Grid preview */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(12, 1fr)', gridAutoRows: '50px', gap: 6 }}>
        {blocks.map(b => (
          <div key={b.id} onClick={() => setSelected(b.id)}
            style={{ gridColumn: `span ${b.colSpan}`, gridRow: `span ${b.rowSpan}`, background: b.color + (selected === b.id ? '30' : '15'), border: `1.5px solid ${b.color}${selected === b.id ? '' : '60'}`, borderRadius: 8, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', transition: 'all 0.15s' }}>
            <span style={{ color: b.color, fontSize: 12, fontWeight: 600 }}>{b.label} ({b.colSpan}×{b.rowSpan})</span>
          </div>
        ))}
      </div>

      {/* Code output */}
      <div style={{ background: '#111', border: '1px solid rgba(255,255,255,0.06)', borderRadius: 10, padding: 14, fontSize: 11, fontFamily: 'monospace', color: 'rgba(255,255,255,0.5)', overflowX: 'auto', whiteSpace: 'pre' }}>
        {code}
      </div>
    </div>
  )
}

Component info

CategoryLayouts
Frameworkreact
TierFREE
Views0
Copies0

About

Responsive CSS grid layout editor with drag reorder, span controls, and code export

More from Layouts

'use client'
import { useState, useRef, useCallback, useEffect } from 'react'

export default function SplitPane() {
  const [split, setSplit] = useState(50)
  const [dragging, setDragging] = useState(false)
  const [collapsed, setCollapsed] = useSta
SplitPane
Layouts