feat: gate premium CV themes
CI and Deploy / test (push) Successful in 2m35s
CI and Deploy / deploy (push) Successful in 1m1s

This commit is contained in:
cesnimda
2026-07-30 23:24:19 +02:00
parent fd2c60e70f
commit 09fc2b03f7
6 changed files with 49 additions and 12 deletions
+9 -5
View File
@@ -50,6 +50,7 @@ public sealed class CvTheme
// ATS-friendly = single-column, no sidebar tables/graphics that trip naive resume parsers. Set on
// the single-column themes; surfaced in GET /api/cv/themes so the picker can badge it.
public bool AtsFriendly { get; init; }
public bool Premium { get; init; }
// Which section keys render in the sidebar for two-column layouts (ignored for single/header-band).
public List<string> SidebarSections { get; init; } = new() { "contact", "skills", "languages" };
@@ -79,7 +80,7 @@ public static class CvThemeCatalog
},
new()
{
Id = "executive", Name = "Executive", Category = "Executive",
Premium = true, Id = "executive", Name = "Executive", Category = "Executive",
Description = "High-contrast, serif, leadership-weighted. For senior and client-facing roles.",
Layout = "single", HeaderStyle = "centered", HeadingStyle = "underline",
Accent = "#7c2d12", Ink = "#1c1917", Muted = "#57534e", Line = "#1c1917",
@@ -88,7 +89,7 @@ public static class CvThemeCatalog
},
new()
{
Id = "technical", Name = "Technical", Category = "Technical",
Premium = true, Id = "technical", Name = "Technical", Category = "Technical",
Description = "Dense two-column layout tuned for engineering CVs — skills and projects up front.",
Layout = "sidebar-left", HeaderStyle = "band", HeadingStyle = "bar",
Accent = "#0f4c5c", Ink = "#102a43", Muted = "#486581", SidebarBg = "#0f4c5c", SidebarInk = "#ffffff",
@@ -107,7 +108,7 @@ public static class CvThemeCatalog
},
new()
{
Id = "nordic", Name = "Nordic", Category = "Modern Professional",
Premium = true, Id = "nordic", Name = "Nordic", Category = "Modern Professional",
Description = "Calm cool-blue sidebar, generous whitespace, Scandinavian restraint.",
Layout = "sidebar-right", HeaderStyle = "plain", HeadingStyle = "caps-rule",
Accent = "#3b6ea5", Ink = "#1f2937", Muted = "#4b5563", SidebarBg = "#eef3f8", SidebarInk = "#1f2937",
@@ -116,7 +117,7 @@ public static class CvThemeCatalog
},
new()
{
Id = "elegant", Name = "Elegant", Category = "Creative",
Premium = true, Id = "elegant", Name = "Elegant", Category = "Creative",
Description = "Editorial serif headings over sans body, premium spacing and a plum accent.",
Layout = "single", HeaderStyle = "kicker", HeadingStyle = "underline",
Accent = "#7c3aed", Ink = "#1f2937", Muted = "#4b5563",
@@ -125,7 +126,7 @@ public static class CvThemeCatalog
},
new()
{
Id = "creative", Name = "Creative", Category = "Creative",
Premium = true, Id = "creative", Name = "Creative", Category = "Creative",
Description = "Bold accent sidebar and photo-forward header for design and product roles.",
Layout = "sidebar-left", HeaderStyle = "band", HeadingStyle = "bar",
Accent = "#db2777", Ink = "#18181b", Muted = "#52525b", SidebarBg = "#be185d", SidebarInk = "#ffffff",
@@ -141,6 +142,9 @@ public static class CvThemeCatalog
return Themes.FirstOrDefault(t => t.Id == key) ?? Themes[0];
}
public static bool CanUse(string? id, bool premiumThemes) =>
Exists(id) && (premiumThemes || !Resolve(id).Premium);
public static bool Exists(string? id)
{
var key = (id ?? string.Empty).Trim().ToLowerInvariant();