Skip to content
Brok UI

Loading…

No results

Blog

Open source

Blog sections — a dashed list, a card grid (with an optional image panel), a magazine layout and a single-article post header.

Preview

6 of 6

resources/views/blocks/blog-editorial.blade.php Blade
@props([
    'eyebrow'      => 'The Journal',
    'heading'      => 'Stories from the studio',
    'subheading'   => 'Field notes on craft, material, and the considered details behind every collection.',
    'viewAllHref'  => '#',
    'viewAllLabel' => 'View all stories',
    'readMoreLabel' => 'Read more',
    'posts'        => null,
])

{{--
    blog-07 — "Editorial" / Monogram "Journal" featured-blog grid.
    A wide-tracked uppercase eyebrow + light font-heading section title, then a
    refined grid of article cards: each a token `bg-muted` aspect placeholder, an
    uppercase wide-tracked category tag, a font-heading title, a quiet date/read-time
    meta line, a short excerpt, and a "Read more" link (chevron flips under RTL).
    A family member of the blog-* set (shares the `blog-featured` root data-slot).
    Static Blade. Composes <x-ui.card>, <x-ui.badge>, <x-ui.button>.
    Semantic tokens only, logical spacing, WCAG AA, RTL-safe.
--}}
@php
    $posts ??= [
        [
            'category' => 'Atelier',
            'title' => 'The quiet craft behind a structured leather bag',
            'excerpt' => 'Inside the workshop where each panel is cut, burnished, and stitched by hand — and why slower production makes for a piece that ages well.',
            'href' => '#',
            'date' => 'June 12, 2026',
            'datetime' => '2026-06-12',
            'readTime' => '6 min read',
            'alt' => 'Hands finishing the edge of a leather bag at a workbench',
        ],
        [
            'category' => 'Materials',
            'title' => 'Vegetable-tanned leather and the patina of time',
            'excerpt' => 'A look at the traditional tanning process we choose over speed, and how it gives every surface its own evolving character.',
            'href' => '#',
            'date' => 'June 4, 2026',
            'datetime' => '2026-06-04',
            'readTime' => '5 min read',
            'alt' => 'Close-up of richly grained tanned leather swatches',
        ],
        [
            'category' => 'Edit',
            'title' => 'Building a wardrobe of fewer, better things',
            'excerpt' => 'Our case for the considered edit — choosing pieces designed to carry from one season into the next rather than chasing the new.',
            'href' => '#',
            'date' => 'May 27, 2026',
            'datetime' => '2026-05-27',
            'readTime' => '4 min read',
            'alt' => 'A neatly arranged capsule of accessories on linen',
        ],
    ];
@endphp

