Skip to main content

Content & marketing

Log Activity Section code

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

resources/views/components/ui/log-activity-section.blade.php

@props([
    'eyebrow' => null,
    'number' => null,
    'title' => null,
    'description' => null,
    'align' => 'center',
    'entries' => [],
    'stream' => 'access.log',
    'live' => true,
    'spacing' => 'base',
])

@php
    /*
    | Full-width landing page section for a logging SaaS. A heading block sits
    | above a wide, monospace activity feed with colour-coded timestamps,
    | subjects, value changes and status badges. Theme-aware surfaces work in
    | both light and dark modes without gradients or decorative icons.
    |
    | Each entry accepts:
    |   timestamp  => string (e.g. '02:14')
    |   subject    => string (entity or resource name)
    |   status     => get|post|put|patch|delete (or update|create|rollback|bulk)
    |   message    => optional plain string
    |   parts      => optional array of text/change/add/code segments
    |
    | Usage:
    |   <x-ui.log-activity-section
    |       number="04"
    |       eyebrow="Web logs"
    |       title="Every request, searchable in real time"
    |       description="HTTP access logs with status codes, latency and method badges."
    |   />
    */
    $spacingClass = ['sm' => 'py-12 sm:py-16', 'base' => 'py-16 sm:py-24', 'lg' => 'py-24 sm:py-32'][$spacing] ?? 'py-16 sm:py-24';
    $isCenter = $align === 'center';
    $headingWrap = $isCenter ? 'mx-auto max-w-2xl text-center' : 'max-w-2xl';

    $defaultEntries = [
        [
            'timestamp' => '14:02:31',
            'subject' => '/api/v1/users',
            'status' => 'get',
            'parts' => [
                ['type' => 'code', 'value' => '200'],
                ['type' => 'text', 'value' => '48ms'],
                ['type' => 'text', 'value' => '1.2kb'],
            ],
        ],
        [
            'timestamp' => '14:02:28',
            'subject' => '/checkout',
            'status' => 'post',
            'parts' => [
                ['type' => 'code', 'value' => '201'],
                ['type' => 'text', 'value' => '142ms'],
                ['type' => 'text', 'value' => 'order created'],
            ],
        ],
        [
            'timestamp' => '14:02:25',
            'subject' => '/assets/app-H3k.css',
            'status' => 'get',
            'parts' => [
                ['type' => 'code', 'value' => '304'],
                ['type' => 'text', 'value' => '8ms'],
                ['type' => 'text', 'value' => 'cached'],
            ],
        ],
        [
            'timestamp' => '14:02:22',
            'subject' => '/login',
            'status' => 'post',
            'parts' => [
                ['type' => 'code', 'value' => '401'],
                ['type' => 'text', 'value' => '19ms'],
                ['type' => 'text', 'value' => 'invalid credentials'],
            ],
        ],
        [
            'timestamp' => '14:02:19',
            'subject' => '/health',
            'status' => 'get',
            'parts' => [
                ['type' => 'code', 'value' => '500'],
                ['type' => 'text', 'value' => '891ms'],
                ['type' => 'text', 'value' => 'upstream timeout'],
            ],
        ],
        [
            'timestamp' => '14:02:16',
            'subject' => '/api/sessions/8f2a',
            'status' => 'delete',
            'parts' => [
                ['type' => 'code', 'value' => '204'],
                ['type' => 'text', 'value' => '33ms'],
            ],
        ],
        [
            'timestamp' => '14:02:14',
            'subject' => '/api/settings',
            'status' => 'patch',
            'parts' => [
                ['type' => 'code', 'value' => '200'],
                ['type' => 'text', 'value' => '56ms'],
                ['type' => 'text', 'value' => 'theme updated'],
            ],
        ],
    ];

    $rows = filled($entries) ? $entries : $defaultEntries;
@endphp

