From c6c4d630fe5f2bcf21a9c21ce7215fe193ad500b Mon Sep 17 00:00:00 2001 From: Till JS Date: Thu, 16 Apr 2026 12:38:30 +0200 Subject: [PATCH] refactor(subscriptions): compact row-based card layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SubscriptionCard and PackageCard were large centered multi-cell cards designed for a standalone pricing page. In the workbench context (narrow card inside a carousel), they wasted too much vertical space for users to compare plans at a glance. Redesigned both as horizontal rows: - Icon | name+mana | price | action — all in one line - Badges (current/popular) inline next to the plan name - No more 3-column internal grid with 70px min-height cells - Clickable row replaces separate SubscriptionButton SubscriptionPage: - Drop the big centered header (icon + title + subtitle) - Move Usage + Costs into a collapsed
section - Section titles as small-caps labels - Billing toggle at top, plans immediately visible Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/subscriptions/src/PackageCard.svelte | 271 ++++---------- .../subscriptions/src/SubscriptionCard.svelte | 353 +++++++----------- .../src/pages/SubscriptionPage.svelte | 238 ++++-------- 3 files changed, 301 insertions(+), 561 deletions(-) diff --git a/packages/subscriptions/src/PackageCard.svelte b/packages/subscriptions/src/PackageCard.svelte index ec646cbe1..db7ce263e 100644 --- a/packages/subscriptions/src/PackageCard.svelte +++ b/packages/subscriptions/src/PackageCard.svelte @@ -1,236 +1,127 @@ -
(isHovered = true)} - onmouseleave={() => (isHovered = false)} - role="article" -> - {#if pkg.popular} -
- {popularLabel} -
- {/if} - - -

- {pkg.name} -

- - -
- -
-
- -
-
- - -
-

- {pkg.manaAmount} -

-

{manaLabel}

-
- - -
-

- {formatPrice(pkg)} -

-

{oneTimeLabel}

-
+
+
+ + {pkg.name} + {#if pkg.popular} + {popularLabel} + {/if} + + {pkg.manaAmount.toLocaleString('de-DE')} Mana +
+ + {formatPrice(pkg)} + {buyLabel} + diff --git a/packages/subscriptions/src/SubscriptionCard.svelte b/packages/subscriptions/src/SubscriptionCard.svelte index f4ac78d7d..2e55240fe 100644 --- a/packages/subscriptions/src/SubscriptionCard.svelte +++ b/packages/subscriptions/src/SubscriptionCard.svelte @@ -1,6 +1,5 @@ -
(isHovered = true)} - onmouseleave={() => (isHovered = false)} - role="article" + diff --git a/packages/subscriptions/src/pages/SubscriptionPage.svelte b/packages/subscriptions/src/pages/SubscriptionPage.svelte index 158d977d0..219898b66 100644 --- a/packages/subscriptions/src/pages/SubscriptionPage.svelte +++ b/packages/subscriptions/src/pages/SubscriptionPage.svelte @@ -7,35 +7,22 @@ import UsageCard from '../UsageCard.svelte'; import CostCard from '../CostCard.svelte'; - // Import default data import defaultSubscriptionData from '../data/subscriptionData.json'; import defaultAppCosts from '../data/appCosts.json'; import defaultUsageData from '../data/defaultUsageData.json'; interface Props { - /** App name for the page title */ appName: string; - /** Handler when user selects a subscription plan */ onSubscribe: (planId: string) => void; - /** Handler when user selects a mana package */ onBuyPackage: (packageId: string) => void; - /** Current plan ID (e.g., 'free', 'Mana_Stream_Small_v1') */ currentPlanId?: string; - /** Current user's usage data (optional, uses defaults if not provided) */ usageData?: UsageData; - /** Custom subscription plans (optional, uses defaults if not provided) */ subscriptions?: SubscriptionPlan[]; - /** Custom mana packages (optional, uses defaults if not provided) */ packages?: ManaPackage[]; - /** Custom cost items (optional, uses defaults if not provided) */ costs?: CostItem[]; - /** Page title */ pageTitle?: string; - /** Subscriptions section title */ subscriptionsTitle?: string; - /** One-time purchases section title */ packagesTitle?: string; - /** Yearly discount label */ yearlyDiscount?: string; } @@ -54,194 +41,125 @@ yearlyDiscount = '33%', }: Props = $props(); - // State let billingCycle = $state('monthly'); - // Get current plan name for display const currentPlanName = $derived(() => { const plan = subscriptions.find((p) => p.id === currentPlanId); return plan?.name || 'Free'; }); - // Get all subscription plans for current billing cycle function getSubscriptionPlans() { return subscriptions.filter((plan) => plan.id !== 'free' && plan.billingCycle === billingCycle); } - // Check if a plan is the current plan function isCurrentPlan(planId: string) { if (currentPlanId === 'free' && planId === 'free') return true; return planId === currentPlanId; } - - Mana - {appName} - - -
- -
-
- -
-
- - - -
-

{pageTitle}

-

Wähle das passende Paket für deine Bedürfnisse

-
- - -
-
- - -
-
- - -
- (billingCycle = cycle)} - {yearlyDiscount} - /> -
- - -
-

{subscriptionsTitle}

- -
- - plan.id === 'free')!} - onSelect={onSubscribe} - isCurrentPlan={isCurrentPlan('free')} - /> - - - {#each getSubscriptionPlans() as plan} - - {/each} -
-
- - -
-

{packagesTitle}

- -
- {#each packages as pkg} - - {/each} -
-
-
+
+ +
+ (billingCycle = cycle)} {yearlyDiscount} />
+ + +
+

{subscriptionsTitle}

+
+ plan.id === 'free')} + onSelect={onSubscribe} + isCurrentPlan={isCurrentPlan('free')} + /> + {#each getSubscriptionPlans() as plan} + + {/each} +
+
+ + +
+

{packagesTitle}

+
+ {#each packages as pkg} + + {/each} +
+
+ + +
+
+ Verbrauch & Kosten +
+ + +
+
+