<x-ui.section data-slot="blog-featured" space="xl" {{ $attributes }}>
    <div class="mx-auto max-w-7xl px-6 sm:px-8 lg:px-12">
        <header class="flex flex-col gap-6 border-b border-border pb-10 sm:flex-row sm:items-end sm:justify-between">
            <div class="max-w-2xl">
                @if ($eyebrow)
                    <p class="font-body text-sm uppercase tracking-[0.3em] text-muted-foreground">{{ __($eyebrow) }}</p>
                @endif
                <h2 class="mt-4 font-heading text-3xl font-normal leading-tight tracking-tight text-balance sm:text-4xl lg:text-5xl">
                    {{ __($heading) }}
                </h2>
                @if ($subheading)
                    <p class="mt-4 max-w-md text-pretty text-sm leading-relaxed text-muted-foreground">{{ __($subheading) }}</p>
                @endif
            </div>

            @if ($viewAllHref)
                <a
                    href="{{ $viewAllHref }}"
                    class="group inline-flex items-center gap-2 self-start rounded-sm font-body text-sm uppercase tracking-widest text-foreground outline-none transition-colors hover:text-primary focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background sm:self-auto"
                >
                    {{ __($viewAllLabel) }}
                    <svg class="size-4 shrink-0 transition-transform group-hover:translate-x-0.5 rtl:-scale-x-100" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
                        <path d="M5 12h14" /><path d="m12 5 7 7-7 7" />
                    </svg>
                </a>
            @endif
        </header>

        <div class="mt-12 grid grid-cols-1 gap-x-8 gap-y-12 sm:grid-cols-2 lg:grid-cols-3">
            @foreach ($posts as $post)
                <article class="relative h-full">
                    <x-ui.card class="group flex h-full flex-col gap-6 border-0 bg-transparent p-0 shadow-none transition-colors">
                        {{-- Media placeholder — no external image; token surface only --}}
                        <div class="aspect-[4/5] w-full overflow-hidden rounded-lg bg-muted" role="img" aria-label="{{ __($post['alt']) }}">
                            <div class="size-full bg-gradient-to-br from-muted via-accent/10 to-muted-foreground/10 transition-transform duration-300 group-hover:scale-[1.03]" aria-hidden="true"></div>
                        </div>

                        <div class="flex flex-1 flex-col">
                            <div class="flex flex-wrap items-center gap-x-4 gap-y-2">
                                @if (! empty($post['category']))
                                    <x-ui.badge variant="outline" size="sm" class="font-body uppercase tracking-widest">{{ __($post['category']) }}</x-ui.badge>
                                @endif
                                <time datetime="{{ $post['datetime'] }}" class="font-body text-sm uppercase tracking-widest text-muted-foreground">{{ __($post['date']) }}</time>
                            </div>

                            <h3 class="mt-4 font-heading text-xl font-medium leading-snug tracking-tight text-balance">
                                <a
                                    href="{{ $post['href'] }}"
                                    class="rounded-sm outline-none transition-colors hover:text-primary focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
                                >
                                    <span class="absolute inset-0" aria-hidden="true"></span>
                                    {{ __($post['title']) }}
                                </a>
                            </h3>

                            <p class="mt-4 flex-1 text-pretty text-sm leading-relaxed text-muted-foreground">{{ __($post['excerpt']) }}</p>

                            <div class="mt-6 flex items-center justify-between gap-4">
                                <x-ui.button
                                    :href="$post['href']"
                                    variant="link"
                                    size="sm"
                                    class="px-0 font-body text-sm uppercase tracking-widest"
                                    :withArrow="true"
                                >
                                    {{ __($readMoreLabel) }}
                                </x-ui.button>
                                @if (! empty($post['readTime']))
                                    <span class="font-body text-sm uppercase tracking-widest text-muted-foreground">{{ __($post['readTime']) }}</span>
                                @endif
                            </div>
                        </div>
                    </x-ui.card>
                </article>
            @endforeach
        </div>
    </div>
</x-ui.section>

Installation

terminal
php artisan ui:add blocks/blog-editorial

Installs these dependencies automatically:

Registry contract

Install confidence

php artisan ui:add blocks/blog-editorial writes only the generated targets below. The CLI validates each file hash before writing and prompts before replacing local changes unless --force is used.

Version
1.0.4
License
open
Stability
stable
Contract
v1
Foundation
≥ 1.0.0
Type Generated target
blade resources/views/blocks/blog-editorial.blade.php

Registry dependencies

badge button card section

Package dependencies

composer: jml/brok:^0.2

Use with AI

A brief for your coding agent: what the block is, the install command, how to render it, its props and the rules. Copy it, or open a prompt about this block in an assistant.

blog-editorial.md
# Brok UI block: Blog Editorial (`blog-editorial`)

An editorial 'journal' blog grid — a wide-tracked section heading over refined article cards, each with a bg-muted media placeholder, uppercase category tag, font-heading title, date meta, excerpt, and a Read more link.

Brok UI is a Laravel Blade registry. `ui:add` copies this block into the app as plain Blade the app owns; it composes installed `<brok:*>` primitives and semantic design tokens.

## Install

```bash
php artisan ui:add blocks/blog-editorial
```

## Render it

```blade
<x-blocks.blog-editorial />
```

## Props

- `eyebrow` (string, default `The Journal`)
- `heading` (string, default `Stories from the studio`)
- `subheading` (string, default `Field notes on craft, material, and the considered details behind every collection.`)
- `view-all-href` (string, default `#`)
- `view-all-label` (string, default `View all stories`)
- `read-more-label` (string, default `Read more`)
- `posts` (mixed|null, default `null`)

## Use when

- Presenting a blog index in an editorial 'journal' style: a wide-tracked heading over refined article cards with font-heading titles.
- Closing each card with a Read more link rather than making the whole card a link target.

