1 estrella en GitHub = 1 componente nuevo.

Dar una estrella
Estructura & Layoutlayoutgridholygraildashboardstructure

Holy Grail Grid

Esquema moderno Holy Grail implementado sobre CSS Grid para layouts complejos.

Vista Previa en Vivo

Holy Grail Grid

Uso

Copia y pega este código directamente en tu componente React:

tsx
import { HolyGrailGrid } from 'react-component-kit-ui/layout';

<HolyGrailGrid><div slot="header">Header</div><div slot="left">Sidebar</div><div slot="main">Content</div><div slot="footer">Footer</div></HolyGrailGrid>

Instalación Manual

Si no estás usando el paquete npm, crea un archivo nuevo y pega el siguiente código: src/components/HolyGrailGrid.tsx + HolyGrailGrid.css:

HolyGrailGrid.tsx
'use client';

import type { CSSProperties, ReactNode } from 'react';
import './HolyGrailGrid.css';

/** class:list → className */
function cx(...args: unknown[]): string {
  const out: string[] = [];
  const walk = (v: unknown) => {
    if (!v) return;
    if (typeof v === 'string' || typeof v === 'number') out.push(String(v));
    else if (Array.isArray(v)) v.forEach(walk);
    else if (typeof v === 'object') for (const [k, on] of Object.entries(v as Record<string, unknown>)) if (on) out.push(k);
  };
  args.forEach(walk);
  return out.join(' ');
}

/** "a: b; --c: d" → style object */
function st(css: string | undefined): CSSProperties {
  const o: Record<string, string> = {};
  for (const decl of String(css ?? '').split(';')) {
    const i = decl.indexOf(':');
    if (i < 0) continue;
    const k = decl.slice(0, i).trim();
    if (k) o[k.startsWith('--') ? k : k.replace(/-([a-z])/g, (_, c) => c.toUpperCase())] = decl.slice(i + 1).trim();
  }
  return o as CSSProperties;
}

/**
 * HolyGrailGrid — Production-grade CSS grid layout container with sticky header, dual sidebars, fluid content, and footer.
 * 
 * @param {string} leftWidth - Left sidebar width. Default is '240px'.
 * @param {string} rightWidth - Right sidebar width. Default is '220px'.
 * @param {string} gap - Spacing gap between grid regions. Default is '1.5rem'.
 * @param {string} className - Optional CSS class.
 */
export interface HolyGrailGridProps {
  leftWidth?: string;
  rightWidth?: string;
  gap?: string;
  className?: string;
  children?: ReactNode;
  header?: ReactNode;
  left?: ReactNode;
  right?: ReactNode;
  footer?: ReactNode;
}

export function HolyGrailGrid({
  leftWidth = '240px',
  rightWidth = '220px',
  gap = '1.5rem',
  className = '',
  children,
  header,
  left,
  right,
  footer
}: HolyGrailGridProps) {
  return (
    <>
      <div className="cq-holy-grail-grid-cq" data-rk-7590db="">
      <div className={cx(['holy-grail', className])} style={st(`--hg-left: ${leftWidth}; --hg-right: ${rightWidth}; --hg-gap: ${gap};`)} data-rk-7590db="">
        <header className="holy-grail__header" data-rk-7590db="">
          {header}
        </header>
      
        <div className="holy-grail__middle" data-rk-7590db="">
          <aside className="holy-grail__left" data-rk-7590db="">
            {left}
          </aside>
      
          <main className="holy-grail__main" data-rk-7590db="">
            {children}
          </main>
      
          <aside className="holy-grail__right" data-rk-7590db="">
            {right}
          </aside>
        </div>
      
        <footer className="holy-grail__footer" data-rk-7590db="">
          {footer}
        </footer>
      </div>
      </div>
    </>
  );
}

export default HolyGrailGrid;
HolyGrailGrid.css
/* HolyGrailGrid — ported from astro-component-kit (layout/HolyGrailGrid.astro) */

.cq-holy-grail-grid-cq:where([data-rk-7590db]) { container-type: inline-size; }
.holy-grail:where([data-rk-7590db]) {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  width: 100%;
  color: var(--c-text-1, #ffffff);
  font-family: var(--font-sans, system-ui, sans-serif);
}

.holy-grail__header:where([data-rk-7590db]) {
  width: 100%;
  padding: var(--sp-4, 1rem) var(--sp-6, 1.5rem);
  background: rgba(10, 10, 14, 0.8);
  backdrop-filter: blur(16px);
  border-bottom: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
}

.holy-grail__middle:where([data-rk-7590db]) {
  display: grid;
  grid-template-columns: var(--hg-left) 1fr var(--hg-right);
  gap: var(--hg-gap);
  flex: 1;
  max-width: 1440px;
  margin: 0 auto;
  width: 100%;
  padding: var(--sp-6, 1.5rem);
}

.holy-grail__left:where([data-rk-7590db]),
.holy-grail__right:where([data-rk-7590db]) {
  padding: var(--sp-4, 1rem);
  background: rgb(var(--ink-rgb, 255 255 255) / 0.02);
  border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.06);
  border-radius: var(--r-lg, 16px);
  height: fit-content;
  position: sticky;
  top: 2rem;
}

.holy-grail__main:where([data-rk-7590db]) {
  padding: var(--sp-6, 1.5rem);
  background: rgb(var(--ink-rgb, 255 255 255) / 0.015);
  border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.06);
  border-radius: var(--r-lg, 16px);
  min-height: 400px;
}

.holy-grail__footer:where([data-rk-7590db]) {
  width: 100%;
  padding: var(--sp-6, 1.5rem);
  background: rgba(10, 10, 14, 0.9);
  border-top: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
  margin-top: auto;
}

@container (max-width: 1024px) {
  .holy-grail__middle:where([data-rk-7590db]) {
    grid-template-columns: var(--hg-left) 1fr;
  }
  .holy-grail__right:where([data-rk-7590db]) {
    display: none;
  }
}

@container (max-width: 768px) {
  .holy-grail__middle:where([data-rk-7590db]) {
    grid-template-columns: 1fr;
  }
  .holy-grail__left:where([data-rk-7590db]) {
    position: static;
  }
}

Información Rápida

Categoría
Estructura & Layout
Nombre de archivo
HolyGrailGrid.tsx
Dependencias
Ninguna — React + CSS puro
Etiquetas
layoutgridholygraildashboardstructure