@extends('layouts.nova') @php $page_title = $page_title ?? 'Community Activity'; $page_meta_description = 'Track comments, replies, reactions, and mentions from across the Skinbase community in one live feed.'; $page_canonical = route('community.activity', array_filter([ 'filter' => ($initialFilter ?? null) && ($initialFilter ?? 'all') !== 'all' ? $initialFilter : null, 'user_id' => $initialUserId ?? null, ], fn (mixed $value): bool => $value !== null && $value !== '')); $useUnifiedSeo = true; $headerBreadcrumbs = collect([ (object) ['name' => $page_title, 'url' => $page_canonical], ]); $breadcrumbs = $headerBreadcrumbs; $seo = \App\Support\Seo\SeoDataBuilder::fromArray( app(\App\Support\Seo\SeoFactory::class)->fromViewData(get_defined_vars()) )->build(); $communityActivityManifestPath = public_path('build/manifest.json'); $communityActivityManifest = is_file($communityActivityManifestPath) ? json_decode((string) file_get_contents($communityActivityManifestPath), true) : null; $communityActivityViteReady = is_array($communityActivityManifest) && array_key_exists('resources/js/Pages/Community/CommunityActivityPage.jsx', $communityActivityManifest); $initialFilterLabel = match (($initialFilter ?? 'all')) { 'comments' => 'Comments', 'replies' => 'Replies', 'following' => 'Following', 'my' => 'My Activity', default => 'All Activity', }; $serverActivities = $props['initialActivities'] ?? []; $serverMeta = $props['initialMeta'] ?? []; $serverFilter = $props['initialFilter'] ?? 'all'; $serverUserId = $props['initialUserId'] ?? null; $serverIsAuthenticated = (bool) ($props['isAuthenticated'] ?? false); $serverResultsLabel = ((int) ($serverMeta['total'] ?? count($serverActivities))) > 0 ? number_format((int) ($serverMeta['total'] ?? count($serverActivities))) . ' events' : 'No recent activity'; $serverFilterTabs = [ ['key' => 'all', 'label' => 'All Activity', 'auth_required' => false], ['key' => 'comments', 'label' => 'Comments', 'auth_required' => false], ['key' => 'replies', 'label' => 'Replies', 'auth_required' => false], ['key' => 'following', 'label' => 'Following', 'auth_required' => true], ['key' => 'my', 'label' => 'My Activity', 'auth_required' => true], ]; $buildFilterUrl = static function (string $filterKey, ?int $userId): string { return route('community.activity', array_filter([ 'filter' => $filterKey !== 'all' ? $filterKey : null, 'user_id' => $userId, ], static fn (mixed $value): bool => $value !== null && $value !== '')); }; $describeActivity = static function (array $activity): array { $type = (string) ($activity['type'] ?? 'activity'); $artworkTitle = (string) data_get($activity, 'artwork.title', 'an artwork'); $artworkUrl = data_get($activity, 'artwork.url'); $storyTitle = (string) data_get($activity, 'story.title', 'a story'); $storyUrl = data_get($activity, 'story.url'); $targetUsername = (string) (data_get($activity, 'target_user.username') ?: data_get($activity, 'target_user.name', 'another creator')); $targetUrl = data_get($activity, 'target_user.profile_url'); $mentionedUsername = (string) (data_get($activity, 'mentioned_user.username') ?: data_get($activity, 'mentioned_user.name', 'someone')); $mentionedUrl = data_get($activity, 'mentioned_user.profile_url'); $commentAuthor = (string) (data_get($activity, 'comment.author.name') ?: data_get($activity, 'comment.author.username', 'a creator')); $commentAuthorUrl = data_get($activity, 'comment.author.profile_url'); $reactionLabel = trim((string) data_get($activity, 'reaction.emoji', '')) . ' ' . (string) data_get($activity, 'reaction.label', 'Like'); return match ($type) { 'upload' => $storyUrl || data_get($activity, 'story.title') ? ['verb' => 'published', 'subject' => $storyTitle, 'subject_url' => $storyUrl, 'context' => null, 'context_url' => null] : ['verb' => 'published', 'subject' => $artworkTitle, 'subject_url' => $artworkUrl, 'context' => null, 'context_url' => null], 'favorite' => ['verb' => 'favorited', 'subject' => $artworkTitle, 'subject_url' => $artworkUrl, 'context' => null, 'context_url' => null], 'follow' => ['verb' => 'followed', 'subject' => '@' . ltrim($targetUsername, '@'), 'subject_url' => $targetUrl, 'context' => null, 'context_url' => null], 'award' => ['verb' => 'awarded', 'subject' => $artworkTitle, 'subject_url' => $artworkUrl, 'context' => null, 'context_url' => null], 'story_like' => ['verb' => 'liked', 'subject' => $storyTitle, 'subject_url' => $storyUrl, 'context' => null, 'context_url' => null], 'story_comment' => ['verb' => 'commented on', 'subject' => $storyTitle, 'subject_url' => $storyUrl, 'context' => null, 'context_url' => null], 'comment' => ['verb' => 'commented on', 'subject' => $artworkTitle, 'subject_url' => $artworkUrl, 'context' => null, 'context_url' => null], 'reply' => ['verb' => 'replied on', 'subject' => $artworkTitle, 'subject_url' => $artworkUrl, 'context' => null, 'context_url' => null], 'reaction' => ['verb' => 'reacted ' . trim($reactionLabel), 'subject' => $commentAuthor, 'subject_url' => $commentAuthorUrl, 'context' => $artworkTitle, 'context_url' => $artworkUrl], 'mention' => ['verb' => 'mentioned', 'subject' => '@' . ltrim($mentionedUsername, '@'), 'subject_url' => $mentionedUrl, 'context' => $artworkTitle, 'context_url' => $artworkUrl], default => ['verb' => 'shared new activity on', 'subject' => $artworkTitle, 'subject_url' => $artworkUrl, 'context' => null, 'context_url' => null], }; }; @endphp @section('content')
{{ $initialFilterLabel }} @if (!empty($initialUserId)) User #{{ $initialUserId }} @else @endif

