Skip to main content

General

Blog code

Copy the implementation or inspect every file that belongs to this component unit.

resources/views/components/ui/blog/article-meta.blade.php

@props([
    'post' => null,
    'date' => null,
    'dateTime' => null,
    'category' => null,
    'categoryHref' => null,
    'draft' => false,
    'statusLabel' => null,
    'statusVariant' => 'amber',
])

@php
    /*
    | Article metadata row: publish date or draft badge, optional category link.
    |
    | Pass a Post model for the standard blog, or scalar props (date, category,
    | categoryHref) to render without a model.
    |
    | Usage:
    |   <x-ui.blog.article-meta :post="$post" />
    |   <x-ui.blog.article-meta date="June 12, 2026" category="Product" :category-href="$url" />
    */
    if ($post) {
        $draft = ! $post->isPublished();
        $date = $post->published_at?->format('F j, Y');
        $dateTime = $post->published_at?->toIso8601String();
        $category = $post->category?->name;
        $categoryHref = $post->category ? route('categories.show', $post->category) : null;
        $statusLabel = $post->statusLabel();
        $statusVariant = $post->statusBadgeVariant();
    }
@endphp

<div {{ $attributes->merge(['class' => 'flex items-center gap-2 text-sm font-medium text-gray-500 dark:text-gray-400']) }}>
    @if ($draft)
        <x-ui.badge :variant="$statusVariant" size="sm">{{ $statusLabel }}</x-ui.badge>
    @elseif ($date)
        <time @if ($dateTime) datetime="{{ $dateTime }}" @endif>{{ $date }}</time>
    @endif

    @if ($category)
        <span aria-hidden="true">&middot;</span>
        @if ($categoryHref)
            <a href="{{ $categoryHref }}" class="transition hover:text-brand-600 dark:hover:text-brand-400">
                <x-ui.badge variant="brand" size="sm" icon="tag">{{ $category }}</x-ui.badge>
            </a>
        @else
            <x-ui.badge variant="brand" size="sm" icon="tag">{{ $category }}</x-ui.badge>
        @endif
    @endif
</div>

resources/views/components/ui/blog/author-byline.blade.php

@props([
    'user' => null,
    'name' => null,
    'label' => 'Author',
    'size' => 'base',
])

@php
    /*
    | Author byline with avatar, name and role label.
    |
    | Pass a User model for the standard blog (uses the user's custom avatar),
    | or a `name` string to render without a model.
    |
    | Usage:
    |   <x-ui.blog.author-byline :user="$post->user" />
    |   <x-ui.blog.author-byline name="Ada Lovelace" label="Founding Designer" />
    */
    $name ??= $user?->fullName();
@endphp

<div {{ $attributes->merge(['class' => 'flex items-center gap-3']) }}>
    @if ($user)
        <x-ui.avatar
            :name="$user->fullName()"
            :initials="$user->avatarInitials()"
            :background="$user->avatarBackground()"
            :color="$user->avatar_character_color"
            :size="$size"
        />
    @else
        <x-ui.avatar :name="$name" :size="$size" />
    @endif

    <div>
        <p class="text-sm font-semibold text-gray-900 dark:text-white">{{ $name }}</p>
        <p class="text-xs text-gray-500 dark:text-gray-400">{{ $label }}</p>
    </div>
</div>

resources/views/components/ui/blog/masthead.blade.php

@props([
    'title',
    'description' => null,
])

@php
    /*
    | Blog page masthead with optional eyebrow badge and trailing actions.
    |
    | Usage:
    |   <x-ui.blog.masthead title="The Blog" description="Thoughts and updates.">
    |       <x-slot:actions><x-ui.button href="...">Write</x-ui.button></x-slot:actions>
    |   </x-ui.blog.masthead>
    |
    |   <x-ui.blog.masthead title="{{ $category->name }}" :description="$category->description">
    |       <x-slot:eyebrow><x-ui.badge variant="brand" icon="tag">Category</x-ui.badge></x-slot:eyebrow>
    |   </x-ui.blog.masthead>
    */
