Build world campaigns rewards and recaps

This commit is contained in:
2026-05-01 11:44:41 +02:00
parent 28e7e46e13
commit 257b0dbef6
100 changed files with 11300 additions and 367 deletions

View File

@@ -62,10 +62,95 @@ final class WorldLaunchSeeder extends Seeder
$now = now();
$currentYear = (int) $now->year;
$springVibes = $this->upsertWorld('spring-vibes-' . $currentYear, [
'title' => 'Spring Vibes ' . $currentYear,
'tagline' => 'Fresh palettes, softer light, and a friendly live participation moment across Skinbase.',
'summary' => 'A live seasonal world for bright artwork, curated collections, creator spotlights, and active submissions.',
'teaser_title' => 'Now live: Spring Vibes',
'teaser_summary' => 'Fresh seasonal artwork, open submissions, and curated highlights are all running inside the current Spring Vibes campaign.',
'description' => 'Spring Vibes is the first fully activated world. It is meant to feel like a live public campaign across homepage, worlds discovery, and upload participation rather than a buried editorial page.',
'theme_key' => 'seasonal',
'accent_color' => '#84cc16',
'accent_color_secondary' => '#14532d',
'background_motif' => 'bloomwave',
'icon_name' => 'fa-solid fa-seedling',
'status' => World::STATUS_PUBLISHED,
'type' => World::TYPE_SEASONAL,
'starts_at' => $now->copy()->subDays(6)->startOfDay(),
'ends_at' => $now->copy()->addDays(18)->endOfDay(),
'promotion_starts_at' => $now->copy()->subDays(2)->startOfDay(),
'promotion_ends_at' => $now->copy()->addDays(12)->endOfDay(),
'is_featured' => true,
'is_active_campaign' => true,
'is_homepage_featured' => true,
'campaign_priority' => 900,
'campaign_label' => 'Live now',
'accepts_submissions' => true,
'participation_mode' => World::PARTICIPATION_MODE_MANUAL_APPROVAL,
'submission_starts_at' => $now->copy()->subDays(4)->startOfDay(),
'submission_ends_at' => $now->copy()->addDays(10)->endOfDay(),
'is_recurring' => true,
'recurrence_key' => 'spring-vibes',
'recurrence_rule' => 'FREQ=YEARLY;BYMONTH=' . $now->month,
'edition_year' => $currentYear,
'cta_label' => 'Join Spring Vibes',
'cta_url' => '/worlds/spring-vibes-' . $currentYear,
'badge_label' => 'Homepage spotlight',
'badge_description' => 'The primary live world promoted across homepage, upload, and worlds discovery surfaces.',
'badge_url' => '/worlds',
'seo_title' => 'Spring Vibes ' . $currentYear . ' on Skinbase',
'seo_description' => 'Spring Vibes is the live seasonal world on Skinbase right now, with open participation and editorially promoted discovery.',
'related_tags_json' => ['spring', 'seasonal', 'fresh', 'bloom'],
'section_order_json' => ['featured_artworks', 'featured_collections', 'featured_creators', 'featured_groups', 'news', 'cards'],
'created_by_user_id' => $editor->id,
'published_at' => $now->copy()->subDays(9),
]);
$springArchive = $this->upsertWorld('spring-vibes-' . ($currentYear - 1), [
'title' => 'Spring Vibes ' . ($currentYear - 1),
'tagline' => 'Last year\'s edition of the recurring spring campaign.',
'summary' => 'Archived spring edition kept visible as part of the recurring worlds record.',
'teaser_title' => 'Spring Vibes archive',
'teaser_summary' => 'The previous edition remains browsable so recurring worlds build continuity over time.',
'description' => 'Spring Vibes archive keeps the prior edition public so the recurring seasonal world feels like a real continuing program.',
'theme_key' => 'seasonal',
'accent_color' => '#65a30d',
'accent_color_secondary' => '#365314',
'background_motif' => 'bloomwave',
'icon_name' => 'fa-solid fa-seedling',
'status' => World::STATUS_ARCHIVED,
'type' => World::TYPE_SEASONAL,
'starts_at' => $now->copy()->subYear()->subDays(6)->startOfDay(),
'ends_at' => $now->copy()->subYear()->addDays(18)->endOfDay(),
'is_featured' => false,
'is_active_campaign' => false,
'is_homepage_featured' => false,
'campaign_priority' => null,
'campaign_label' => 'Archive edition',
'is_recurring' => true,
'recurrence_key' => 'spring-vibes',
'recurrence_rule' => 'FREQ=YEARLY;BYMONTH=' . $now->month,
'edition_year' => $currentYear - 1,
'cta_label' => 'Browse archive',
'cta_url' => '/worlds/spring-vibes-' . ($currentYear - 1),
'badge_label' => 'Archive edition',
'badge_description' => 'The prior Spring Vibes edition remains visible for continuity.',
'badge_url' => '/worlds',
'seo_title' => 'Spring Vibes ' . ($currentYear - 1) . ' archive',
'seo_description' => 'The previous Spring Vibes edition remains public as part of the recurring worlds archive.',
'related_tags_json' => ['spring', 'archive'],
'section_order_json' => ['featured_artworks', 'featured_creators', 'news'],
'parent_world_id' => $springVibes->id,
'created_by_user_id' => $editor->id,
'published_at' => $now->copy()->subYear()->subDays(12),
]);
$retroMonth = $this->upsertWorld('retro-month-' . $currentYear, [
'title' => 'Retro Month ' . $currentYear,
'tagline' => 'Chrome, scanlines, glossy interfaces, and warm-digital nostalgia.',
'summary' => 'A featured editorial world that packages retro-inspired artworks, collections, creators, groups, news, and Nova cards into one recurring seasonal destination.',
'teaser_title' => 'Explore Retro Month',
'teaser_summary' => 'A live supporting campaign for glossy nostalgia, synth palettes, and editorially curated retro culture.',
'description' => "Retro Month curates the surface language of nostalgia into a single destination. It highlights polished throwback artwork, creator identity, collaborative groups, and the editorial context that makes seasonal programming feel intentional instead of accidental.",
'theme_key' => 'retro-month',
'accent_color' => '#f97316',
@@ -76,7 +161,13 @@ final class WorldLaunchSeeder extends Seeder
'type' => World::TYPE_CAMPAIGN,
'starts_at' => $now->copy()->subDays(10)->startOfDay(),
'ends_at' => $now->copy()->addDays(18)->endOfDay(),
'promotion_starts_at' => $now->copy()->subDays(5)->startOfDay(),
'promotion_ends_at' => $now->copy()->addDays(9)->endOfDay(),
'is_featured' => true,
'is_active_campaign' => true,
'is_homepage_featured' => false,
'campaign_priority' => 450,
'campaign_label' => 'Supporting campaign',
'is_recurring' => true,
'recurrence_key' => 'retro-month',
'recurrence_rule' => 'FREQ=YEARLY;BYMONTH=' . $now->month,
@@ -109,6 +200,10 @@ final class WorldLaunchSeeder extends Seeder
'starts_at' => $now->copy()->subYear()->subDays(10)->startOfDay(),
'ends_at' => $now->copy()->subYear()->addDays(18)->endOfDay(),
'is_featured' => false,
'is_active_campaign' => false,
'is_homepage_featured' => false,
'campaign_priority' => null,
'campaign_label' => 'Archive edition',
'is_recurring' => true,
'recurrence_key' => 'retro-month',
'recurrence_rule' => 'FREQ=YEARLY;BYMONTH=' . $now->month,
@@ -131,6 +226,8 @@ final class WorldLaunchSeeder extends Seeder
'title' => 'Pixel Week ' . $currentYear,
'tagline' => 'Small-scale craft, tight palettes, and highly legible form.',
'summary' => 'An upcoming themed week focused on pixel art, sprites, handheld aesthetics, and compact visual systems.',
'teaser_title' => 'Pixel Week is coming up',
'teaser_summary' => 'The next campaign is queued with a tight pixel-art brief, creator spotlights, and themed collections.',
'description' => 'Pixel Week is scheduled as the next clear editorial world, giving the public navigation a real forward-looking destination instead of a dead module stub.',
'theme_key' => 'pixel-week',
'accent_color' => '#38bdf8',
@@ -141,7 +238,13 @@ final class WorldLaunchSeeder extends Seeder
'type' => World::TYPE_EVENT,
'starts_at' => $now->copy()->addDays(24)->startOfDay(),
'ends_at' => $now->copy()->addDays(31)->endOfDay(),
'promotion_starts_at' => $now->copy()->addDays(18)->startOfDay(),
'promotion_ends_at' => $now->copy()->addDays(31)->endOfDay(),
'is_featured' => false,
'is_active_campaign' => true,
'is_homepage_featured' => false,
'campaign_priority' => 300,
'campaign_label' => 'Upcoming campaign',
'is_recurring' => true,
'recurrence_key' => 'pixel-week',
'recurrence_rule' => 'FREQ=YEARLY;BYMONTH=' . $now->copy()->addDays(24)->month,
@@ -255,6 +358,22 @@ final class WorldLaunchSeeder extends Seeder
'published_at' => $now->copy()->subDays(7),
]);
$this->syncRelations($springVibes, [
$this->relation('featured_artworks', WorldRelation::TYPE_ARTWORK, $artworks[2]?->id, 'Live seasonal feature', true, 0),
$this->relation('featured_artworks', WorldRelation::TYPE_ARTWORK, $artworks[1]?->id, 'Community highlight', false, 1),
$this->relation('featured_collections', WorldRelation::TYPE_COLLECTION, $collections[1]?->id, 'Fresh picks', true, 0),
$this->relation('featured_creators', WorldRelation::TYPE_USER, $sceneCreator->id, 'Spring spotlight creator', true, 0),
$this->relation('featured_groups', WorldRelation::TYPE_GROUP, $groups[0]?->id, 'Collaborative feature', true, 0),
$this->relation('news', WorldRelation::TYPE_NEWS, ($newsArticles[0] ?? null)?->id, 'Launch coverage', true, 0),
$this->relation('cards', WorldRelation::TYPE_CARD, ($cards[0] ?? null)?->id, 'Campaign card', true, 0),
]);
$this->syncRelations($springArchive, [
$this->relation('featured_artworks', WorldRelation::TYPE_ARTWORK, $artworks[2]?->id, 'Archive favorite', true, 0),
$this->relation('featured_creators', WorldRelation::TYPE_USER, $sceneCreator->id, 'Returning creator', true, 0),
$this->relation('news', WorldRelation::TYPE_NEWS, ($newsArticles[0] ?? null)?->id, 'Previous launch notes', true, 0),
]);
$this->syncRelations($retroMonth, [
$this->relation('featured_artworks', WorldRelation::TYPE_ARTWORK, $artworks[0]?->id, 'Signature piece', true, 0),
$this->relation('featured_artworks', WorldRelation::TYPE_ARTWORK, $artworks[2]?->id, 'Editorial pick', false, 1),