Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 60 additions & 58 deletions src/runtime/components/PricingTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -150,80 +150,82 @@ const [DefineFeatureTemplate, ReuseFeatureTemplate] = createReusableTemplate<{ t

<template>
<DefineTierTemplate v-slot="{ tier }">
<slot :name="(tier.id as keyof PricingTableSlots<T>)" :tier="(tier as T)">
<slot name="tier" :tier="(tier as T)">
<div data-slot="tierTitleWrapper" :class="ui.tierTitleWrapper({ class: uiProp?.tierTitleWrapper })">
<div data-slot="tierTitle" :class="ui.tierTitle({ class: uiProp?.tierTitle })">
<slot :name="(`${tier.id}-title` as keyof PricingTableSlots<T>)" :tier="tier">
<slot name="tier-title" :tier="(tier as T)">
{{ tier.title }}
<div data-slot="tierWrapper" :class="ui.tierWrapper({ class: uiProp?.tierWrapper })">
<slot :name="(tier.id as keyof PricingTableSlots<T>)" :tier="(tier as T)">
<slot name="tier" :tier="(tier as T)">
<div data-slot="tierTitleWrapper" :class="ui.tierTitleWrapper({ class: uiProp?.tierTitleWrapper })">
<div data-slot="tierTitle" :class="ui.tierTitle({ class: uiProp?.tierTitle })">
<slot :name="(`${tier.id}-title` as keyof PricingTableSlots<T>)" :tier="tier">
<slot name="tier-title" :tier="(tier as T)">
{{ tier.title }}
</slot>
</slot>
</slot>
</div>

<slot :name="(`${tier.id}-badge` as keyof PricingTableSlots<T>)" :tier="tier">
<slot name="tier-badge" :tier="(tier as T)">
<UBadge
v-if="tier.badge"
color="primary"
variant="subtle"
v-bind="typeof tier.badge === 'string' ? { label: tier.badge } : tier.badge"
data-slot="tierBadge"
:class="ui.tierBadge({ class: uiProp?.tierBadge })"
/>
</slot>
</slot>
</div>

<div v-if="tier.description || !!slots['tier-description'] || !!slots[(`${tier.id}-description` as keyof PricingTableSlots<T>)]" data-slot="tierDescription" :class="ui.tierDescription({ class: uiProp?.tierDescription })">
<slot :name="(`${tier.id}-description` as keyof PricingTableSlots<T>)" :tier="tier">
<slot name="tier-description" :tier="(tier as T)">
{{ tier.description }}
</slot>
</slot>
</div>
</div>

<div v-if="tier.discount || tier.price || !!slots['tier-discount'] || !!slots[(`${tier.id}-discount` as keyof PricingTableSlots<T>)] || !!slots['tier-price'] || !!slots[(`${tier.id}-price` as keyof PricingTableSlots<T>)] || tier.billingCycle || tier.billingPeriod || !!slots['tier-billing'] || !!slots[(`${tier.id}-billing` as keyof PricingTableSlots<T>)]" data-slot="tierPriceWrapper" :class="ui.tierPriceWrapper({ class: uiProp?.tierPriceWrapper })">
<div v-if="(tier.discount && tier.price) || !!slots[(`${tier.id}-discount` as keyof PricingTableSlots<T>)] || !!slots['tier-discount']" data-slot="tierDiscount" :class="ui.tierDiscount({ class: uiProp?.tierDiscount })">
<slot :name="(`${tier.id}-discount` as keyof PricingTableSlots<T>)" :tier="tier">
<slot name="tier-discount" :tier="(tier as T)">
{{ tier.price }}
<slot :name="(`${tier.id}-badge` as keyof PricingTableSlots<T>)" :tier="tier">
<slot name="tier-badge" :tier="(tier as T)">
<UBadge
v-if="tier.badge"
color="primary"
variant="subtle"
v-bind="typeof tier.badge === 'string' ? { label: tier.badge } : tier.badge"
data-slot="tierBadge"
:class="ui.tierBadge({ class: uiProp?.tierBadge })"
/>
</slot>
</slot>
</div>

<div v-if="(tier.discount || tier.price) || !!slots[(`${tier.id}-price` as keyof PricingTableSlots<T>)] || !!slots['tier-price']" data-slot="tierPrice" :class="ui.tierPrice({ class: uiProp?.tierPrice })">
<slot :name="(`${tier.id}-price` as keyof PricingTableSlots<T>)" :tier="tier">
<slot name="tier-price" :tier="(tier as T)">
{{ tier.discount || tier.price }}
<div data-slot="tierDescription" :class="ui.tierDescription({ class: uiProp?.tierDescription })">
<slot :name="(`${tier.id}-description` as keyof PricingTableSlots<T>)" :tier="tier">
<slot name="tier-description" :tier="(tier as T)">
{{ tier.description }}
</slot>
</slot>
</div>

<div v-if="tier.billingCycle || tier.billingPeriod || !!slots[(`${tier.id}-billing` as keyof PricingTableSlots<T>)] || !!slots['tier-billing']" data-slot="tierBilling" :class="ui.tierBilling({ class: uiProp?.tierBilling })">
<slot :name="(`${tier.id}-billing` as keyof PricingTableSlots<T>)" :tier="tier">
<slot name="tier-billing" :tier="(tier as T)">
<span data-slot="tierBillingPeriod" :class="ui.tierBillingPeriod({ class: uiProp?.tierBillingPeriod })">
{{ tier.billingPeriod || '&nbsp;' }}
</span>
<div data-slot="tierPriceWrapper" :class="ui.tierPriceWrapper({ class: uiProp?.tierPriceWrapper })">
<div v-if="(tier.discount && tier.price) || !!slots[(`${tier.id}-discount` as keyof PricingTableSlots<T>)] || !!slots['tier-discount']" data-slot="tierDiscount" :class="ui.tierDiscount({ class: uiProp?.tierDiscount })">
<slot :name="(`${tier.id}-discount` as keyof PricingTableSlots<T>)" :tier="tier">
<slot name="tier-discount" :tier="(tier as T)">
{{ tier.price }}
</slot>
</slot>
</div>

<div v-if="(tier.discount || tier.price) || !!slots[(`${tier.id}-price` as keyof PricingTableSlots<T>)] || !!slots['tier-price']" data-slot="tierPrice" :class="ui.tierPrice({ class: uiProp?.tierPrice })">
<slot :name="(`${tier.id}-price` as keyof PricingTableSlots<T>)" :tier="tier">
<slot name="tier-price" :tier="(tier as T)">
{{ tier.discount || tier.price }}
</slot>
</slot>
</div>

<span v-if="tier.billingCycle" data-slot="tierBillingCycle" :class="ui.tierBillingCycle({ class: uiProp?.tierBillingCycle })">
{{ tier.billingCycle }}
</span>
<div v-if="tier.billingCycle || tier.billingPeriod || !!slots[(`${tier.id}-billing` as keyof PricingTableSlots<T>)] || !!slots['tier-billing']" data-slot="tierBilling" :class="ui.tierBilling({ class: uiProp?.tierBilling })">
<slot :name="(`${tier.id}-billing` as keyof PricingTableSlots<T>)" :tier="tier">
<slot name="tier-billing" :tier="(tier as T)">
<span data-slot="tierBillingPeriod" :class="ui.tierBillingPeriod({ class: uiProp?.tierBillingPeriod })">
{{ tier.billingPeriod || '&nbsp;' }}
</span>

<span v-if="tier.billingCycle" data-slot="tierBillingCycle" :class="ui.tierBillingCycle({ class: uiProp?.tierBillingCycle })">
{{ tier.billingCycle }}
</span>
</slot>
</slot>
</slot>
</div>
</div>
</div>

<div v-if="!!slots[(`${tier.id}-button` as keyof PricingTableSlots<T>)] || !!slots['tier-button'] || tier.button" data-slot="tierButton" :class="ui.tierButton({ class: uiProp?.tierButton })">
<slot :name="(`${tier.id}-button` as keyof PricingTableSlots<T>)" :tier="tier">
<slot name="tier-button" :tier="(tier as T)">
<UButton v-if="tier.button" block size="lg" v-bind="tier.button" />
<div v-if="!!slots[(`${tier.id}-button` as keyof PricingTableSlots<T>)] || !!slots['tier-button'] || tier.button" data-slot="tierButton" :class="ui.tierButton({ class: uiProp?.tierButton })">
<slot :name="(`${tier.id}-button` as keyof PricingTableSlots<T>)" :tier="tier">
<slot name="tier-button" :tier="(tier as T)">
<UButton v-if="tier.button" block size="lg" v-bind="tier.button" />
</slot>
</slot>
</slot>
</div>
</div>
</slot>
</slot>
</slot>
</div>
</DefineTierTemplate>

<DefineFeatureTemplate v-slot="{ feature, tier }">
Expand Down
7 changes: 4 additions & 3 deletions src/theme/pricing-table.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export default {
slots: {
root: 'w-full relative',
table: 'w-full table-fixed border-separate border-spacing-x-0 hidden md:table',
table: 'w-full table-fixed border-separate border-spacing-x-0 hidden md:table h-fit',
list: 'md:hidden flex flex-col gap-6 w-full',
item: 'p-6 flex flex-col border border-default rounded-lg',
caption: 'sr-only',
Expand All @@ -10,7 +10,8 @@ export default {
tr: '',
th: 'py-4 font-normal text-left border-b border-default',
td: 'px-6 py-4 text-center border-b border-default',
tier: 'p-6 text-left font-normal',
tier: 'p-6 text-left font-normal align-top h-full',
tierWrapper: 'flex flex-col md:h-full',
tierTitleWrapper: 'flex items-center gap-3',
tierTitle: 'text-lg font-semibold text-highlighted',
tierDescription: 'text-sm font-normal text-muted mt-1',
Expand All @@ -21,7 +22,7 @@ export default {
tierBilling: 'flex flex-col justify-between min-w-0',
tierBillingPeriod: 'text-toned truncate text-xs font-medium',
tierBillingCycle: 'text-muted truncate text-xs font-medium',
tierButton: 'mt-6',
tierButton: 'mt-6 md:mt-auto md:pt-6',
tierFeatureIcon: 'size-5 shrink-0',
section: 'mt-6 flex flex-col gap-2',
sectionTitle: 'font-semibold text-sm text-highlighted',
Expand Down
Loading
Loading