## Avoid when

- Use blog-list or blog-image-grid for a plainer list or grid without the editorial typography treatment.

## Rules

- Render the installed block with `<x-blocks.blog-editorial />` and pass data through its props; edit the copied file only for structural changes.
- Keep the semantic design tokens (`bg-background`, `text-muted-foreground`); never swap in raw colour utilities.
- Keep the `data-slot` attributes and the logical (start/end) spacing so the markup still mirrors under `dir="rtl"`.

## Links

- Docs: https://brokui.dev/blocks/blog-editorial
- Registry JSON (files, props, contract): https://brokui.dev/r/open/blocks/blog-editorial.json

Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.

Guidance

Use when

  • Presenting a blog index in an editorial 'journal' style: a wide-tracked heading over refined article cards with font-heading titles.
  • Closing each card with a Read more link rather than making the whole card a link target.

Avoid when

  • Use blog-list or blog-image-grid for a plainer list or grid without the editorial typography treatment.

Anti-patterns

  • Do not replace semantic props with conflicting utility classes.
  • Do not remove labels, focus styles, or state attributes.
Anatomy
root blog-featured

Usage

Render the block as a component, passing data where useful:

resources/views/welcome.blade.php Blade
<x-blocks.blog-editorial />

Built from primitives

Composes <brok:*> Semantic tokens Re-themeable RTL-ready

This block composes installed <brok:*> primitives and semantic design tokens only — it does not reimplement any primitive. Re-theme it (light, dark, admin, customer) by editing CSS variables; flip the preview to RTL to confirm it mirrors.

Source

The exact, editable file ui:add writes into your app. The preview above renders this same source — there are no preview-only blocks.

resources/views/blocks/blog-editorial.blade.php Blade
@props([
    'eyebrow'      => 'The Journal',
    'heading'      => 'Stories from the studio',
    'subheading'   => 'Field notes on craft, material, and the considered details behind every collection.',
    'viewAllHref'  => '#',
    'viewAllLabel' => 'View all stories',
    'readMoreLabel' => 'Read more',
    'posts'        => null,
])

{{--
    blog-07 — "Editorial" / Monogram "Journal" featured-blog grid.
    A wide-tracked uppercase eyebrow + light font-heading section title, then a
    refined grid of article cards: each a token `bg-muted` aspect placeholder, an
    uppercase wide-tracked category tag, a font-heading title, a quiet date/read-time
    meta line, a short excerpt, and a "Read more" link (chevron flips under RTL).
    A family member of the blog-* set (shares the `blog-featured` root data-slot).
    Static Blade. Composes <x-ui.card>, <x-ui.badge>, <x-ui.button>.
    Semantic tokens only, logical spacing, WCAG AA, RTL-safe.
--}}
@php
    $posts ??= [
        [
            'category' => 'Atelier',
            'title' => 'The quiet craft behind a structured leather bag',
            'excerpt' => 'Inside the workshop where each panel is cut, burnished, and stitched by hand — and why slower production makes for a piece that ages well.',
            'href' => '#',
            'date' => 'June 12, 2026',
            'datetime' => '2026-06-12',
            'readTime' => '6 min read',
            'alt' => 'Hands finishing the edge of a leather bag at a workbench',
        ],
        [
            'category' => 'Materials',
            'title' => 'Vegetable-tanned leather and the patina of time',
            'excerpt' => 'A look at the traditional tanning process we choose over speed, and how it gives every surface its own evolving character.',
            'href' => '#',
            'date' => 'June 4, 2026',
            'datetime' => '2026-06-04',
            'readTime' => '5 min read',
            'alt' => 'Close-up of richly grained tanned leather swatches',
        ],
        [
            'category' => 'Edit',
            'title' => 'Building a wardrobe of fewer, better things',
            'excerpt' => 'Our case for the considered edit — choosing pieces designed to carry from one season into the next rather than chasing the new.',
            'href' => '#',
            'date' => 'May 27, 2026',
            'datetime' => '2026-05-27',
            'readTime' => '4 min read',
            'alt' => 'A neatly arranged capsule of accessories on linen',
        ],
    ];
@endphp