@endphp

<header {{ $attributes->merge(['class' => 'flex flex-col gap-4 border-b border-gray-200 pb-8 sm:flex-row sm:items-end sm:justify-between sm:gap-6 dark:border-gray-800']) }}>
    <div class="min-w-0">
        @isset($eyebrow)
            <div class="flex items-center gap-2">{{ $eyebrow }}</div>
        @endisset

        <h1 @class([
            'text-4xl font-bold tracking-tight text-gray-900 dark:text-white',
            'mt-3' => isset($eyebrow),
        ])>{{ $title }}</h1>

        @if ($description)
            <p class="mt-2 text-base text-gray-500 dark:text-gray-400">{{ $description }}</p>
        @endif
    </div>

    @isset($actions)
        <div class="flex w-full shrink-0 flex-wrap items-center gap-2 sm:w-auto">{{ $actions }}</div>
    @endisset
</header>

resources/views/components/ui/blog/post-list-item.blade.php

@props([
    'post' => null,
    'showCategory' => true,
    'title' => null,
    'author' => null,
    'date' => null,
    'dateTime' => null,
    'category' => null,
    'comments' => 0,
    'href' => '#',
    'excerpt' => null,
])

@php
    /*
    | Blog reading-list row: meta, title, excerpt and comment count.
    |
    | Pass a Post model for the standard blog, or the scalar props
    | (title, author, date, category, comments, href, excerpt) to render a row
    | without a model (e.g. in showcases).
    |
    | Usage:
    |   <x-ui.blog.post-list-item :post="$post" />
    |   <x-ui.blog.post-list-item title="..." author="Ada" date="Jun 9, 2026" :href="$url" />
    */
    if ($post) {
        $title = $post->title;
        $author = $post->user->fullName();
        $date = $post->published_at->format('M j, Y');
        $dateTime = $post->published_at->toIso8601String();
        $category = $showCategory ? $post->category?->name : null;
        $comments = $post->comments_count;
        $href = route('posts.show', $post);
        $excerpt = $post->excerpt ?: Str::limit(strip_tags($post->body), 180);
    }
@endphp

<article {{ $attributes->merge(['class' => 'group py-10']) }}>
    <a href="{{ $href }}" class="block">
        <div class="flex items-center gap-2 text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">
            <span>{{ $author }}</span>
            <span aria-hidden="true">&middot;</span>
            <time @if ($dateTime) datetime="{{ $dateTime }}" @endif>{{ $date }}</time>
            @if ($showCategory && $category)
                <span aria-hidden="true">&middot;</span>
                <span class="text-brand-600 dark:text-brand-400">{{ $category }}</span>
            @endif
        </div>

        <h2 class="mt-3 text-2xl font-bold tracking-tight text-gray-900 transition-colors group-hover:text-brand-600 dark:text-white dark:group-hover:text-brand-400">
            {{ $title }}
        </h2>

        @if ($excerpt)
            <p class="mt-3 text-base leading-relaxed text-gray-600 dark:text-gray-300">
                {{ $excerpt }}
            </p>
        @endif

        <div class="mt-4 flex items-center gap-4 text-sm text-gray-500 dark:text-gray-400">
            <span class="inline-flex items-center gap-1.5">
                <x-ui.icon name="chat-circle" size="sm" />
                {{ $comments }} {{ Str::plural('comment', $comments) }}
            </span>
            <span class="inline-flex items-center gap-1 font-medium text-brand-600 opacity-0 transition-opacity group-hover:opacity-100 dark:text-brand-400">
                Read
                <x-ui.icon name="arrow-right" weight="bold" size="sm" class="transition-transform group-hover:translate-x-0.5" />
            </span>
        </div>
    </a>
</article>