Макеты и Сеткиlayoutgridholygraildashboardstructure
Holy Grail Grid
Современная раскладка Holy Grail на CSS Grid для сложных порталов.
Живое превью
Использование
Скопируйте и вставьте этот код в ваш 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>Ручная установка
Если вы не используете пакет npm, создайте файл и вставьте следующий код: 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;
}
}Краткая информация
- Категория
- Макеты и Сетки
- Имя файла
HolyGrailGrid.tsx- Зависимости
- Нет — чистый React + CSS
- Теги
- layoutgridholygraildashboardstructure