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
+2
View File
@@ -33,6 +33,8 @@ export type CvTheme = {
photoShape: string;
supportsIcons: boolean;
atsFriendly: boolean;
premium: boolean;
available: boolean;
swatches: string[];
};
+9 -5
View File
@@ -570,17 +570,21 @@ function CustomizeTab({ settings, update, themes }: {
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 1 }}>
{themes.map((t) => {
const active = t.id === settings.themeId;
const locked = t.available === false;
return (
<Paper key={t.id} variant="outlined" role="button" tabIndex={0}
onClick={() => update({ themeId: t.id })}
onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); update({ themeId: t.id }); } }}
sx={{ p: 1, cursor: "pointer", outline: "none", borderColor: active ? "primary.main" : undefined, borderWidth: active ? 2 : 1, "&:focus-visible": { boxShadow: 3 } }}>
<Paper key={t.id} variant="outlined" role="button" tabIndex={locked ? -1 : 0} aria-disabled={locked}
onClick={() => { if (!locked) update({ themeId: t.id }); }}
onKeyDown={(e) => { if (!locked && (e.key === "Enter" || e.key === " ")) { e.preventDefault(); update({ themeId: t.id }); } }}
sx={{ p: 1, cursor: locked ? "not-allowed" : "pointer", opacity: locked ? 0.6 : 1, outline: "none", borderColor: active ? "primary.main" : undefined, borderWidth: active ? 2 : 1, "&:focus-visible": { boxShadow: 3 } }}>
<Stack direction="row" spacing={0.5} sx={{ mb: 0.5 }}>
{t.swatches.map((s, i) => <Box key={i} sx={{ width: 14, height: 14, borderRadius: "3px", bgcolor: s, border: "1px solid rgba(0,0,0,0.1)" }} />)}
</Stack>
<Typography variant="body2" sx={{ fontWeight: 700 }}>{t.name}</Typography>
<Typography variant="caption" color="text.secondary" sx={{ display: "block" }}>{t.category}</Typography>
{t.atsFriendly && <Chip size="small" label="ATS-friendly" color="success" variant="outlined" sx={{ mt: 0.5, height: 18, fontSize: 10 }} />}
<Stack direction="row" spacing={0.5} sx={{ mt: 0.5 }}>
{t.atsFriendly && <Chip size="small" label="ATS-friendly" color="success" variant="outlined" sx={{ height: 18, fontSize: 10 }} />}
{t.premium && <Chip size="small" label={locked ? "Premium" : "Premium unlocked"} color="secondary" variant="outlined" sx={{ height: 18, fontSize: 10 }} />}
</Stack>
</Paper>
);
})}