fix(gallery): fill tall portrait cards to full block width with object-cover crop
- ArtworkCard: add w-full to nova-card-media, use absolute inset-0 on img so object-cover fills the max-height capped box instead of collapsing the width - MasonryGallery.css: add width:100% to media container, position img absolutely so top/bottom is cropped rather than leaving dark gaps - Add React MasonryGallery + ArtworkCard components and entry point - Add recommendation system: UserRecoProfile model/DTO/migration, SuggestedCreatorsController, SuggestedTagsController, Recommendation services, config/recommendations.php - SimilarArtworksController, DiscoverController, HomepageService updates - Update routes (api + web) and discover/for-you views - Refresh favicon assets, update vite.config.js
This commit is contained in:
@@ -7,6 +7,7 @@ namespace App\Services;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Tag;
|
||||
use App\Services\ArtworkSearchService;
|
||||
use App\Services\Recommendation\RecommendationService;
|
||||
use App\Services\UserPreferenceService;
|
||||
use App\Support\AvatarUrl;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
@@ -26,9 +27,10 @@ final class HomepageService
|
||||
private const CACHE_TTL = 300; // 5 minutes
|
||||
|
||||
public function __construct(
|
||||
private readonly ArtworkService $artworks,
|
||||
private readonly ArtworkSearchService $search,
|
||||
private readonly UserPreferenceService $prefs,
|
||||
private readonly ArtworkService $artworks,
|
||||
private readonly ArtworkSearchService $search,
|
||||
private readonly UserPreferenceService $prefs,
|
||||
private readonly RecommendationService $reco,
|
||||
) {}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
@@ -70,6 +72,7 @@ final class HomepageService
|
||||
'is_logged_in' => true,
|
||||
'user_data' => $this->getUserData($user),
|
||||
'hero' => $this->getHeroArtwork(),
|
||||
'for_you' => $this->getForYouPreview($user),
|
||||
'from_following' => $this->getFollowingFeed($user, $prefs),
|
||||
'trending' => $this->getTrending(),
|
||||
'fresh' => $this->getFreshUploads(),
|
||||
@@ -86,6 +89,22 @@ final class HomepageService
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* "For You" homepage preview: first 12 results from the Phase 1 personalised feed.
|
||||
*
|
||||
* Uses RecommendationService which handles Meilisearch retrieval, PHP reranking,
|
||||
* diversity controls, and its own Redis cache layer.
|
||||
*/
|
||||
public function getForYouPreview(\App\Models\User $user, int $limit = 12): array
|
||||
{
|
||||
try {
|
||||
return $this->reco->forYouPreview($user, $limit);
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('HomepageService::getForYouPreview failed', ['error' => $e->getMessage()]);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Sections
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user