Auto-escalate package card styling by price tier for a more premium look
Package cards for every brand/model now scale their visual weight with price rank within that model: cheapest stays plain, mid-tier packages get a green-accented card, and the priciest gets a dark "premium" treatment with a glowing border — no extra admin config needed. Also fixes an invalid brand-950 Tailwind class (the palette only goes to 900) that was silently dropping the intended dark-mode colors. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
9e417d0f04
commit
181bb95014
1 changed files with 95 additions and 49 deletions
|
|
@ -45,6 +45,21 @@ export default function ModelPage() {
|
||||||
|
|
||||||
const { model, packages } = data;
|
const { model, packages } = data;
|
||||||
|
|
||||||
|
// Preis-Rang innerhalb dieses Modells bestimmt die optische Wucht der Kachel:
|
||||||
|
// die guenstigste Option bleibt schlicht/hell, dazwischen liegende Pakete
|
||||||
|
// bekommen einen Akzent-Rahmen, das teuerste Paket eine dunkle "Premium"-Karte.
|
||||||
|
// Das braucht keine zusaetzliche Admin-Einstellung und passt sich automatisch an.
|
||||||
|
const rankById = new Map(
|
||||||
|
[...packages].sort((a, b) => a.total_price - b.total_price).map((p, i) => [p.id, i])
|
||||||
|
);
|
||||||
|
const tierOf = (pkg) => {
|
||||||
|
if (packages.length <= 1) return 'plain';
|
||||||
|
const rank = rankById.get(pkg.id);
|
||||||
|
if (rank === 0) return 'plain';
|
||||||
|
if (rank === packages.length - 1) return 'premium';
|
||||||
|
return 'accent';
|
||||||
|
};
|
||||||
|
|
||||||
const contactUrl = (pkg) => {
|
const contactUrl = (pkg) => {
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
brand: model.brand_name,
|
brand: model.brand_name,
|
||||||
|
|
@ -72,13 +87,19 @@ export default function ModelPage() {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="grid gap-6 sm:grid-cols-2 xl:grid-cols-3">
|
<div className="grid gap-6 sm:grid-cols-2 xl:grid-cols-3">
|
||||||
{packages.map((pkg) => (
|
{packages.map((pkg) => {
|
||||||
|
const tier = tierOf(pkg);
|
||||||
|
const isPremium = tier === 'premium';
|
||||||
|
|
||||||
|
return (
|
||||||
<div
|
<div
|
||||||
key={pkg.id}
|
key={pkg.id}
|
||||||
className={`relative flex flex-col rounded-xl border bg-white p-6 shadow-sm dark:bg-neutral-900 ${
|
className={`relative flex flex-col rounded-xl border p-6 ${
|
||||||
pkg.is_featured
|
isPremium
|
||||||
? 'border-brand-500 ring-2 ring-brand-500/50 dark:border-brand-400 dark:ring-brand-400/40'
|
? 'border-brand-500/50 bg-gradient-to-br from-neutral-900 via-neutral-900 to-brand-900/60 shadow-xl shadow-brand-500/20 ring-1 ring-brand-500/40 dark:border-brand-400/60 dark:shadow-brand-400/25 dark:ring-brand-400/50'
|
||||||
: 'border-neutral-200 dark:border-neutral-800'
|
: tier === 'accent'
|
||||||
|
? 'border-2 border-brand-400 bg-brand-50 shadow-lg shadow-brand-500/10 dark:border-brand-500/70 dark:bg-brand-900/20'
|
||||||
|
: 'border-neutral-200 bg-white shadow-sm dark:border-neutral-800 dark:bg-neutral-900'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{pkg.is_featured && (
|
{pkg.is_featured && (
|
||||||
|
|
@ -88,20 +109,40 @@ export default function ModelPage() {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{pkg.icon_name && (
|
{pkg.icon_name && (
|
||||||
<div className="mb-3 flex h-11 w-11 items-center justify-center rounded-full bg-brand-100 text-brand-600 dark:bg-brand-900/40 dark:text-brand-400">
|
<div
|
||||||
|
className={`mb-3 flex h-11 w-11 items-center justify-center rounded-full ${
|
||||||
|
isPremium
|
||||||
|
? 'bg-brand-500/15 text-brand-400 ring-1 ring-brand-500/40'
|
||||||
|
: 'bg-brand-100 text-brand-600 dark:bg-brand-900/40 dark:text-brand-400'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<DynamicIcon name={pkg.icon_name} className="h-6 w-6" />
|
<DynamicIcon name={pkg.icon_name} className="h-6 w-6" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<h2 className="text-lg font-bold text-neutral-900 dark:text-white">{pkg.name}</h2>
|
<h2 className={`text-lg font-bold ${isPremium ? 'text-white' : 'text-neutral-900 dark:text-white'}`}>
|
||||||
{pkg.tagline && <p className="mt-1 text-sm text-neutral-500 dark:text-neutral-400">{pkg.tagline}</p>}
|
{pkg.name}
|
||||||
|
</h2>
|
||||||
|
{pkg.tagline && (
|
||||||
|
<p className={`mt-1 text-sm ${isPremium ? 'text-neutral-400' : 'text-neutral-500 dark:text-neutral-400'}`}>
|
||||||
|
{pkg.tagline}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="my-4">
|
<div className="my-4">
|
||||||
<p className="text-xs uppercase tracking-wide text-neutral-400">{t('modelPage.totalPrice')}</p>
|
<p className={`text-xs uppercase tracking-wide ${isPremium ? 'text-neutral-500' : 'text-neutral-400'}`}>
|
||||||
<p className="text-2xl font-extrabold text-brand-600 dark:text-brand-400">{formatPrice(pkg.total_price)}</p>
|
{t('modelPage.totalPrice')}
|
||||||
|
</p>
|
||||||
|
<p className={`text-2xl font-extrabold ${isPremium ? 'text-brand-400' : 'text-brand-600 dark:text-brand-400'}`}>
|
||||||
|
{formatPrice(pkg.total_price)}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul className="mb-5 flex-1 list-disc space-y-1 pl-5 text-sm text-neutral-700 dark:text-neutral-300">
|
<ul
|
||||||
|
className={`mb-5 flex-1 list-disc space-y-1 pl-5 text-sm ${
|
||||||
|
isPremium ? 'text-neutral-300' : 'text-neutral-700 dark:text-neutral-300'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
{pkg.products.map((product) => (
|
{pkg.products.map((product) => (
|
||||||
<li key={product.id}>
|
<li key={product.id}>
|
||||||
{product.name_override || product.scraped_name || t('modelPage.productLoading')}
|
{product.name_override || product.scraped_name || t('modelPage.productLoading')}
|
||||||
|
|
@ -117,13 +158,18 @@ export default function ModelPage() {
|
||||||
<Link
|
<Link
|
||||||
to={contactUrl(pkg)}
|
to={contactUrl(pkg)}
|
||||||
className={`inline-block rounded-md px-4 py-2 text-center text-sm font-semibold text-white ${
|
className={`inline-block rounded-md px-4 py-2 text-center text-sm font-semibold text-white ${
|
||||||
pkg.is_featured ? 'bg-brand-600 hover:bg-brand-700' : 'bg-brand-500 hover:bg-brand-600'
|
isPremium
|
||||||
|
? 'bg-brand-500 shadow-lg shadow-brand-500/30 hover:bg-brand-400'
|
||||||
|
: tier === 'accent'
|
||||||
|
? 'bg-brand-600 hover:bg-brand-700'
|
||||||
|
: 'bg-brand-500 hover:bg-brand-600'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{t('modelPage.requestContact')}
|
{t('modelPage.requestContact')}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue