11<template >
2- <div class =" pricing-card" :class =" { featured: featured }" >
3- <div v-if =" badge" class =" card-badge" >
4- <span >{{ badge }}</span >
5- </div >
6-
7- <div class =" card-header" >
8- <h3 class =" card-title" >{{ title }}</h3 >
9- <div class =" card-subtitle" v-if =" subtitle" >{{ subtitle }}</div >
10- <div class =" card-price" >
11- <span class =" price-amount" >{{ price }}</span >
12- <span class =" price-period" v-if =" period" >{{ period }}</span >
2+ <div class =" h-full flex flex-col" >
3+ <div v-if =" !badge" class =" h-12" > </div >
4+ <div
5+ :class =" [
6+ 'relative bg-white rounded-2xl flex flex-col grow overflow-hidden',
7+ featured ? 'border-4 border-teal-500 shadow-lg' : 'border border-gray-200 shadow-md',
8+ badge ? 'pt-12' : ''
9+ ]"
10+ >
11+ <div v-if =" badge" class =" absolute left-0 right-0 top-0" >
12+ <span class =" block w-full text-center bg-teal-500 text-white font-semibold py-3 rounded-t-xl" >{{ badge }}</span >
13+ </div >
14+
15+ <div class =" px-7.5 py-10 flex flex-col gap-y-4 h-83" >
16+ <div >
17+ <h3 class =" text-xl font-bold text-gray-900 mb-1" >{{ title }}</h3 >
18+ <div class =" text-md text-gray-700" v-if =" subtitle" >{{ subtitle }}</div >
19+ </div >
20+
21+ <div class =" grow" >
22+ <div class =" mb-4" >
23+ <span class =" text-3xl font-bold text-gray-900" >{{ price }}</span >
24+ <span class =" text-gray-500 ml-3" v-if =" period" >{{ period }}</span >
25+ </div >
26+ <p class =" text-base text-sm text-gray-600" >{{ description }}</p >
27+ </div >
28+
29+ <div class =" flex justify-center" >
30+ <a :href =" ctaLink" class =" w-full max-w-2xl inline-block text-center rounded-full bg-black text-white font-medium py-2.5" >{{ ctaText }}</a >
31+ </div >
1332 </div >
14- <p class =" card-description" >{{ description }}</p >
15- </div >
1633
17- <ul class =" feature-list" >
18- <li v-for =" (feature, index) in features" :key =" index" class =" feature-item" >
19- <CheckIcon class =" feature-icon" />
20- <span >{{ feature }}</span >
21- </li >
22- </ul >
34+ <hr class =" border-t border-gray-300 mx-7.5" />
2335
24- <div class =" card-footer" >
25- <a :href =" ctaLink" class =" cta-button" :class =" ctaClass" >
26- {{ ctaText }}
27- </a >
36+ <ul class =" p-7.5 space-y-2.5 grow" >
37+ <li v-for =" (feature, index) in features" :key =" index" class =" flex items-center gap-4 text-black-100" >
38+ <CheckIcon class =" w-8 h-8 flex-shrink-0" />
39+ <span class =" text-base" >{{ feature }}</span >
40+ </li >
41+ </ul >
2842 </div >
2943 </div >
3044</template >
3145<script setup lang="ts">
3246
33- import { h , defineComponent } from " vue" ;
47+ import { h , defineComponent , useAttrs } from ' vue'
48+
3449interface Props {
3550 title: string
3651 subtitle? : string
@@ -46,165 +61,20 @@ interface Props {
4661}
4762
4863defineProps <Props >()
64+
4965const CheckIcon = defineComponent ({
50- name: " CheckIcon" ,
66+ name: ' CheckIcon' ,
5167 setup() {
68+ const attrs = useAttrs ()
5269 return () =>
53- h (" svg" , { class: " w-5 h-5 text-green-500" , fill: " currentColor" , viewBox: " 0 0 20 20" }, [
54- h (" path" , {
55- " fill-rule" : " evenodd" ,
56- d: " M16.707 5.293a1 1 0 0 1 0 1.414l-8 8a1 1 0 0 1-1.414 0l-4-4a1 1 0 0 1 1.414-1.414L8 12.586l7.293-7.293a1 1 0 0 1 1.414 0z" ,
57- " clip-rule" : " evenodd" ,
58- }),
59- ]);
70+ h (
71+ ' svg' ,
72+ { ... attrs , fill: ' none' , viewBox: ' 0 0 24 24' , xmlns: ' http://www.w3.org/2000/svg' },
73+ [
74+ h (' circle' , { cx: ' 12' , cy: ' 12' , r: ' 9' , stroke: ' currentColor' , ' stroke-width' : ' 1.8' , fill: ' white' }),
75+ h (' path' , { d: ' M9 12.5l1.8 1.8L15 10' , stroke: ' currentColor' , ' stroke-width' : ' 1.8' , ' stroke-linecap' : ' round' , ' stroke-linejoin' : ' round' , fill: ' none' }),
76+ ]
77+ )
6078 },
61- });
79+ })
6280 </script >
63-
64- <style scoped>
65-
66- .pricing-card {
67- position : relative ;
68- padding : 2rem ;
69- background : var (--vp-c-bg );
70- border : 2px solid var (--vp-c-border );
71- border-radius : 1.5rem ;
72- box-shadow : var (--vp-shadow-2 );
73- transition : all 0.3s ease ;
74- border-left : 4px solid var (--vp-c-border );
75- border-right : 4px solid var (--vp-c-border );
76- display : flex ;
77- flex-direction : column ;
78- justify-content : space-between ;
79- height : 100% ;
80- }
81-
82- .pricing-card.featured {
83- border-color : var (--vp-c-brand-1 );
84- border-left-color : var (--vp-c-brand-1 );
85- border-right-color : var (--vp-c-brand-1 );
86- transform : scale (1.02 );
87- box-shadow : var (--vp-shadow-3 );
88- }
89-
90- .card-badge {
91- position : absolute ;
92- top : -0.75rem ;
93- left : 50% ;
94- transform : translateX (-50% );
95- }
96-
97- .card-badge span {
98- background : var (--vp-c-brand-1 );
99- color : white ;
100- font-size : 0.75rem ;
101- font-weight : 600 ;
102- padding : 0.5rem 1rem ;
103- border-radius : 9999px ;
104- }
105-
106- .pricing-card :not (.featured ) .card-badge span {
107- background : var (--vp-c-bg-alt );
108- color : var (--vp-c-text-2 );
109- }
110-
111- .card-header {
112- text-align : center ;
113- margin-bottom : 2rem ;
114- }
115-
116- .card-title {
117- font-size : 1.5rem ;
118- font-weight : 700 ;
119- color : var (--vp-c-text-1 );
120- margin-bottom : 0.5rem ;
121- }
122-
123- .card-subtitle {
124- font-size : 0.875rem ;
125- color : var (--vp-c-text-2 );
126- margin-bottom : 1.5rem ;
127- }
128-
129- .card-price {
130- margin-bottom : 1.5rem ;
131- }
132-
133- .price-amount {
134- font-size : 3rem ;
135- font-weight : 700 ;
136- color : var (--vp-c-text-1 );
137- line-height : 1 ;
138- }
139-
140- /* Handle longer pricing text like "Pay As You Go" */
141- .price-amount :not ([class *= " $" ]):not ([class *= " Custom" ]) {
142- font-size : 2rem ;
143- }
144-
145- .price-period {
146- color : var (--vp-c-text-2 );
147- margin-left : 0.5rem ;
148- }
149-
150- .card-description {
151- color : var (--vp-c-text-2 );
152- line-height : 1.6 ;
153- }
154-
155- .feature-list {
156- list-style : none ;
157- padding : 0 ;
158- margin : 0 0 2rem 0 ;
159- display : flex ;
160- flex-direction : column ;
161- gap : 1rem ;
162- flex-grow : 1 ;
163- }
164-
165- .feature-item {
166- display : flex ;
167- align-items : center ;
168- gap : 0.75rem ;
169- color : var (--vp-c-text-2 );
170- }
171-
172- .feature-icon {
173- flex-shrink : 0 ;
174- }
175-
176- .card-footer {
177- margin-top : auto ;
178- text-align : center ;
179- }
180-
181- .cta-button {
182- display : inline-flex ;
183- align-items : center ;
184- justify-content : center ;
185- width : 100% ;
186- padding : 0.75rem 1.5rem ;
187- font-weight : 600 ;
188- border-radius : 0.5rem ;
189- text-decoration : none ;
190- transition : all 0.2s ease ;
191- border : 2px solid var (--vp-c-border );
192- color : var (--vp-c-text-1 );
193- }
194-
195- .cta-button :hover {
196- border-color : var (--vp-c-brand-1 );
197- background : var (--vp-c-brand-soft );
198- }
199-
200- .cta-button.primary {
201- background : var (--vp-c-brand-1 );
202- border-color : var (--vp-c-brand-1 );
203- color : white ;
204- }
205-
206- .cta-button.primary :hover {
207- background : var (--vp-c-brand-2 );
208- border-color : var (--vp-c-brand-2 );
209- }
210- </style >
0 commit comments