Live community pulse

Comments, replies, reactions, and mentions from across Skinbase in one scrolling Nova feed.

{{ $serverResultsLabel }}
@foreach ($serverFilterTabs as $tab) @php $isDisabled = $tab['auth_required'] && ! $serverIsAuthenticated; $isActive = $serverFilter === $tab['key']; @endphp @if ($isDisabled) {{ $tab['label'] }} @else {{ $tab['label'] }} @endif @endforeach
@if (count($serverActivities) === 0)

No activity yet

When creators and members interact around artworks, their activity will appear here.

@else
@foreach ($serverActivities as $activity) @php $activityUser = data_get($activity, 'user', []); $activityArtwork = data_get($activity, 'artwork', []); $activityStory = data_get($activity, 'story', []); $activityCommentBody = trim((string) data_get($activity, 'comment.body', '')); $activityHeadline = $describeActivity($activity); $activityAvatarUrl = data_get($activityUser, 'avatar_url') ?: '/images/avatar_default.webp'; $activityProfileUrl = data_get($activityUser, 'profile_url'); $activityName = data_get($activityUser, 'name') ?: data_get($activityUser, 'username', 'Skinbase creator'); $activityUsername = data_get($activityUser, 'username'); $activityPreviewUrl = data_get($activityArtwork, 'thumb_url') ?: data_get($activityStory, 'cover_url'); $activityPreviewAlt = data_get($activityArtwork, 'title') ?: data_get($activityStory, 'title') ?: 'Activity preview'; $activityPreviewLink = data_get($activityArtwork, 'url') ?: data_get($activityStory, 'url'); @endphp
{{ $activityName }}

@if ($activityProfileUrl) {{ $activityName }} @else {{ $activityName }} @endif

@if ($activityUsername)

@{{ $activityUsername }}

@endif

{{ data_get($activity, 'time_ago', '') }}

{{ $activityHeadline['verb'] }} @if (!empty($activityHeadline['subject'])) @if (!empty($activityHeadline['subject_url'])) {{ $activityHeadline['subject'] }} @else {{ $activityHeadline['subject'] }} @endif @endif @if (!empty($activityHeadline['context'])) on @if (!empty($activityHeadline['context_url'])) {{ $activityHeadline['context'] }} @else {{ $activityHeadline['context'] }} @endif @endif

@if ($activityCommentBody !== '')

{{ \Illuminate\Support\Str::limit($activityCommentBody, 240) }}

@endif @if (($activity['type'] ?? null) === 'mention' && data_get($activity, 'mentioned_user.username'))
Mentioned @{{ data_get($activity, 'mentioned_user.username') }}
@endif
@if ($activityPreviewUrl) @endif
@endforeach
@endif
@if ($communityActivityViteReady) @vite(['resources/js/Pages/Community/CommunityActivityPage.jsx']) @endif @endsection