General
Log Activity Row code
Copy the implementation or inspect every file that belongs to this component unit.
resources/views/components/ui/log-activity-row.blade.php
@props([
'timestamp',
'subject',
'status' => 'update',
'message' => null,
'parts' => [],
'divider' => true,
])
@php
/*
| Single row in the log activity feed. Renders a timestamp, subject, optional
| structured message parts, and a status badge. Message parts support plain
| text, value changes (old -> new), and additions.
|
| Usage:
| <x-ui.log-activity-row
| timestamp="14:02:31"
| subject="GET /api/v1/users"
| status="get"
| :parts="[
| ['type' => 'code', 'value' => '200'],
| ['type' => 'text', 'value' => '48ms'],
| ]"
| />
*/
$statusKey = strtolower((string) $status);
$statusMeta = [
'get' => [
'label' => 'GET',
'badge' => 'bg-gray-500/10 text-gray-600 dark:bg-gray-400/10 dark:text-gray-400',
],
'post' => [
'label' => 'POST',
'badge' => 'bg-green-500/10 text-green-700 dark:bg-green-400/10 dark:text-green-300',
],
'put' => [
'label' => 'PUT',
'badge' => 'bg-accent-500/10 text-accent-700 dark:bg-accent-400/10 dark:text-accent-300',
],
'patch' => [
'label' => 'PATCH',
'badge' => 'bg-accent-500/10 text-accent-700 dark:bg-accent-400/10 dark:text-accent-300',
],
'delete' => [
'label' => 'DELETE',
'badge' => 'bg-amber-500/10 text-amber-700 dark:bg-amber-400/10 dark:text-amber-300',
],
'update' => [
'label' => 'UPDATE',
'badge' => 'bg-accent-500/10 text-accent-700 dark:bg-accent-400/10 dark:text-accent-300',
],
'create' => [
'label' => 'CREATE',
'badge' => 'bg-green-500/10 text-green-700 dark:bg-green-400/10 dark:text-green-300',
],
'rollback' => [
'label' => 'ROLLBACK',
'badge' => 'bg-amber-500/10 text-amber-700 dark:bg-amber-400/10 dark:text-amber-300',
],
'bulk' => [
'label' => 'BULK',
'badge' => 'bg-gray-500/10 text-gray-600 dark:bg-gray-400/10 dark:text-gray-400',
],
];
$codeTone = function (string $code): string {
$status = (int) $code;
if ($status >= 500) {
return 'text-red-600 dark:text-red-400';
}
if ($status >= 400) {
return 'text-amber-600 dark:text-amber-400';
}
if ($status >= 300) {
return 'text-accent-600 dark:text-accent-400';
}
if ($status >= 200) {
return 'text-green-600 dark:text-green-400';
}
return 'text-gray-500 dark:text-gray-400';
};
$meta = $statusMeta[$statusKey] ?? $statusMeta['get'];
$segments = filled($parts) ? $parts : (filled($message) ? [['type' => 'text', 'value' => $message]] : []);
@endphp
<div {{ $attributes->merge(['class' => 'group relative flex min-w-0 items-start gap-3 px-4 py-3 transition sm:gap-4 sm:px-6 sm:py-3.5 hover:bg-gray-100/70 dark:hover:bg-white/[0.03]']) }}>
<time datetime="{{ $timestamp }}" class="shrink-0 select-none pt-0.5 font-mono text-xs tabular-nums text-gray-400 dark:text-gray-500">
{{ $timestamp }}
</time>
<div class="min-w-0 flex-1 font-mono text-[13px] leading-relaxed">
<span class="font-medium text-gray-900 dark:text-gray-100">{{ $subject }}</span>
@if ($segments !== [])
<span class="text-gray-400 dark:text-gray-600" aria-hidden="true"> · </span>
@foreach ($segments as $segment)
@php($type = $segment['type'] ?? 'text')
@if ($type === 'change')
@if (filled($segment['label'] ?? null))
<span class="text-gray-500 dark:text-gray-400">{{ $segment['label'] }} </span>
@endif
<span class="text-red-600 dark:text-red-400">{{ $segment['from'] ?? '' }}</span>
<span class="text-gray-400 dark:text-gray-500" aria-hidden="true"> -> </span>
<span class="text-green-600 dark:text-green-400">{{ $segment['to'] ?? '' }}</span>
@elseif ($type === 'add')
<span class="text-green-600 dark:text-green-400">{{ $segment['value'] ?? '' }}</span>
@elseif ($type === 'code')
<span class="{{ $codeTone((string) ($segment['value'] ?? '')) }}">{{ $segment['value'] ?? '' }}</span>
@else
<span class="text-gray-500 dark:text-gray-400">{{ $segment['value'] ?? '' }}</span>
@endif
@if (! $loop->last)
<span class="text-gray-400 dark:text-gray-600"> </span>
@endif
@endforeach
@endif
</div>
<span class="shrink-0 rounded-md px-2 py-0.5 font-mono text-[10px] font-semibold uppercase tracking-[0.14em] {{ $meta['badge'] }}">
{{ $meta['label'] }}
</span>
@if ($divider)
<div class="pointer-events-none absolute inset-x-0 bottom-0 hairline-fade-x" aria-hidden="true"></div>
@endif
</div>