<section {{ $attributes->merge(['class' => $spacingClass]) }}>
    @if ($eyebrow || $title || $description)
        <div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
            <div class="{{ $headingWrap }}">
                @if ($eyebrow)
                    <div class="flex items-center gap-2.5 text-sm font-semibold {{ $isCenter ? 'justify-center' : '' }}">
                        @if ($number)
                            <span class="inline-flex h-6 min-w-6 items-center justify-center rounded-md bg-brand-600 px-1.5 text-xs font-bold text-white tabular-nums">{{ $number }}</span>
                        @endif
                        <span class="uppercase tracking-[0.12em] text-brand-600 dark:text-brand-400">{{ $eyebrow }}</span>
                    </div>
                @endif
                @if ($title)
                    <h2 class="mt-4 text-3xl font-semibold tracking-tight text-gray-900 dark:text-white text-balance sm:text-4xl">{{ $title }}</h2>
                @endif
                @if ($description)
                    <p class="mt-4 text-lg leading-relaxed text-gray-600 dark:text-gray-400 text-pretty">{{ $description }}</p>
                @endif
            </div>
        </div>
    @endif

    <div @class([
        'relative',
        ($eyebrow || $title || $description) ? 'mt-12 sm:mt-16' : null,
    ])>
        <div class="mx-auto w-full max-w-[100rem] px-4 sm:px-6 lg:px-8">
            <div class="relative overflow-hidden rounded-2xl bg-white shadow-sm dark:bg-gray-950 sm:rounded-3xl">
                <div class="pointer-events-none absolute inset-x-0 top-0 hairline-fade-x" aria-hidden="true"></div>

                <div class="relative flex flex-col gap-3 px-4 py-4 sm:flex-row sm:items-center sm:justify-between sm:px-6">
                    <div class="min-w-0">
                        <p class="font-mono text-xs uppercase tracking-[0.16em] text-gray-500 dark:text-gray-400">Access log</p>
                        <p class="mt-1 truncate font-mono text-sm text-gray-900 dark:text-gray-100">{{ $stream }}</p>
                    </div>

                    @if ($live)
                        <div class="flex shrink-0 items-center gap-2">
                            <span class="relative flex h-2 w-2" aria-hidden="true">
                                <span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-500 opacity-60 motion-reduce:animate-none"></span>
                                <span class="relative inline-flex h-2 w-2 rounded-full bg-green-500"></span>
                            </span>
                            <span class="font-mono text-xs uppercase tracking-[0.14em] text-green-700 dark:text-green-400">Live</span>
                        </div>
                    @endif

                    <div class="pointer-events-none absolute inset-x-0 bottom-0 hairline-fade-x" aria-hidden="true"></div>
                </div>

                <div>
                    @foreach ($rows as $entry)
                        <x-ui.log-activity-row
                            :timestamp="$entry['timestamp'] ?? ''"
                            :subject="$entry['subject'] ?? ''"
                            :status="$entry['status'] ?? 'update'"
                            :message="$entry['message'] ?? null"
                            :parts="$entry['parts'] ?? []"
                            :divider="! $loop->last"
                        />
                    @endforeach
                </div>

                <div class="relative flex flex-wrap items-center justify-between gap-3 px-4 py-3 font-mono text-xs text-gray-500 dark:text-gray-400 sm:px-6">
                    <div class="pointer-events-none absolute inset-x-0 top-0 hairline-fade-x" aria-hidden="true"></div>
                    <span>{{ count($rows) }} events in view</span>
                    <span class="text-gray-400 dark:text-gray-500">Updated just now</span>
                </div>

                <div class="pointer-events-none absolute inset-x-0 bottom-0 hairline-fade-x" aria-hidden="true"></div>
            </div>
        </div>
    </div>

    @if ($slot->isNotEmpty())
        <div class="mx-auto mt-10 max-w-7xl px-4 sm:px-6 lg:px-8">
            {{ $slot }}
        </div>
    @endif
</section>