gradientflow-saas / components /pricing-card.js
wanderingcloud's picture
Create a modern, attractive SaaS website landing page with the use of smart gradients and slick animations including appealing, modern mouse hover animations.
0bfd444 verified
Raw History Blame Contribute Delete
7.85 kB
class PricingCard extends HTMLElement {
constructor() {
super();
this.isYearly = false;
}
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.render();
this.bindEvents();
}
render() {
const plan = this.getAttribute('plan') || 'Basic';
const price = this.getAttribute('price') || '0';
const popular = this.hasAttribute('popular');
const features = JSON.parse(this.getAttribute('features') || '[]');
const yearly = this.getAttribute('yearly') === 'true';
const monthlyPrice = parseInt(price);
const yearlyPrice = Math.round(monthlyPrice * 12 * 0.8); // 20% discount
const savings = Math.round((1 - 0.8) * 100);
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
}
.pricing-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 24px;
padding: 2rem;
position: relative;
transition: all 0.3s ease;
overflow: hidden;
}
.pricing-card:hover {
transform: translateY(-10px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
}
.pricing-card.popular {
border-color: rgba(147, 51, 234, 0.5);
background: rgba(147, 51, 234, 0.1);
}
.popular-badge {
position: absolute;
top: 1rem;
right: 1rem;
background: linear-gradient(135deg, #9333ea, #ec4899);
color: white;
padding: 0.25rem 0.75rem;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 600;
}
.plan-name {
font-size: 1.5rem;
font-weight: bold;
margin-bottom: 0.5rem;
color: #1f2937;
}
.plan-description {
color: #6b7280;
margin-bottom: 2rem;
}
.price-container {
margin-bottom: 2rem;
}
.price {
font-size: 3rem;
font-weight: bold;
color: #1f2937;
display: inline-block;
}
.price-crossed {
position: relative;
display: inline-block;
color: #9ca3af;
font-size: 1.5rem;
margin-left: 0.5rem;
}
.price-crossed::after {
content: '';
position: absolute;
left: 0;
top: 50%;
width: 100%;
height: 2px;
background: #ef4444;
transform: rotate(-15deg);
animation: strike 0.3s ease-out;
}
.savings-badge {
display: inline-block;
background: #10b981;
color: white;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.75rem;
font-weight: 600;
margin-left: 0.5rem;
}
.period {
color: #6b7280;
}
.features {
list-style: none;
padding: 0;
margin: 0 0 2rem 0;
}
.features li {
display: flex;
align-items: center;
margin-bottom: 1rem;
color: #4b5563;
}
.features li::before {
content: '✓';
color: #10b981;
font-weight: bold;
margin-right: 0.75rem;
font-size: 1.25rem;
}
.btn-choose {
width: 100%;
padding: 0.75rem 1.5rem;
background: linear-gradient(135deg, #9333ea, #ec4899);
color: white;
border: none;
border-radius: 12px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-choose:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(147, 51, 234, 0.3);
}
.dark .pricing-card {
background: rgba(0, 0, 0, 0.3);
border-color: rgba(255, 255, 255, 0.1);
color: #e5e7eb;
}
.dark .plan-name {
color: #f9fafb;
}
.dark .price {
color: #f9fafb;
}
.dark .plan-description,
.dark .period,
.dark .features li {
color: #d1d5db;
}
@keyframes strike {
from { width: 0; }
to { width: 100%; }
}
</style>
<div class="pricing-card ${popular ? 'popular' : ''}">
${popular ? '<span class="popular-badge">Most Popular</span>' : ''}
<h3 class="plan-name">${plan}</h3>
<p class="plan-description">Perfect for ${plan.toLowerCase()} teams</p>
<div class="price-container">
<span class="price">$${yearly ? yearlyPrice : monthlyPrice}</span>
${yearly ? `<span class="price-crossed">$${monthlyPrice * 12}</span>` : ''}
<span class="savings-badge" style="display: ${yearly ? 'inline-block' : 'none'}">Save ${savings}%</span>
<div class="period">per ${yearly ? 'year' : 'month'}</div>
</div>
<ul class="features">
${features.map(feature => `<li>${feature}</li>`).join('')}
</ul>
<button class="btn-choose">Choose Plan</button>
</div>
`;
}
bindEvents() {
this.shadowRoot.querySelector('.btn-choose').addEventListener('click', () => {
// Handle plan selection
const event = new CustomEvent('planselected', {
detail: { plan: this.getAttribute('plan') }
});
window.dispatchEvent(event);
});
}
static get observedAttributes() {
return ['yearly'];
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'yearly') {
this.isYearly = newValue === 'true';
this.render();
}
}
}
customElements.define('custom-pricing-card', PricingCard);