添加到购物车按钮组件 - Memphis 灰度天气
一个复杂的“添加到购物车”按钮组件,具有 Memphis 设计灵感,使用灰度配色方案,适用于天气/气候产品。功能包括动态图标、加载状态、脉冲动画和项目计数,所有这些都是响应式的,并支持深色模式。此组件旨在为天气数据订阅或气候相关产品提供有趣而实用的行动号召。
HTML 代码
<div class="flex items-center justify-center p-4 min-h-screen bg-neutral-100 dark:bg-neutral-900 font-sans">
<div class="relative w-full max-w-sm rounded-[24px] overflow-hidden shadow-xl
bg-white dark:bg-neutral-800
border-4 border-black dark:border-white
transform skew-y-3 rotate-1 scale-95 transition-all duration-300 ease-in-out
hover:skew-y-0 hover:rotate-0 hover:scale-100">
<!-- Memphis Pattern Background -->
<div class="absolute inset-0 z-0 opacity-20 dark:opacity-10">
<div class="absolute -top-10 -left-10 w-32 h-32 bg-neutral-600 dark:bg-neutral-400 rounded-full"></div>
<div class="absolute -bottom-5 -right-5 w-24 h-24 bg-neutral-700 dark:bg-neutral-300 transform rotate-45"></div>
<div class="absolute top-1/4 right-1/4 w-16 h-16 bg-neutral-500 dark:bg-neutral-500 transform skew-x-12"></div>
<div class="absolute bottom-1/3 left-1/3 w-20 h-20 bg-neutral-400 dark:bg-neutral-600 rounded-lg"></div>
</div>
<div class="relative z-10 p-6 sm:p-8 flex flex-col items-center justify-center space-y-6">
<!-- Product Title/Description (Example: Weather Data Package) -->
<h2 class="text-2xl sm:text-3xl font-bold text-neutral-900 dark:text-neutral-50 text-center uppercase tracking-wide
transform -skew-x-6 bg-neutral-200 dark:bg-neutral-700 p-2 rounded-lg">
Premium Climate Insights
</h2>
<p class="text-md sm:text-lg text-neutral-700 dark:text-neutral-200 text-center max-w-xs leading-relaxed">
Unlock 7-day extended forecasts & historical data.
</p>
<div class="flex items-center space-x-4 mb-4">
<!-- Price Display -->
<span class="text-4xl sm:text-5xl font-extrabold text-neutral-900 dark:text-neutral-50
flex items-center skew-y-2
bg-neutral-300 dark:bg-yellow-500
border-4 border-black dark:border-white
px-4 py-2 rounded-xl shadow-lg relative z-10">
<span class="block transform -rotate-6 relative top-1 text-2xl">$</span>29.99
</span>
<!-- Icon for Weather/Climate -->
<img src="https://raw.githubusercontent.com/twbs/icons/main/icons/cloud-sun-fill.svg" alt="Weather Icon" class="w-16 h-16 sm:w-20 sm:h-20
text-neutral-600 dark:text-neutral-300
filter drop-shadow-lg
transform rotate-12 transition-transform duration-300 hover:rotate-0 dark:invert">
</div>
<!-- Dynamic Add to Cart Button -->
<button type="button" class="group relative overflow-hidden h-16 w-full rounded-full
bg-black dark:bg-white
text-white dark:text-black
text-xl sm:text-2xl font-bold uppercase tracking-wider
flex items-center justify-center
shadow-xl
border-4 border-neutral-700 dark:border-neutral-300
transform skew-x-3 transition-transform duration-300
hover:skew-x-0 hover:scale-105
focus:outline-none focus:ring-4 focus:ring-neutral-400 dark:focus:ring-neutral-600 focus:ring-offset-2 focus:ring-offset-white dark:focus:ring-offset-neutral-800">
<span class="absolute inset-0 bg-neutral-800 dark:bg-neutral-200 transform scale-x-0 group-hover:scale-x-100 origin-left transition-transform duration-500 ease-out z-0"></span>
<!-- Button content -->
<span class="relative z-10 flex items-center space-x-3 transition-transform duration-300 group-hover:-translate-y-full group-[.added]:translate-x-0 group-[.loading]:translate-x-0">
<span>Add to Cart</span>
<svg class="w-7 h-7 fill-current transition-all duration-300 group-hover:rotate-[360deg]" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M17 11H9.83L12.59 8.24L11.17 6.83L7 11L11.17 15.17L12.59 13.76L9.83 11H17V11Z" />
<path d="M17 12H7V10H17V12Z" class="opacity-0 group-hover:opacity-100 transition-opacity duration-300"/>
</svg>
</span>
<!-- Added state -->
<span class="absolute z-10 flex items-center space-x-3 text-white dark:text-black transition-transform duration-300 -translate-y-full group-hover:translate-y-0 group-[.added]:translate-y-0">
<span>Added!</span>
<svg class="w-7 h-7 fill-current animate-bounce" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M9 16.2L4.8 12L3.4 13.4L9 19L21 7L19.6 5.6L9 16.2Z"/>
</svg>
</span>
<!-- Loading state -->
<span class="absolute z-10 flex items-center space-x-3 text-white dark:text-black transition-transform duration-300 -translate-y-full group-hover:translate-y-0 group-[.loading]:translate-y-0">
<svg class="animate-spin h-7 w-7 text-white dark:text-black" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
Loading...
</span>
</button>
<!-- Quantity Selector / Item Count -->
<div class="flex items-center space-x-4 mt-4 text-neutral-800 dark:text-neutral-100">
<span class="text-lg sm:text-xl font-semibold
transform -rotate-3 leading-none opacity-80
bg-neutral-200 dark:bg-neutral-700 px-3 py-1 rounded-full">
Items:
</span>
<div class="flex items-center space-x-2
bg-neutral-300 dark:bg-neutral-600
border-2 border-black dark:border-white
rounded-xl shadow-inner p-1">
<button class="w-10 h-10 flex items-center justify-center rounded-full
bg-black dark:bg-white text-white dark:text-black
text-2xl font-bold
transition-all duration-200
hover:scale-110 focus:outline-none focus:ring-2 focus:ring-black dark:focus:ring-white
transform rotate-6 hover:rotate-0">-</button>
<span class="w-12 h-12 flex items-center justify-center
text-3xl font-extrabold
border-l-2 border-r-2 border-neutral-600 dark:border-neutral-300
text-neutral-900 dark:text-neutral-50">
1
</span>
<button class="w-10 h-10 flex items-center justify-center rounded-full
bg-black dark:bg-white text-white dark:text-black
text-2xl font-bold
transition-all duration-200
hover:scale-110 focus:outline-none focus:ring-2 focus:ring-black dark:focus:ring-white
transform -rotate-6 hover:-rotate-0">+</button>
</div>
</div>
</div>
</div>
</div>
<!-- To demonstrate states, one would typically add JS to toggle 'added' and 'loading' classes on the button -->
<!-- Example: -->
<!-- <script>
const button = document.querySelector('.group.relative');
button.addEventListener('click', () => {
button.classList.add('loading');
setTimeout(() => {
button.classList.remove('loading');
button.classList.add('added');
setTimeout(() => {
button.classList.remove('added');
// Optionally reset button or show another state
}, 2000); // Display 'Added!' for 2 seconds
}, 1500); // Simulate loading for 1.5 seconds
});
</script> -->