872 lines
20 KiB
Markdown
872 lines
20 KiB
Markdown
# HLCRF Layout System
|
|
|
|
HLCRF (Header-Left-Content-Right-Footer) is a hierarchical, composable layout system for building complex layouts with infinite nesting. It provides flexible region-based layouts without restricting HTML structure.
|
|
|
|
## Overview
|
|
|
|
Traditional Blade layouts force rigid inheritance hierarchies. HLCRF allows components to declare which layout regions they contribute to, enabling composition without structural constraints.
|
|
|
|
**Use Cases:**
|
|
- Admin panels and dashboards
|
|
- Content management interfaces
|
|
- Marketing landing pages
|
|
- E-commerce product pages
|
|
- Documentation sites
|
|
- Any complex multi-region layout
|
|
|
|
### Traditional Blade Layouts
|
|
|
|
```blade
|
|
{{-- layouts/admin.blade.php --}}
|
|
<html>
|
|
<body>
|
|
<header>@yield('header')</header>
|
|
<aside>@yield('sidebar')</aside>
|
|
<main>@yield('content')</main>
|
|
</body>
|
|
</html>
|
|
|
|
{{-- pages/dashboard.blade.php --}}
|
|
@extends('layouts.admin')
|
|
|
|
@section('header')
|
|
Dashboard Header
|
|
@endsection
|
|
|
|
@section('content')
|
|
Dashboard Content
|
|
@endsection
|
|
```
|
|
|
|
**Problems:**
|
|
- Rigid structure
|
|
- Deep nesting
|
|
- Hard to compose sections
|
|
- Components can't contribute to multiple regions
|
|
|
|
### HLCRF Approach
|
|
|
|
```blade
|
|
{{-- pages/dashboard.blade.php --}}
|
|
<x-hlcrf::layout>
|
|
<x-hlcrf::header>
|
|
Dashboard Header
|
|
</x-hlcrf::header>
|
|
|
|
<x-hlcrf::left>
|
|
Navigation Menu
|
|
</x-hlcrf::left>
|
|
|
|
<x-hlcrf::content>
|
|
Dashboard Content
|
|
</x-hlcrf::content>
|
|
|
|
<x-hlcrf::right>
|
|
Sidebar Widgets
|
|
</x-hlcrf::right>
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
**Benefits:**
|
|
- Declarative region definition
|
|
- Easy composition
|
|
- Components contribute to any region
|
|
- No structural constraints
|
|
|
|
## Layout Regions
|
|
|
|
HLCRF defines five semantic regions:
|
|
|
|
```
|
|
┌────────────────────────────────────┐
|
|
│ Header (H) │
|
|
├──────┬─────────────────┬───────────┤
|
|
│ │ │ │
|
|
│ Left │ Content (C) │ Right │
|
|
│ (L) │ │ (R) │
|
|
│ │ │ │
|
|
├──────┴─────────────────┴───────────┤
|
|
│ Footer (F) │
|
|
└────────────────────────────────────┘
|
|
```
|
|
|
|
### Self-Documenting IDs
|
|
|
|
Every HLCRF element receives a unique ID that describes its position in the DOM tree. This makes debugging, styling, and testing trivial:
|
|
|
|
**ID Format:** `{Region}-{Index}-{NestedRegion}-{NestedIndex}...`
|
|
|
|
**Examples:**
|
|
- `H-0` = First header element
|
|
- `L-1` = Second left sidebar element (0-indexed)
|
|
- `C-R-2` = Content region → Right sidebar → Third element
|
|
- `C-L-0-R-1` = Content → Left → First element → Right → Second element
|
|
|
|
**Region Letters:**
|
|
- `H` = Header
|
|
- `L` = Left
|
|
- `C` = Content
|
|
- `R` = Right
|
|
- `F` = Footer
|
|
|
|
**Benefits:**
|
|
1. **Instant debugging** - See element position from DevTools
|
|
2. **Precise CSS targeting** - No class soup needed
|
|
3. **Test selectors** - Stable IDs for E2E tests
|
|
4. **Documentation** - DOM structure is self-explanatory
|
|
|
|
```html
|
|
<!-- Real-world example -->
|
|
<div id="H-0" class="hlcrf-header">
|
|
<nav>Global Navigation</nav>
|
|
</div>
|
|
|
|
<div id="C-0" class="hlcrf-content">
|
|
<div id="C-L-0" class="hlcrf-left">
|
|
<!-- This is: Content → Left → First element -->
|
|
<aside>Sidebar</aside>
|
|
</div>
|
|
|
|
<div id="C-C-0" class="hlcrf-content">
|
|
<!-- This is: Content → Content (nested) → First element -->
|
|
<article>Main content</article>
|
|
</div>
|
|
|
|
<div id="C-R-0" class="hlcrf-right">
|
|
<!-- This is: Content → Right → First element -->
|
|
<aside>Widgets</aside>
|
|
</div>
|
|
</div>
|
|
```
|
|
|
|
**CSS Examples:**
|
|
|
|
```css
|
|
/* Target specific nested elements */
|
|
#C-R-2 { width: 300px; }
|
|
|
|
/* Target all right sidebars at any depth */
|
|
[id$="-R-0"] { background: #f9f9f9; }
|
|
|
|
/* Target deeply nested content regions */
|
|
[id*="-C-"][id*="-C-"] { padding: 2rem; }
|
|
|
|
/* Target second header element anywhere */
|
|
[id^="H-1"], [id*="-H-1"] { font-weight: bold; }
|
|
```
|
|
|
|
### Header Region
|
|
|
|
Top section for navigation, branding, global actions:
|
|
|
|
```blade
|
|
<x-hlcrf::header>
|
|
<nav class="flex items-center justify-between">
|
|
<div class="logo">
|
|
<img src="/logo.png" alt="Logo">
|
|
</div>
|
|
|
|
<div class="nav-links">
|
|
<a href="/dashboard">Dashboard</a>
|
|
<a href="/settings">Settings</a>
|
|
</div>
|
|
|
|
<div class="user-menu">
|
|
<x-user-dropdown />
|
|
</div>
|
|
</nav>
|
|
</x-hlcrf::header>
|
|
```
|
|
|
|
### Left Region
|
|
|
|
Sidebar navigation, filters, secondary navigation:
|
|
|
|
```blade
|
|
<x-hlcrf::left>
|
|
<aside class="w-64">
|
|
<nav class="space-y-2">
|
|
<a href="/posts" class="block px-4 py-2">Posts</a>
|
|
<a href="/categories" class="block px-4 py-2">Categories</a>
|
|
<a href="/tags" class="block px-4 py-2">Tags</a>
|
|
</nav>
|
|
</aside>
|
|
</x-hlcrf::left>
|
|
```
|
|
|
|
### Content Region
|
|
|
|
Main content area:
|
|
|
|
```blade
|
|
<x-hlcrf::content>
|
|
<div class="container mx-auto">
|
|
<h1>Dashboard</h1>
|
|
|
|
<div class="grid grid-cols-3 gap-4">
|
|
<x-stat-card title="Posts" :value="$postCount" />
|
|
<x-stat-card title="Users" :value="$userCount" />
|
|
<x-stat-card title="Comments" :value="$commentCount" />
|
|
</div>
|
|
|
|
<div class="mt-8">
|
|
<x-recent-activity :activities="$activities" />
|
|
</div>
|
|
</div>
|
|
</x-hlcrf::content>
|
|
```
|
|
|
|
### Right Region
|
|
|
|
Contextual help, related actions, widgets:
|
|
|
|
```blade
|
|
<x-hlcrf::right>
|
|
<aside class="w-80 space-y-4">
|
|
<x-help-widget>
|
|
<h3>Getting Started</h3>
|
|
<p>Learn how to create your first post...</p>
|
|
</x-help-widget>
|
|
|
|
<x-quick-actions-widget>
|
|
<x-button href="/posts/create">New Post</x-button>
|
|
<x-button href="/categories/create">New Category</x-button>
|
|
</x-quick-actions-widget>
|
|
</aside>
|
|
</x-hlcrf::right>
|
|
```
|
|
|
|
### Footer Region
|
|
|
|
Copyright, links, status information:
|
|
|
|
```blade
|
|
<x-hlcrf::footer>
|
|
<footer class="text-center text-sm text-gray-600">
|
|
© 2026 Your Company. All rights reserved.
|
|
<span class="mx-2">|</span>
|
|
<a href="/privacy">Privacy</a>
|
|
<span class="mx-2">|</span>
|
|
<a href="/terms">Terms</a>
|
|
</footer>
|
|
</x-hlcrf::footer>
|
|
```
|
|
|
|
## Component Composition
|
|
|
|
### Multiple Components Contributing
|
|
|
|
Components can contribute to multiple regions:
|
|
|
|
```blade
|
|
<x-hlcrf::layout>
|
|
{{-- Page header --}}
|
|
<x-hlcrf::header>
|
|
<x-page-header title="Blog Posts" />
|
|
</x-hlcrf::header>
|
|
|
|
{{-- Filters sidebar --}}
|
|
<x-hlcrf::left>
|
|
<x-post-filters />
|
|
</x-hlcrf::left>
|
|
|
|
{{-- Main content --}}
|
|
<x-hlcrf::content>
|
|
<x-post-list :posts="$posts" />
|
|
</x-hlcrf::content>
|
|
|
|
{{-- Help sidebar --}}
|
|
<x-hlcrf::right>
|
|
<x-post-help />
|
|
<x-post-stats :posts="$posts" />
|
|
</x-hlcrf::right>
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
### Nested Layouts
|
|
|
|
HLCRF layouts can be nested infinitely. Each element receives a unique, self-documenting ID that describes its position in the DOM tree:
|
|
|
|
```blade
|
|
{{-- components/post-editor.blade.php --}}
|
|
<div class="post-editor">
|
|
{{-- Nested HLCRF layout inside a parent layout --}}
|
|
<x-hlcrf::layout>
|
|
{{-- Editor toolbar goes to header --}}
|
|
<x-hlcrf::header>
|
|
<x-editor-toolbar />
|
|
</x-hlcrf::header>
|
|
|
|
{{-- Content editor --}}
|
|
<x-hlcrf::content>
|
|
<textarea name="content">{{ $post->content }}</textarea>
|
|
</x-hlcrf::content>
|
|
|
|
{{-- Metadata sidebar --}}
|
|
<x-hlcrf::right>
|
|
<x-post-metadata :post="$post" />
|
|
</x-hlcrf::right>
|
|
</x-hlcrf::layout>
|
|
</div>
|
|
```
|
|
|
|
**Generated IDs:**
|
|
```html
|
|
<div id="H-0"><!-- First Header element --></div>
|
|
<div id="L-0"><!-- First Left element --></div>
|
|
<div id="C-0"><!-- First Content element --></div>
|
|
<div id="C-R-2"><!-- Content → Right, 3rd element (0-indexed: 2) --></div>
|
|
<div id="C-L-0-R-1"><!-- Content → Left → First → Right → Second --></div>
|
|
```
|
|
|
|
The ID format follows the pattern:
|
|
- Single letter = region type (`H`=Header, `L`=Left, `C`=Content, `R`=Right, `F`=Footer)
|
|
- Number = index within that region (0-based)
|
|
- Dash separates nesting levels
|
|
|
|
This makes the DOM structure self-documenting and enables precise CSS targeting:
|
|
|
|
```css
|
|
/* Target all right sidebars at any nesting level */
|
|
[id$="-R-0"] { /* ... */ }
|
|
|
|
/* Target deeply nested content areas */
|
|
[id^="C-"][id*="-C-"] { /* ... */ }
|
|
|
|
/* Target second element in any header */
|
|
[id^="H-1"] { /* ... */ }
|
|
```
|
|
|
|
## Layout Variants
|
|
|
|
### Two-Column Layout
|
|
|
|
```blade
|
|
<x-hlcrf::layout variant="two-column">
|
|
<x-hlcrf::left>
|
|
Navigation
|
|
</x-hlcrf::left>
|
|
|
|
<x-hlcrf::content>
|
|
Main Content
|
|
</x-hlcrf::content>
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
### Three-Column Layout
|
|
|
|
```blade
|
|
<x-hlcrf::layout variant="three-column">
|
|
<x-hlcrf::left>
|
|
Left Sidebar
|
|
</x-hlcrf::left>
|
|
|
|
<x-hlcrf::content>
|
|
Main Content
|
|
</x-hlcrf::content>
|
|
|
|
<x-hlcrf::right>
|
|
Right Sidebar
|
|
</x-hlcrf::right>
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
### Full-Width Layout
|
|
|
|
```blade
|
|
<x-hlcrf::layout variant="full-width">
|
|
<x-hlcrf::header>
|
|
Header
|
|
</x-hlcrf::header>
|
|
|
|
<x-hlcrf::content>
|
|
Full-Width Content
|
|
</x-hlcrf::content>
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
### Modal Layout
|
|
|
|
```blade
|
|
<x-hlcrf::layout variant="modal">
|
|
<x-hlcrf::header>
|
|
<h2>Edit Post</h2>
|
|
</x-hlcrf::header>
|
|
|
|
<x-hlcrf::content>
|
|
<form>...</form>
|
|
</x-hlcrf::content>
|
|
|
|
<x-hlcrf::footer>
|
|
<x-button type="submit">Save</x-button>
|
|
<x-button variant="secondary" @click="close">Cancel</x-button>
|
|
</x-hlcrf::footer>
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
## Responsive Behavior
|
|
|
|
HLCRF layouts adapt to screen size:
|
|
|
|
```blade
|
|
<x-hlcrf::layout
|
|
:breakpoints="[
|
|
'mobile' => 'stack', // Stack regions on mobile
|
|
'tablet' => 'two-column', // Two columns on tablet
|
|
'desktop' => 'three-column', // Three columns on desktop
|
|
]"
|
|
>
|
|
<x-hlcrf::left>Sidebar</x-hlcrf::left>
|
|
<x-hlcrf::content>Content</x-hlcrf::content>
|
|
<x-hlcrf::right>Widgets</x-hlcrf::right>
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
**Result:**
|
|
- **Mobile:** Left → Content → Right (stacked vertically)
|
|
- **Tablet:** Left | Content (side-by-side)
|
|
- **Desktop:** Left | Content | Right (three columns)
|
|
|
|
## Region Options
|
|
|
|
### Collapsible Regions
|
|
|
|
```blade
|
|
<x-hlcrf::left collapsible="true" collapsed="false">
|
|
Navigation Menu
|
|
</x-hlcrf::left>
|
|
```
|
|
|
|
### Fixed Regions
|
|
|
|
```blade
|
|
<x-hlcrf::header fixed="true">
|
|
Sticky Header
|
|
</x-hlcrf::header>
|
|
```
|
|
|
|
### Scrollable Regions
|
|
|
|
```blade
|
|
<x-hlcrf::content scrollable="true" max-height="600px">
|
|
Long Content
|
|
</x-hlcrf::content>
|
|
```
|
|
|
|
### Region Width
|
|
|
|
```blade
|
|
<x-hlcrf::left width="250px">
|
|
Fixed width sidebar
|
|
</x-hlcrf::left>
|
|
|
|
<x-hlcrf::right width="25%">
|
|
Percentage width sidebar
|
|
</x-hlcrf::right>
|
|
```
|
|
|
|
## Conditional Regions
|
|
|
|
### Show/Hide Based on Conditions
|
|
|
|
```blade
|
|
<x-hlcrf::layout>
|
|
@auth
|
|
<x-hlcrf::header>
|
|
<x-user-nav />
|
|
</x-hlcrf::header>
|
|
@endauth
|
|
|
|
<x-hlcrf::content>
|
|
Main Content
|
|
</x-hlcrf::content>
|
|
|
|
@can('view-admin-sidebar')
|
|
<x-hlcrf::right>
|
|
<x-admin-widgets />
|
|
</x-hlcrf::right>
|
|
@endcan
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
### Feature Flags
|
|
|
|
```blade
|
|
<x-hlcrf::layout>
|
|
<x-hlcrf::content>
|
|
Content
|
|
</x-hlcrf::content>
|
|
|
|
@feature('advanced-analytics')
|
|
<x-hlcrf::right>
|
|
<x-analytics-widgets />
|
|
</x-hlcrf::right>
|
|
@endfeature
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
## Styling
|
|
|
|
### Custom Classes
|
|
|
|
```blade
|
|
<x-hlcrf::layout class="min-h-screen bg-gray-50">
|
|
<x-hlcrf::header class="bg-white shadow">
|
|
Header
|
|
</x-hlcrf::header>
|
|
|
|
<x-hlcrf::content class="max-w-7xl mx-auto py-6">
|
|
Content
|
|
</x-hlcrf::content>
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
### Slot Attributes
|
|
|
|
```blade
|
|
<x-hlcrf::left
|
|
class="bg-gray-900 text-white"
|
|
width="256px"
|
|
>
|
|
Dark Sidebar
|
|
</x-hlcrf::left>
|
|
```
|
|
|
|
## Real-World Examples
|
|
|
|
### Marketing Landing Page
|
|
|
|
```blade
|
|
<x-hlcrf::layout>
|
|
{{-- Sticky header with CTA --}}
|
|
<x-hlcrf::header fixed="true">
|
|
<nav>
|
|
<x-logo />
|
|
<x-nav-links />
|
|
<x-cta-button>Get Started</x-cta-button>
|
|
</nav>
|
|
</x-hlcrf::header>
|
|
|
|
{{-- Hero section with sidebar --}}
|
|
<x-hlcrf::content>
|
|
<x-hlcrf::layout>
|
|
<x-hlcrf::content>
|
|
<x-hero-section />
|
|
</x-hlcrf::content>
|
|
|
|
<x-hlcrf::right>
|
|
<x-trust-badges />
|
|
<x-testimonial />
|
|
</x-hlcrf::right>
|
|
</x-hlcrf::layout>
|
|
</x-hlcrf::content>
|
|
|
|
{{-- Footer with newsletter --}}
|
|
<x-hlcrf::footer>
|
|
<x-hlcrf::layout>
|
|
<x-hlcrf::left>
|
|
<x-footer-nav />
|
|
</x-hlcrf::left>
|
|
|
|
<x-hlcrf::content>
|
|
<x-newsletter-signup />
|
|
</x-hlcrf::content>
|
|
</x-hlcrf::layout>
|
|
</x-hlcrf::footer>
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
### E-Commerce Product Page
|
|
|
|
```blade
|
|
<x-hlcrf::layout>
|
|
<x-hlcrf::header>
|
|
<x-store-header />
|
|
</x-hlcrf::header>
|
|
|
|
<x-hlcrf::content>
|
|
<x-hlcrf::layout>
|
|
{{-- Product images --}}
|
|
<x-hlcrf::left width="60%">
|
|
<x-product-gallery :images="$product->images" />
|
|
</x-hlcrf::left>
|
|
|
|
{{-- Product details and buy box --}}
|
|
<x-hlcrf::right width="40%">
|
|
<x-product-info :product="$product" />
|
|
<x-buy-box :product="$product" />
|
|
<x-delivery-info />
|
|
</x-hlcrf::right>
|
|
</x-hlcrf::layout>
|
|
|
|
{{-- Reviews and recommendations --}}
|
|
<x-hlcrf::layout>
|
|
<x-hlcrf::content>
|
|
<x-product-reviews :product="$product" />
|
|
</x-hlcrf::content>
|
|
|
|
<x-hlcrf::right>
|
|
<x-recommended-products :product="$product" />
|
|
</x-hlcrf::right>
|
|
</x-hlcrf::layout>
|
|
</x-hlcrf::content>
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
### Blog with Ads
|
|
|
|
```blade
|
|
<x-hlcrf::layout>
|
|
<x-hlcrf::header>
|
|
<x-blog-header />
|
|
</x-hlcrf::header>
|
|
|
|
<x-hlcrf::content>
|
|
<x-hlcrf::layout>
|
|
{{-- Sidebar navigation --}}
|
|
<x-hlcrf::left width="250px">
|
|
<x-category-nav />
|
|
<x-ad-slot position="sidebar-top" />
|
|
</x-hlcrf::left>
|
|
|
|
{{-- Article content --}}
|
|
<x-hlcrf::content>
|
|
<article>
|
|
<h1>{{ $post->title }}</h1>
|
|
<x-ad-slot position="article-top" />
|
|
{!! $post->content !!}
|
|
<x-ad-slot position="article-bottom" />
|
|
</article>
|
|
|
|
<x-comments :post="$post" />
|
|
</x-hlcrf::content>
|
|
|
|
{{-- Widgets and ads --}}
|
|
<x-hlcrf::right width="300px">
|
|
<x-ad-slot position="sidebar-right-1" />
|
|
<x-popular-posts />
|
|
<x-ad-slot position="sidebar-right-2" />
|
|
<x-newsletter-widget />
|
|
</x-hlcrf::right>
|
|
</x-hlcrf::layout>
|
|
</x-hlcrf::content>
|
|
|
|
<x-hlcrf::footer>
|
|
<x-blog-footer />
|
|
</x-hlcrf::footer>
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
## Advanced Patterns
|
|
|
|
### Dynamic Region Loading
|
|
|
|
```blade
|
|
<x-hlcrf::layout>
|
|
<x-hlcrf::content>
|
|
Main Content
|
|
</x-hlcrf::content>
|
|
|
|
<x-hlcrf::right>
|
|
{{-- Load widgets based on page --}}
|
|
@foreach($widgets as $widget)
|
|
@include("widgets.{$widget}")
|
|
@endforeach
|
|
</x-hlcrf::right>
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
### Livewire Integration
|
|
|
|
```blade
|
|
<x-hlcrf::layout>
|
|
<x-hlcrf::header>
|
|
@livewire('global-search')
|
|
</x-hlcrf::header>
|
|
|
|
<x-hlcrf::content>
|
|
@livewire('post-list')
|
|
</x-hlcrf::content>
|
|
|
|
<x-hlcrf::right>
|
|
@livewire('post-filters')
|
|
</x-hlcrf::right>
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
### Portal Teleportation
|
|
|
|
Send content to regions from anywhere:
|
|
|
|
```blade
|
|
{{-- Page content --}}
|
|
<x-hlcrf::content>
|
|
<h1>My Page</h1>
|
|
|
|
{{-- Component that teleports to header --}}
|
|
<x-page-actions>
|
|
<x-button>Action 1</x-button>
|
|
<x-button>Action 2</x-button>
|
|
</x-page-actions>
|
|
</x-hlcrf::content>
|
|
|
|
{{-- page-actions.blade.php component --}}
|
|
<x-hlcrf::portal target="header-actions">
|
|
{{ $slot }}
|
|
</x-hlcrf::portal>
|
|
```
|
|
|
|
## Implementation
|
|
|
|
### Layout Component
|
|
|
|
```php
|
|
<?php
|
|
|
|
namespace Core\Front\Components\View\Components;
|
|
|
|
use Illuminate\View\Component;
|
|
|
|
class HlcrfLayout extends Component
|
|
{
|
|
public function __construct(
|
|
public ?string $variant = 'three-column',
|
|
public array $breakpoints = [],
|
|
) {}
|
|
|
|
public function render()
|
|
{
|
|
return view('components.hlcrf.layout');
|
|
}
|
|
}
|
|
```
|
|
|
|
### Layout View
|
|
|
|
```blade
|
|
{{-- components/hlcrf/layout.blade.php --}}
|
|
<div class="hlcrf-layout hlcrf-variant-{{ $variant }}">
|
|
@if($header ?? false)
|
|
<div class="hlcrf-region hlcrf-header">
|
|
{{ $header }}
|
|
</div>
|
|
@endif
|
|
|
|
<div class="hlcrf-main">
|
|
@if($left ?? false)
|
|
<div class="hlcrf-region hlcrf-left">
|
|
{{ $left }}
|
|
</div>
|
|
@endif
|
|
|
|
<div class="hlcrf-region hlcrf-content">
|
|
{{ $content ?? $slot }}
|
|
</div>
|
|
|
|
@if($right ?? false)
|
|
<div class="hlcrf-region hlcrf-right">
|
|
{{ $right }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
@if($footer ?? false)
|
|
<div class="hlcrf-region hlcrf-footer">
|
|
{{ $footer }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
```
|
|
|
|
## Testing
|
|
|
|
### Component Testing
|
|
|
|
```php
|
|
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use Tests\TestCase;
|
|
|
|
class HlcrfLayoutTest extends TestCase
|
|
{
|
|
public function test_renders_three_column_layout(): void
|
|
{
|
|
$view = $this->blade(
|
|
'<x-hlcrf::layout>
|
|
<x-hlcrf::left>Left</x-hlcrf::left>
|
|
<x-hlcrf::content>Content</x-hlcrf::content>
|
|
<x-hlcrf::right>Right</x-hlcrf::right>
|
|
</x-hlcrf::layout>'
|
|
);
|
|
|
|
$view->assertSee('Left');
|
|
$view->assertSee('Content');
|
|
$view->assertSee('Right');
|
|
}
|
|
|
|
public function test_optional_regions(): void
|
|
{
|
|
$view = $this->blade(
|
|
'<x-hlcrf::layout>
|
|
<x-hlcrf::content>Content Only</x-hlcrf::content>
|
|
</x-hlcrf::layout>'
|
|
);
|
|
|
|
$view->assertSee('Content Only');
|
|
$view->assertDontSee('hlcrf-left');
|
|
$view->assertDontSee('hlcrf-right');
|
|
}
|
|
}
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### 1. Use Semantic Regions
|
|
|
|
```blade
|
|
{{-- ✅ Good - semantic use --}}
|
|
<x-hlcrf::header>Global Navigation</x-hlcrf::header>
|
|
<x-hlcrf::left>Page Navigation</x-hlcrf::left>
|
|
<x-hlcrf::content>Main Content</x-hlcrf::content>
|
|
<x-hlcrf::right>Contextual Help</x-hlcrf::right>
|
|
|
|
{{-- ❌ Bad - misuse of regions --}}
|
|
<x-hlcrf::header>Sidebar Content</x-hlcrf::header>
|
|
<x-hlcrf::left>Footer Content</x-hlcrf::left>
|
|
```
|
|
|
|
### 2. Keep Regions Optional
|
|
|
|
```blade
|
|
{{-- ✅ Good - gracefully handles missing regions --}}
|
|
<x-hlcrf::layout>
|
|
<x-hlcrf::content>
|
|
Content works without sidebars
|
|
</x-hlcrf::content>
|
|
</x-hlcrf::layout>
|
|
```
|
|
|
|
### 3. Consistent Widths
|
|
|
|
```blade
|
|
{{-- ✅ Good - consistent sidebar widths --}}
|
|
<x-hlcrf::left width="256px">Nav</x-hlcrf::left>
|
|
<x-hlcrf::right width="256px">Widgets</x-hlcrf::right>
|
|
```
|
|
|
|
### 4. Mobile-First
|
|
|
|
```blade
|
|
{{-- ✅ Good - stack on mobile --}}
|
|
<x-hlcrf::layout
|
|
:breakpoints="['mobile' => 'stack', 'desktop' => 'three-column']"
|
|
>
|
|
```
|
|
|
|
## Learn More
|
|
|
|
- [Admin Components](/packages/admin#components)
|
|
- [Livewire Integration](/packages/admin#livewire)
|
|
- [Responsive Design](/patterns-guide/responsive-design)
|