Extract season overview/workflow cards and add sponsor seed data

Splits AdminSeasonsView into AdminSeasonOverviewCard and AdminSeasonWorkflowCard
for cleaner separation of concerns. Adds SeedSponsorsBootstrapper with demo
sponsor SVG assets and extends SeedCatalog with sponsor seed entries.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
AzuTear
2026-06-29 09:08:56 +02:00
parent 1ab26ec2fd
commit c466348d18
11 changed files with 668 additions and 446 deletions
+40
View File
@@ -7,6 +7,7 @@ internal sealed record CandidateSeed(string CategorySlug, string DisplayName, st
internal sealed record WinnerSeed(int Year, string CategorySlug, string DisplayName, string ChannelSlug, string Platform);
internal sealed record SiteFaqSeed(string Question, string Answer);
internal sealed record SiteSocialSeed(string Label, string Platform, string Url, string Icon);
internal sealed record SponsorSeed(string Name, string WebsiteUrl, string LogoUrl, string Description, string Tier, int SortOrder);
internal static class SeedCatalog
{
@@ -141,4 +142,43 @@ Partner werden im Rahmen der Show und auf den öffentlichen Kontaktflächen gena
new(2023, "community-liebling-rising-star", "Sora Blau", "@sorablau", "YouTube"),
new(2023, "best-collab-duo-rising-star", "Yuki & Melo", "@yukistern", "Twitch"),
];
internal static readonly SponsorSeed[] DemoSponsorSeeds =
[
new(
"HoshiForge Studio",
"https://hoshiforge.example",
"/demo/sponsors/hoshiforge-studio.svg",
"Branding-, Overlay- und Debuet-Visuals fuer VTuber-Projekte und Community-Events.",
"Presenting Sponsor",
10),
new(
"NekoPixel Energy",
"https://nekopixel.example",
"/demo/sponsors/nekopixel-energy.svg",
"Community-fokussierter Drink-Partner fuer lange Showabende, Watchpartys und Creator-Collabs.",
"Gold Partner",
20),
new(
"PrismLoop Audio",
"https://prismloop.example",
"/demo/sponsors/prismloop-audio.svg",
"Audio-Tools, Intro-Packs und Stream-Sounddesign fuer Live-Shows und Highlight-Clips.",
"Gold Partner",
30),
new(
"CloudBeacon Hosting",
"https://cloudbeacon.example",
"/demo/sponsors/cloudbeacon-hosting.svg",
"Skalierbares Hosting fuer Voting, Landingpages und Event-Traffic rund um Showtage.",
"Tech Partner",
40),
new(
"ChibiCanvas Market",
"https://chibicanvas.example",
"/demo/sponsors/chibicanvas-market.svg",
"Merch-, Sticker- und Artist-Marketplace mit Fokus auf VTuber, Emotes und Fanartikel.",
"Community Partner",
50),
];
}
+1
View File
@@ -22,6 +22,7 @@ public static partial class SeedDataBootstrapper
if (seasons.TryGetValue(2026, out var currentSeason))
{
await EnsureCandidatesAsync(db, currentSeason, SeedCatalog.CurrentCandidateSeeds);
await EnsureSponsorsAsync(db, currentSeason);
await EnsureSeedOperationalDataAsync(db, currentSeason);
}
+40
View File
@@ -0,0 +1,40 @@
using Backend.Domain;
using Microsoft.EntityFrameworkCore;
namespace Backend.Data;
public static partial class SeedDataBootstrapper
{
private static async Task EnsureSponsorsAsync(AwardsDbContext db, Season season)
{
var existingSponsors = await db.Sponsors
.Where(item => item.SeasonId == season.Id)
.ToListAsync();
foreach (var seed in SeedCatalog.DemoSponsorSeeds)
{
var sponsor = existingSponsors.FirstOrDefault(item =>
string.Equals(item.Name, seed.Name, StringComparison.OrdinalIgnoreCase))
?? new Sponsor
{
SeasonId = season.Id,
CreatedAt = DateTimeOffset.UtcNow,
};
sponsor.Name = seed.Name;
sponsor.WebsiteUrl = seed.WebsiteUrl;
sponsor.LogoUrl = seed.LogoUrl;
sponsor.Description = seed.Description;
sponsor.Tier = seed.Tier;
sponsor.SortOrder = seed.SortOrder;
sponsor.IsVisible = true;
sponsor.UpdatedAt = DateTimeOffset.UtcNow;
if (sponsor.Id == 0)
{
db.Sponsors.Add(sponsor);
existingSponsors.Add(sponsor);
}
}
}
}