<x-ui.section data-slot="blog-featured" space="xl" {{ $attributes }}>
    <div class="mx-auto max-w-7xl px-6 sm:px-8 lg:px-12">
        <header class="flex flex-col gap-6 border-b border-border pb-10 sm:flex-row sm:items-end sm:justify-between">
            <div class="max-w-2xl">
                @if ($eyebrow)
                    <p class="font-body text-sm uppercase tracking-[0.3em] text-muted-foreground">{{ __($eyebrow) }}</p>
                @endif
                <h2 class="mt-4 font-heading text-3xl font-normal leading-tight tracking-tight text-balance sm:text-4xl lg:text-5xl">
                    {{ __($heading) }}
                </h2>
                @if ($subheading)
                    <p class="mt-4 max-w-md text-pretty text-sm leading-relaxed text-muted-foreground">{{ __($subheading) }}</p>
                @endif
            </div>

            @if ($viewAllHref)
                <a
                    href="{{ $viewAllHref }}"
                    class="group inline-flex items-center gap-2 self-start rounded-sm font-body text-sm uppercase tracking-widest text-foreground outline-none transition-colors hover:text-primary focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background sm:self-auto"
                >
                    {{ __($viewAllLabel) }}
                    <svg class="size-4 shrink-0 transition-transform group-hover:translate-x-0.5 rtl:-scale-x-100" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
                        <path d="M5 12h14" /><path d="m12 5 7 7-7 7" />
                    </svg>
                </a>
            @endif
        </header>

        <div class="mt-12 grid grid-cols-1 gap-x-8 gap-y-12 sm:grid-cols-2 lg:grid-cols-3">
            @foreach ($posts as $post)
                <article class="relative h-full">
                    <x-ui.card class="group flex h-full flex-col gap-6 border-0 bg-transparent p-0 shadow-none transition-colors">
                        {{-- Media placeholder — no external image; token surface only --}}
                        <div class="aspect-[4/5] w-full overflow-hidden rounded-lg bg-muted" role="img" aria-label="{{ __($post['alt']) }}">
                            <div class="size-full bg-gradient-to-br from-muted via-accent/10 to-muted-foreground/10 transition-transform duration-300 group-hover:scale-[1.03]" aria-hidden="true"></div>
                        </div>

                        <div class="flex flex-1 flex-col">
                            <div class="flex flex-wrap items-center gap-x-4 gap-y-2">
                                @if (! empty($post['category']))
                                    <x-ui.badge variant="outline" size="sm" class="font-body uppercase tracking-widest">{{ __($post['category']) }}</x-ui.badge>
                                @endif
                                <time datetime="{{ $post['datetime'] }}" class="font-body text-sm uppercase tracking-widest text-muted-foreground">{{ __($post['date']) }}</time>
                            </div>

                            <h3 class="mt-4 font-heading text-xl font-medium leading-snug tracking-tight text-balance">
                                <a
                                    href="{{ $post['href'] }}"
                                    class="rounded-sm outline-none transition-colors hover:text-primary focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
                                >
                                    <span class="absolute inset-0" aria-hidden="true"></span>
                                    {{ __($post['title']) }}
                                </a>
                            </h3>

                            <p class="mt-4 flex-1 text-pretty text-sm leading-relaxed text-muted-foreground">{{ __($post['excerpt']) }}</p>

                            <div class="mt-6 flex items-center justify-between gap-4">
                                <x-ui.button
                                    :href="$post['href']"
                                    variant="link"
                                    size="sm"
                                    class="px-0 font-body text-sm uppercase tracking-widest"
                                    :withArrow="true"
                                >
                                    {{ __($readMoreLabel) }}
                                </x-ui.button>
                                @if (! empty($post['readTime']))
                                    <span class="font-body text-sm uppercase tracking-widest text-muted-foreground">{{ __($post['readTime']) }}</span>
                                @endif
                            </div>
                        </div>
                    </x-ui.card>
                </article>
            @endforeach
        </div>
    </div>
</x-ui.section>

Ownership & lifecycle

Owner, release state, review evidence and adoption for this item.
Owner
Platform UI (@JoshJML)
Current version
1.0.4
Status
Stable
License
open
Deprecation
Not deprecated
Contract
v1
Foundation
≥ 1.0.0