mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-23 21:36:41 +02:00
style: auto-format codebase with Prettier
Applied formatting to 1487+ files using pnpm format:write - TypeScript/JavaScript files - Svelte components - Astro pages - JSON configs - Markdown docs 13 files still need manual review (Astro JSX comments)
This commit is contained in:
parent
0241f5554c
commit
d36b321d9d
3952 changed files with 661498 additions and 739751 deletions
|
|
@ -6,69 +6,79 @@ import Container from '../atoms/Container.astro';
|
|||
import Button from '../atoms/Button.astro';
|
||||
|
||||
interface CTA {
|
||||
text: string;
|
||||
href: string;
|
||||
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
|
||||
text: string;
|
||||
href: string;
|
||||
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
primaryCta?: CTA;
|
||||
secondaryCta?: CTA;
|
||||
variant?: 'default' | 'highlighted' | 'minimal';
|
||||
class?: string;
|
||||
id?: string;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
primaryCta?: CTA;
|
||||
secondaryCta?: CTA;
|
||||
variant?: 'default' | 'highlighted' | 'minimal';
|
||||
class?: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
subtitle,
|
||||
primaryCta,
|
||||
secondaryCta,
|
||||
variant = 'default',
|
||||
class: className = '',
|
||||
id
|
||||
title,
|
||||
subtitle,
|
||||
primaryCta,
|
||||
secondaryCta,
|
||||
variant = 'default',
|
||||
class: className = '',
|
||||
id,
|
||||
} = Astro.props;
|
||||
|
||||
const variantStyles = {
|
||||
default: 'bg-[var(--color-background-page)]',
|
||||
highlighted: 'bg-[var(--color-primary)]/10 border-y border-[var(--color-primary)]/20',
|
||||
minimal: ''
|
||||
default: 'bg-[var(--color-background-page)]',
|
||||
highlighted: 'bg-[var(--color-primary)]/10 border-y border-[var(--color-primary)]/20',
|
||||
minimal: '',
|
||||
};
|
||||
---
|
||||
|
||||
<section id={id} class:list={["py-16 md:py-24", variantStyles[variant], className]}>
|
||||
<Container size="md">
|
||||
<div class="text-center space-y-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-[var(--color-text-primary)] leading-tight">
|
||||
<slot name="title">{title}</slot>
|
||||
</h2>
|
||||
<section id={id} class:list={['py-16 md:py-24', variantStyles[variant], className]}>
|
||||
<Container size="md">
|
||||
<div class="text-center space-y-6">
|
||||
<h2
|
||||
class="text-2xl sm:text-3xl md:text-4xl font-bold text-[var(--color-text-primary)] leading-tight"
|
||||
>
|
||||
<slot name="title">{title}</slot>
|
||||
</h2>
|
||||
|
||||
{subtitle && (
|
||||
<p class="text-base sm:text-lg text-[var(--color-text-secondary)] max-w-2xl mx-auto leading-relaxed">
|
||||
{subtitle}
|
||||
</p>
|
||||
)}
|
||||
{
|
||||
subtitle && (
|
||||
<p class="text-base sm:text-lg text-[var(--color-text-secondary)] max-w-2xl mx-auto leading-relaxed">
|
||||
{subtitle}
|
||||
</p>
|
||||
)
|
||||
}
|
||||
|
||||
{(primaryCta || secondaryCta) && (
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center pt-4">
|
||||
{primaryCta && (
|
||||
<Button href={primaryCta.href} variant={primaryCta.variant ?? 'primary'} size="lg">
|
||||
<slot name="primaryCtaIcon" />
|
||||
{primaryCta.text}
|
||||
</Button>
|
||||
)}
|
||||
{secondaryCta && (
|
||||
<Button href={secondaryCta.href} variant={secondaryCta.variant ?? 'secondary'} size="lg">
|
||||
<slot name="secondaryCtaIcon" />
|
||||
{secondaryCta.text}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{
|
||||
(primaryCta || secondaryCta) && (
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center pt-4">
|
||||
{primaryCta && (
|
||||
<Button href={primaryCta.href} variant={primaryCta.variant ?? 'primary'} size="lg">
|
||||
<slot name="primaryCtaIcon" />
|
||||
{primaryCta.text}
|
||||
</Button>
|
||||
)}
|
||||
{secondaryCta && (
|
||||
<Button
|
||||
href={secondaryCta.href}
|
||||
variant={secondaryCta.variant ?? 'secondary'}
|
||||
size="lg"
|
||||
>
|
||||
<slot name="secondaryCtaIcon" />
|
||||
{secondaryCta.text}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
<slot />
|
||||
</div>
|
||||
</Container>
|
||||
<slot />
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -7,109 +7,119 @@ import Container from '../atoms/Container.astro';
|
|||
import SectionHeader from '../atoms/SectionHeader.astro';
|
||||
|
||||
interface FAQItem {
|
||||
question: string;
|
||||
answer: string;
|
||||
question: string;
|
||||
answer: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
faqs: FAQItem[];
|
||||
class?: string;
|
||||
id?: string;
|
||||
singleExpand?: boolean;
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
faqs: FAQItem[];
|
||||
class?: string;
|
||||
id?: string;
|
||||
singleExpand?: boolean;
|
||||
}
|
||||
|
||||
const {
|
||||
title = 'Frequently Asked Questions',
|
||||
subtitle,
|
||||
faqs,
|
||||
class: className = '',
|
||||
id = 'faq',
|
||||
singleExpand = true
|
||||
title = 'Frequently Asked Questions',
|
||||
subtitle,
|
||||
faqs,
|
||||
class: className = '',
|
||||
id = 'faq',
|
||||
singleExpand = true,
|
||||
} = Astro.props;
|
||||
|
||||
const sectionId = `faq-section-${Math.random().toString(36).substring(7)}`;
|
||||
---
|
||||
|
||||
<section id={id} class:list={["py-16 md:py-24", className]}>
|
||||
<Container size="md">
|
||||
<SectionHeader title={title} subtitle={subtitle} />
|
||||
<section id={id} class:list={['py-16 md:py-24', className]}>
|
||||
<Container size="md">
|
||||
<SectionHeader title={title} subtitle={subtitle} />
|
||||
|
||||
<div class="max-w-3xl mx-auto space-y-4" data-faq-container={singleExpand ? sectionId : undefined}>
|
||||
{faqs.map((faq, index) => (
|
||||
<details class="group" data-faq-item={singleExpand ? sectionId : undefined}>
|
||||
<summary class="cursor-pointer list-none">
|
||||
<div class="bg-[var(--color-background-card)] rounded-xl p-5 sm:p-6 border border-[var(--color-border)] hover:bg-[var(--color-background-card-hover)] hover:border-[var(--color-border-hover,var(--color-border))] transition-all duration-200">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<h3 class="font-semibold text-base sm:text-lg text-[var(--color-text-primary)] pr-4 group-open:text-[var(--color-primary)] transition-colors text-left">
|
||||
{faq.question}
|
||||
</h3>
|
||||
<div class="flex-shrink-0 w-5 h-5 text-[var(--color-primary)] transition-transform duration-300 group-open:rotate-180">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-hidden max-h-0 group-open:max-h-[1000px] transition-all duration-300 ease-in-out">
|
||||
<div class="pt-4 text-[var(--color-text-secondary)] leading-relaxed text-sm sm:text-base prose prose-sm max-w-none">
|
||||
<Fragment set:html={faq.answer} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</summary>
|
||||
</details>
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
class="max-w-3xl mx-auto space-y-4"
|
||||
data-faq-container={singleExpand ? sectionId : undefined}
|
||||
>
|
||||
{
|
||||
faqs.map((faq, index) => (
|
||||
<details class="group" data-faq-item={singleExpand ? sectionId : undefined}>
|
||||
<summary class="cursor-pointer list-none">
|
||||
<div class="bg-[var(--color-background-card)] rounded-xl p-5 sm:p-6 border border-[var(--color-border)] hover:bg-[var(--color-background-card-hover)] hover:border-[var(--color-border-hover,var(--color-border))] transition-all duration-200">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<h3 class="font-semibold text-base sm:text-lg text-[var(--color-text-primary)] pr-4 group-open:text-[var(--color-primary)] transition-colors text-left">
|
||||
{faq.question}
|
||||
</h3>
|
||||
<div class="flex-shrink-0 w-5 h-5 text-[var(--color-primary)] transition-transform duration-300 group-open:rotate-180">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 9l-7 7-7-7"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-hidden max-h-0 group-open:max-h-[1000px] transition-all duration-300 ease-in-out">
|
||||
<div class="pt-4 text-[var(--color-text-secondary)] leading-relaxed text-sm sm:text-base prose prose-sm max-w-none">
|
||||
<Fragment set:html={faq.answer} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</summary>
|
||||
</details>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
<slot name="contact" />
|
||||
<slot />
|
||||
</Container>
|
||||
<slot name="contact" />
|
||||
<slot />
|
||||
</Container>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
details summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
details summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
details[open] summary ~ * {
|
||||
animation: slideDown 0.3s ease-out;
|
||||
}
|
||||
details[open] summary ~ * {
|
||||
animation: slideDown 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script define:vars={{ sectionId, singleExpand }}>
|
||||
if (singleExpand) {
|
||||
function setupFAQ() {
|
||||
const container = document.querySelector(`[data-faq-container="${sectionId}"]`);
|
||||
if (!container) return;
|
||||
if (singleExpand) {
|
||||
function setupFAQ() {
|
||||
const container = document.querySelector(`[data-faq-container="${sectionId}"]`);
|
||||
if (!container) return;
|
||||
|
||||
const items = container.querySelectorAll(`[data-faq-item="${sectionId}"]`);
|
||||
const items = container.querySelectorAll(`[data-faq-item="${sectionId}"]`);
|
||||
|
||||
items.forEach((item) => {
|
||||
item.addEventListener('toggle', (e) => {
|
||||
if (e.target.open) {
|
||||
items.forEach((otherItem) => {
|
||||
if (otherItem !== e.target && otherItem.open) {
|
||||
otherItem.open = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
items.forEach((item) => {
|
||||
item.addEventListener('toggle', (e) => {
|
||||
if (e.target.open) {
|
||||
items.forEach((otherItem) => {
|
||||
if (otherItem !== e.target && otherItem.open) {
|
||||
otherItem.open = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setupFAQ();
|
||||
document.addEventListener('astro:page-load', setupFAQ);
|
||||
}
|
||||
setupFAQ();
|
||||
document.addEventListener('astro:page-load', setupFAQ);
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -8,88 +8,88 @@ import Card from '../atoms/Card.astro';
|
|||
import SectionHeader from '../atoms/SectionHeader.astro';
|
||||
|
||||
interface Feature {
|
||||
icon: string;
|
||||
title: string;
|
||||
description: string;
|
||||
href?: string;
|
||||
icon: string;
|
||||
title: string;
|
||||
description: string;
|
||||
href?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
features: Feature[];
|
||||
columns?: 2 | 3 | 4;
|
||||
variant?: 'cards' | 'simple' | 'icons-left';
|
||||
class?: string;
|
||||
id?: string;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
features: Feature[];
|
||||
columns?: 2 | 3 | 4;
|
||||
variant?: 'cards' | 'simple' | 'icons-left';
|
||||
class?: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
subtitle,
|
||||
features,
|
||||
columns = 3,
|
||||
variant = 'cards',
|
||||
class: className = '',
|
||||
id
|
||||
title,
|
||||
subtitle,
|
||||
features,
|
||||
columns = 3,
|
||||
variant = 'cards',
|
||||
class: className = '',
|
||||
id,
|
||||
} = Astro.props;
|
||||
|
||||
const gridCols = {
|
||||
2: 'md:grid-cols-2',
|
||||
3: 'md:grid-cols-2 lg:grid-cols-3',
|
||||
4: 'md:grid-cols-2 lg:grid-cols-4'
|
||||
2: 'md:grid-cols-2',
|
||||
3: 'md:grid-cols-2 lg:grid-cols-3',
|
||||
4: 'md:grid-cols-2 lg:grid-cols-4',
|
||||
};
|
||||
---
|
||||
|
||||
<section id={id} class:list={["py-16 md:py-24", className]}>
|
||||
<Container>
|
||||
<SectionHeader title={title} subtitle={subtitle} />
|
||||
<section id={id} class:list={['py-16 md:py-24', className]}>
|
||||
<Container>
|
||||
<SectionHeader title={title} subtitle={subtitle} />
|
||||
|
||||
<div class:list={["grid gap-6 md:gap-8", gridCols[columns]]}>
|
||||
{features.map((feature) => (
|
||||
variant === 'cards' ? (
|
||||
<Card variant="hover" padding="lg" as={feature.href ? 'a' : 'div'} href={feature.href}>
|
||||
<div class="flex flex-col items-center text-center h-full">
|
||||
<div class="text-4xl sm:text-5xl mb-4 transform group-hover:scale-110 transition-transform duration-300">
|
||||
{feature.icon}
|
||||
</div>
|
||||
<h3 class="font-semibold text-lg sm:text-xl text-[var(--color-text-primary)] mb-3">
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm sm:text-base leading-relaxed">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
) : variant === 'icons-left' ? (
|
||||
<div class="flex gap-4">
|
||||
<div class="flex-shrink-0 text-3xl">
|
||||
{feature.icon}
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-semibold text-lg text-[var(--color-text-primary)] mb-2">
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm leading-relaxed">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div class="text-center">
|
||||
<div class="text-4xl mb-4">{feature.icon}</div>
|
||||
<h3 class="font-semibold text-lg text-[var(--color-text-primary)] mb-2">
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm leading-relaxed">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
))}
|
||||
</div>
|
||||
<div class:list={['grid gap-6 md:gap-8', gridCols[columns]]}>
|
||||
{
|
||||
features.map((feature) =>
|
||||
variant === 'cards' ? (
|
||||
<Card variant="hover" padding="lg" as={feature.href ? 'a' : 'div'} href={feature.href}>
|
||||
<div class="flex flex-col items-center text-center h-full">
|
||||
<div class="text-4xl sm:text-5xl mb-4 transform group-hover:scale-110 transition-transform duration-300">
|
||||
{feature.icon}
|
||||
</div>
|
||||
<h3 class="font-semibold text-lg sm:text-xl text-[var(--color-text-primary)] mb-3">
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm sm:text-base leading-relaxed">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
) : variant === 'icons-left' ? (
|
||||
<div class="flex gap-4">
|
||||
<div class="flex-shrink-0 text-3xl">{feature.icon}</div>
|
||||
<div>
|
||||
<h3 class="font-semibold text-lg text-[var(--color-text-primary)] mb-2">
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm leading-relaxed">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div class="text-center">
|
||||
<div class="text-4xl mb-4">{feature.icon}</div>
|
||||
<h3 class="font-semibold text-lg text-[var(--color-text-primary)] mb-2">
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p class="text-[var(--color-text-secondary)] text-sm leading-relaxed">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
<slot name="highlight" />
|
||||
<slot />
|
||||
</Container>
|
||||
<slot name="highlight" />
|
||||
<slot />
|
||||
</Container>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -9,132 +9,136 @@ import Badge from '../atoms/Badge.astro';
|
|||
import SectionHeader from '../atoms/SectionHeader.astro';
|
||||
|
||||
interface PricingFeature {
|
||||
text: string;
|
||||
included: boolean;
|
||||
text: string;
|
||||
included: boolean;
|
||||
}
|
||||
|
||||
interface PricingPlan {
|
||||
name: string;
|
||||
description?: string;
|
||||
price: string;
|
||||
period?: string;
|
||||
features: PricingFeature[] | string[];
|
||||
cta: {
|
||||
text: string;
|
||||
href: string;
|
||||
};
|
||||
highlighted?: boolean;
|
||||
badge?: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
price: string;
|
||||
period?: string;
|
||||
features: PricingFeature[] | string[];
|
||||
cta: {
|
||||
text: string;
|
||||
href: string;
|
||||
};
|
||||
highlighted?: boolean;
|
||||
badge?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
plans: PricingPlan[];
|
||||
class?: string;
|
||||
id?: string;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
plans: PricingPlan[];
|
||||
class?: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
subtitle,
|
||||
plans,
|
||||
class: className = '',
|
||||
id = 'pricing'
|
||||
} = Astro.props;
|
||||
const { title, subtitle, plans, class: className = '', id = 'pricing' } = Astro.props;
|
||||
|
||||
// Normalize features to always have { text, included } format
|
||||
function normalizeFeatures(features: PricingFeature[] | string[]): PricingFeature[] {
|
||||
return features.map(f => typeof f === 'string' ? { text: f, included: true } : f);
|
||||
return features.map((f) => (typeof f === 'string' ? { text: f, included: true } : f));
|
||||
}
|
||||
---
|
||||
|
||||
<section id={id} class:list={["py-16 md:py-24", className]}>
|
||||
<Container>
|
||||
<SectionHeader title={title} subtitle={subtitle} />
|
||||
<section id={id} class:list={['py-16 md:py-24', className]}>
|
||||
<Container>
|
||||
<SectionHeader title={title} subtitle={subtitle} />
|
||||
|
||||
<div class:list={[
|
||||
"grid gap-6 md:gap-8",
|
||||
plans.length === 2 && "md:grid-cols-2 max-w-4xl mx-auto",
|
||||
plans.length === 3 && "md:grid-cols-3",
|
||||
plans.length >= 4 && "md:grid-cols-2 lg:grid-cols-4"
|
||||
]}>
|
||||
{plans.map((plan) => (
|
||||
<Card
|
||||
variant={plan.highlighted ? 'glow' : 'bordered'}
|
||||
padding="lg"
|
||||
class:list={[
|
||||
"flex flex-col relative",
|
||||
plan.highlighted && "ring-2 ring-[var(--color-primary)] scale-105"
|
||||
]}
|
||||
>
|
||||
{plan.badge && (
|
||||
<div class="absolute -top-3 left-1/2 -translate-x-1/2">
|
||||
<Badge variant="primary">{plan.badge}</Badge>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
class:list={[
|
||||
'grid gap-6 md:gap-8',
|
||||
plans.length === 2 && 'md:grid-cols-2 max-w-4xl mx-auto',
|
||||
plans.length === 3 && 'md:grid-cols-3',
|
||||
plans.length >= 4 && 'md:grid-cols-2 lg:grid-cols-4',
|
||||
]}
|
||||
>
|
||||
{
|
||||
plans.map((plan) => (
|
||||
<Card
|
||||
variant={plan.highlighted ? 'glow' : 'bordered'}
|
||||
padding="lg"
|
||||
class:list={[
|
||||
'flex flex-col relative',
|
||||
plan.highlighted && 'ring-2 ring-[var(--color-primary)] scale-105',
|
||||
]}
|
||||
>
|
||||
{plan.badge && (
|
||||
<div class="absolute -top-3 left-1/2 -translate-x-1/2">
|
||||
<Badge variant="primary">{plan.badge}</Badge>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div class="text-center mb-6">
|
||||
<h3 class="text-xl font-bold text-[var(--color-text-primary)] mb-2">
|
||||
{plan.name}
|
||||
</h3>
|
||||
{plan.description && (
|
||||
<p class="text-sm text-[var(--color-text-secondary)]">
|
||||
{plan.description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div class="text-center mb-6">
|
||||
<h3 class="text-xl font-bold text-[var(--color-text-primary)] mb-2">{plan.name}</h3>
|
||||
{plan.description && (
|
||||
<p class="text-sm text-[var(--color-text-secondary)]">{plan.description}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div class="text-center mb-6">
|
||||
<span class="text-4xl font-bold text-[var(--color-text-primary)]">
|
||||
{plan.price}
|
||||
</span>
|
||||
{plan.period && (
|
||||
<span class="text-[var(--color-text-secondary)]">
|
||||
/{plan.period}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div class="text-center mb-6">
|
||||
<span class="text-4xl font-bold text-[var(--color-text-primary)]">{plan.price}</span>
|
||||
{plan.period && (
|
||||
<span class="text-[var(--color-text-secondary)]">/{plan.period}</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<ul class="space-y-3 mb-8 flex-1">
|
||||
{normalizeFeatures(plan.features).map((feature) => (
|
||||
<li class="flex items-start gap-3">
|
||||
<svg
|
||||
class:list={[
|
||||
"w-5 h-5 flex-shrink-0 mt-0.5",
|
||||
feature.included ? "text-green-500" : "text-[var(--color-text-muted)]"
|
||||
]}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
{feature.included ? (
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
) : (
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
)}
|
||||
</svg>
|
||||
<span class:list={[
|
||||
"text-sm",
|
||||
feature.included ? "text-[var(--color-text-primary)]" : "text-[var(--color-text-muted)] line-through"
|
||||
]}>
|
||||
{feature.text}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<ul class="space-y-3 mb-8 flex-1">
|
||||
{normalizeFeatures(plan.features).map((feature) => (
|
||||
<li class="flex items-start gap-3">
|
||||
<svg
|
||||
class:list={[
|
||||
'w-5 h-5 flex-shrink-0 mt-0.5',
|
||||
feature.included ? 'text-green-500' : 'text-[var(--color-text-muted)]',
|
||||
]}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
{feature.included ? (
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
/>
|
||||
) : (
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
)}
|
||||
</svg>
|
||||
<span
|
||||
class:list={[
|
||||
'text-sm',
|
||||
feature.included
|
||||
? 'text-[var(--color-text-primary)]'
|
||||
: 'text-[var(--color-text-muted)] line-through',
|
||||
]}
|
||||
>
|
||||
{feature.text}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<Button
|
||||
href={plan.cta.href}
|
||||
variant={plan.highlighted ? 'primary' : 'secondary'}
|
||||
fullWidth
|
||||
>
|
||||
{plan.cta.text}
|
||||
</Button>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
<Button
|
||||
href={plan.cta.href}
|
||||
variant={plan.highlighted ? 'primary' : 'secondary'}
|
||||
fullWidth
|
||||
>
|
||||
{plan.cta.text}
|
||||
</Button>
|
||||
</Card>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
<slot />
|
||||
</Container>
|
||||
<slot />
|
||||
</Container>
|
||||
</section>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue