feat: artwork page carousels, recommendations, avatars & fixes
- Infinite loop carousels for Similar Artworks & Trending rails
- Mouse wheel horizontal scrolling on both carousels
- Author avatar shown on hover in RailCard (similar + trending)
- Removed "View" badge from RailCard hover overlay
- Added `id` to Meilisearch filterable attributes
- Auto-prepend Scout prefix in meilisearch:configure-index command
- Added author name + avatar to Similar Artworks API response
- Added avatar_url to ArtworkListResource author object
- Added direct /art/{id}/{slug} URL to ArtworkListResource
- Fixed race condition: Similar Artworks no longer briefly shows trending items
- Fixed user_profiles eager load (user_id primary key, not id)
- Bumped /api/art/{id}/similar rate limit to 300/min
- Removed decorative heart icons from tag pills
- Moved ReactionBar under artwork description
This commit is contained in:
@@ -54,29 +54,37 @@ class ArtworkListResource extends JsonResource
|
||||
? '/' . strtolower($contentTypeSlug) . '/' . strtolower($categoryPath) . '/' . $slugVal
|
||||
: null;
|
||||
|
||||
$artId = $get('id');
|
||||
$directUrl = $artId && $slugVal ? '/art/' . $artId . '/' . $slugVal : null;
|
||||
|
||||
$decode = static fn (?string $v): string => html_entity_decode((string) ($v ?? ''), ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||
|
||||
return [
|
||||
'id' => $artId,
|
||||
'slug' => $slugVal,
|
||||
'title' => $get('title'),
|
||||
'description' => $this->when($request->boolean('include_description'), fn() => $get('description')),
|
||||
'title' => $decode($get('title')),
|
||||
'description' => $this->when($request->boolean('include_description'), fn() => $decode($get('description'))),
|
||||
'dimensions' => [
|
||||
'width' => $get('width'),
|
||||
'height' => $get('height'),
|
||||
],
|
||||
'thumbnail_url' => $this->when(! empty($hash) && ! empty($thumbExt), fn() => ThumbnailService::fromHash($hash, $thumbExt, 'md')),
|
||||
'author' => $this->whenLoaded('user', function () {
|
||||
'author' => $this->whenLoaded('user', function () use ($decode) {
|
||||
return [
|
||||
'name' => $this->user->name ?? null,
|
||||
'name' => $decode($this->user->name ?? null),
|
||||
'avatar_url' => $this->user?->profile?->avatar_url,
|
||||
];
|
||||
}),
|
||||
'category' => $primaryCategory ? [
|
||||
'slug' => $primaryCategory->slug ?? null,
|
||||
'name' => $primaryCategory->name ?? null,
|
||||
'name' => $decode($primaryCategory->name ?? null),
|
||||
'content_type' => $contentTypeSlug,
|
||||
'url' => $webUrl,
|
||||
] : null,
|
||||
'urls' => [
|
||||
'web' => $webUrl,
|
||||
'canonical' => $webUrl,
|
||||
'web' => $webUrl ?? $directUrl,
|
||||
'direct' => $directUrl,
|
||||
'canonical' => $webUrl ?? $directUrl,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -56,11 +56,13 @@ class ArtworkResource extends JsonResource
|
||||
}
|
||||
}
|
||||
|
||||
$decode = static fn (?string $v): string => html_entity_decode((string) ($v ?? ''), ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||
|
||||
return [
|
||||
'id' => (int) $this->id,
|
||||
'slug' => (string) $this->slug,
|
||||
'title' => (string) $this->title,
|
||||
'description' => (string) ($this->description ?? ''),
|
||||
'title' => $decode($this->title),
|
||||
'description' => $decode($this->description),
|
||||
'dimensions' => [
|
||||
'width' => (int) ($this->width ?? 0),
|
||||
'height' => (int) ($this->height ?? 0),
|
||||
@@ -80,7 +82,7 @@ class ArtworkResource extends JsonResource
|
||||
],
|
||||
'user' => [
|
||||
'id' => (int) ($this->user?->id ?? 0),
|
||||
'name' => (string) ($this->user?->name ?? ''),
|
||||
'name' => html_entity_decode((string) ($this->user?->name ?? ''), ENT_QUOTES | ENT_HTML5, 'UTF-8'),
|
||||
'username' => (string) ($this->user?->username ?? ''),
|
||||
'profile_url' => $this->user?->username ? '/@' . $this->user->username : null,
|
||||
'avatar_url' => $this->user?->profile?->avatar_url,
|
||||
@@ -102,14 +104,21 @@ class ArtworkResource extends JsonResource
|
||||
'categories' => $this->categories->map(fn ($category) => [
|
||||
'id' => (int) $category->id,
|
||||
'slug' => (string) $category->slug,
|
||||
'name' => (string) $category->name,
|
||||
'name' => html_entity_decode((string) $category->name, ENT_QUOTES | ENT_HTML5, 'UTF-8'),
|
||||
'content_type_slug' => (string) ($category->contentType?->slug ?? ''),
|
||||
'url' => $category->contentType ? $category->url : null,
|
||||
'parent' => $category->parent ? [
|
||||
'id' => (int) $category->parent->id,
|
||||
'slug' => (string) $category->parent->slug,
|
||||
'name' => html_entity_decode((string) $category->parent->name, ENT_QUOTES | ENT_HTML5, 'UTF-8'),
|
||||
'content_type_slug' => (string) ($category->parent->contentType?->slug ?? ''),
|
||||
'url' => $category->parent->contentType ? $category->parent->url : null,
|
||||
] : null,
|
||||
])->values(),
|
||||
'tags' => $this->tags->map(fn ($tag) => [
|
||||
'id' => (int) $tag->id,
|
||||
'slug' => (string) $tag->slug,
|
||||
'name' => (string) $tag->name,
|
||||
'name' => html_entity_decode((string) $tag->name, ENT_QUOTES | ENT_HTML5, 'UTF-8'),
|
||||
])->values(),
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user