This commit is contained in:
Your Name committed 2026-06-21 02:09:26 -04:00
1 parent 3cacaacbeb
commit 8b73b8dd2f
52 files changed
+265 -265

No files matched your search

+4 -4
View File
@@ -32,7 +32,7 @@ export default function CartDrawer() {
/> />
{/* Drawer */} {/* Drawer */}
<div className="relative w-full max-w-md h-full bg-white shadow-2xl flex flex-col animate-slide-left"> <div className="relative w-full max-w-md h-full bg-spa-light shadow-2xl flex flex-col animate-slide-left">
{/* Header */} {/* Header */}
<div className="p-6 border-b border-spa-stone/10 flex items-center justify-between bg-spa-light"> <div className="p-6 border-b border-spa-stone/10 flex items-center justify-between bg-spa-light">
<h2 className="text-xl font-bold flex items-center gap-2 text-pop-black"> <h2 className="text-xl font-bold flex items-center gap-2 text-pop-black">
@@ -65,7 +65,7 @@ export default function CartDrawer() {
</div> </div>
) : ( ) : (
items.map((item) => ( items.map((item) => (
<div key={item.cartItemId} className="flex gap-4 p-4 rounded-2xl bg-white border border-spa-stone/10 shadow-sm group relative"> <div key={item.cartItemId} className="flex gap-4 p-4 rounded-2xl bg-spa-light border border-spa-stone/10 shadow-sm group relative">
<div className="w-18 h-22 rounded-lg bg-spa-sage/30 overflow-hidden flex-shrink-0" style={{ width: '72px', height: '88px' }}> <div className="w-18 h-22 rounded-lg bg-spa-sage/30 overflow-hidden flex-shrink-0" style={{ width: '72px', height: '88px' }}>
<img <img
src={item.productImage || '/images/fallback-product.svg'} src={item.productImage || '/images/fallback-product.svg'}
@@ -225,7 +225,7 @@ function CartDrawerFooter({ subtotal, onClose, t }: { subtotal: number; onClose:
value={couponInput} value={couponInput}
onChange={e => setCouponInput(e.target.value.toUpperCase())} onChange={e => setCouponInput(e.target.value.toUpperCase())}
placeholder={t('cart.couponPlaceholder', 'Discount Code')} placeholder={t('cart.couponPlaceholder', 'Discount Code')}
className="flex-1 bg-white border border-spa-stone/20 rounded-lg px-3 py-2 text-sm text-pop-black focus:border-spa-forest outline-none uppercase tracking-widest placeholder:text-spa-stone/50" className="flex-1 bg-spa-light border border-spa-stone/20 rounded-lg px-3 py-2 text-sm text-pop-black focus:border-spa-forest outline-none uppercase tracking-widest placeholder:text-spa-stone/50"
/> />
<button <button
onClick={handleApplyCoupon} onClick={handleApplyCoupon}
@@ -292,7 +292,7 @@ function CartDrawerFooter({ subtotal, onClose, t }: { subtotal: number; onClose:
<Link <Link
to="/checkout" to="/checkout"
onClick={onClose} onClick={onClose}
className="flex items-center justify-center gap-2 w-full py-4 bg-spa-forest text-white font-bold rounded-xl uppercase tracking-widest text-sm hover:bg-spa-stone hover:shadow-lg transition-all duration-300 group" className="flex items-center justify-center gap-2 w-full py-4 bg-spa-forest text-spa-light font-bold rounded-xl uppercase tracking-widest text-sm hover:bg-spa-stone hover:shadow-lg transition-all duration-300 group"
> >
<ShoppingBag className="w-4 h-4" /> <ShoppingBag className="w-4 h-4" />
ดำเนินการชำระเงิน ดำเนินการชำระเงิน
+1 -1
View File
@@ -16,7 +16,7 @@ export default function DynamicBanner({ payload }: DynamicBannerProps) {
const buttonText = getLocalizedField(payload.buttonText, lang); const buttonText = getLocalizedField(payload.buttonText, lang);
return ( return (
<section className="ui-section-band bg-white relative overflow-hidden"> <section className="ui-section-band bg-spa-light relative overflow-hidden">
{linkUrl ? ( {linkUrl ? (
<Link to={linkUrl} className="ui-banner-shell group block cursor-pointer"> <Link to={linkUrl} className="ui-banner-shell group block cursor-pointer">
<div className="absolute inset-0 z-0"> <div className="absolute inset-0 z-0">
@@ -26,7 +26,7 @@ export default function DynamicCategories({ payload, categories, loading }: Dyna
}, [categories, categoryIds]); }, [categories, categoryIds]);
return ( return (
<section id="categories" className="ui-section-band relative overflow-hidden bg-white"> <section id="categories" className="ui-section-band relative overflow-hidden bg-spa-light">
<div className="ui-section-inner space-y-16 relative z-10"> <div className="ui-section-inner space-y-16 relative z-10">
<div className="space-y-4 text-center"> <div className="space-y-4 text-center">
<h2 className="text-4xl font-bold tracking-tight text-pop-black md:text-5xl"> <h2 className="text-4xl font-bold tracking-tight text-pop-black md:text-5xl">
@@ -40,7 +40,7 @@ export default function DynamicCategories({ payload, categories, loading }: Dyna
{loading ? ( {loading ? (
<div className="grid grid-cols-2 gap-6 md:grid-cols-5"> <div className="grid grid-cols-2 gap-6 md:grid-cols-5">
{Array.from({ length: 5 }).map((_, i) => ( {Array.from({ length: 5 }).map((_, i) => (
<div key={i} className="ui-shell-card h-80 animate-pulse bg-gray-50" /> <div key={i} className="ui-shell-card h-80 animate-pulse bg-spa-sage" />
))} ))}
</div> </div>
) : ( ) : (
@@ -58,12 +58,12 @@ export default function DynamicCategories({ payload, categories, loading }: Dyna
alt={getLocalizedField(cat.name, lang)} alt={getLocalizedField(cat.name, lang)}
onError={(e) => { (e.target as HTMLImageElement).style.display = 'none' }} onError={(e) => { (e.target as HTMLImageElement).style.display = 'none' }}
/> />
<div className="absolute bottom-6 left-6 right-6 z-20 text-white"> <div className="absolute bottom-6 left-6 right-6 z-20 text-spa-light">
<span className="mb-1 block text-xl font-semibold"> <span className="mb-1 block text-xl font-semibold">
{getLocalizedField(cat.name, localStorage.getItem('app_lang') || 'en')} {getLocalizedField(cat.name, localStorage.getItem('app_lang') || 'en')}
</span> </span>
{cat._count && ( {cat._count && (
<span className="text-sm font-medium text-white/80"> <span className="text-sm font-medium text-spa-light">
{cat._count.products} Products {cat._count.products} Products
</span> </span>
)} )}
@@ -100,7 +100,7 @@ export default function DynamicEditorialCarousel({ payload }: DynamicEditorialCa
<div className="pt-2"> <div className="pt-2">
<Link <Link
to={slide.buttonLink} to={slide.buttonLink}
className="inline-flex items-center gap-2 text-xs font-bold uppercase tracking-widest text-spa-gold hover:text-white transition-colors group/link" className="inline-flex items-center gap-2 text-xs font-bold uppercase tracking-widest text-spa-gold hover:text-spa-light transition-colors group/link"
> >
{slide.buttonText} {slide.buttonText}
<span className="group-hover/link:translate-x-1 transition-transform">&rarr;</span> <span className="group-hover/link:translate-x-1 transition-transform">&rarr;</span>
@@ -73,7 +73,7 @@ export default function DynamicEditorialTile({ payload }: DynamicEditorialTilePr
<div className="pt-4"> <div className="pt-4">
<Link <Link
to={buttonLink} to={buttonLink}
className="ui-chip border-current px-8 py-3.5 hover:bg-spa-gold hover:border-spa-gold hover:text-white" className="ui-chip border-current px-8 py-3.5 hover:bg-spa-gold hover:border-spa-gold hover:text-spa-light"
> >
{buttonText} {buttonText}
</Link> </Link>
@@ -28,7 +28,7 @@ export default function DynamicHeroArticle({ payload }: DynamicHeroArticleProps)
<div className="ui-hero-overlay" /> <div className="ui-hero-overlay" />
</div> </div>
)} )}
<div className="ui-hero-content text-white"> <div className="ui-hero-content text-spa-light">
{category && ( {category && (
<span className="mb-4 block text-sm font-bold uppercase tracking-widest text-spa-gold"> <span className="mb-4 block text-sm font-bold uppercase tracking-widest text-spa-gold">
{category} {category}
@@ -70,7 +70,7 @@ export default function DynamicNewsletter({ payload }: DynamicNewsletterProps) {
</div> </div>
{status === 'success' ? ( {status === 'success' ? (
<div className="p-6 bg-white/5 border border-spa-gold/30 rounded-2xl animate-pop-in space-y-2"> <div className="p-6 bg-spa-light border border-spa-gold/30 rounded-2xl animate-pop-in space-y-2">
<h4 className="text-spa-gold font-semibold text-lg">{t('newsletter.thankYou')}</h4> <h4 className="text-spa-gold font-semibold text-lg">{t('newsletter.thankYou')}</h4>
<p className="text-xs text-spa-light/75">{t('newsletter.successMessage')}</p> <p className="text-xs text-spa-light/75">{t('newsletter.successMessage')}</p>
</div> </div>
+3 -3
View File
@@ -26,13 +26,13 @@ export default function DynamicProducts({ payload, categories = [] }: DynamicPro
return ( return (
<section className="ui-section-band relative bg-pop-bg"> <section className="ui-section-band relative bg-pop-bg">
<div className="ui-section-inner relative z-10 space-y-12"> <div className="ui-section-inner relative z-10 space-y-12">
<div className="flex items-end justify-between gap-6 border-b border-gray-200 pb-6 md:flex-row"> <div className="flex items-end justify-between gap-6 border-b border-spa-stone/20 pb-6 md:flex-row">
<div> <div>
<h2 className="text-4xl font-bold text-pop-black md:text-5xl"> <h2 className="text-4xl font-bold text-pop-black md:text-5xl">
{title || "Featured Picks"} {title || "Featured Picks"}
</h2> </h2>
{subtitle && ( {subtitle && (
<p className="text-gray-500 mt-2">{subtitle}</p> <p className="text-spa-stone mt-2">{subtitle}</p>
)} )}
</div> </div>
<Link <Link
@@ -45,7 +45,7 @@ export default function DynamicProducts({ payload, categories = [] }: DynamicPro
</div> </div>
{products.length === 0 ? ( {products.length === 0 ? (
<div className="py-12 text-center text-gray-500"> <div className="py-12 text-center text-spa-stone">
No products found in this section No products found in this section
</div> </div>
) : layout === 'carousel' ? ( ) : layout === 'carousel' ? (
@@ -14,7 +14,7 @@ export default function DynamicQuoteCallout({ payload }: DynamicQuoteCalloutProp
const role = getLocalizedField(payload.role, lang); const role = getLocalizedField(payload.role, lang);
return ( return (
<section className="ui-section-band bg-white"> <section className="ui-section-band bg-spa-light">
<div className="ui-section-inner text-center"> <div className="ui-section-inner text-center">
<svg className="w-12 h-12 mx-auto text-spa-gold/40 mb-8" fill="currentColor" viewBox="0 0 24 24"> <svg className="w-12 h-12 mx-auto text-spa-gold/40 mb-8" fill="currentColor" viewBox="0 0 24 24">
<path d="M14.017 21v-7.391c0-5.704 3.731-9.57 8.983-10.609l.995 2.151c-2.432.917-3.995 3.638-3.995 5.849h4v10h-9.983zm-14.017 0v-7.391c0-5.704 3.748-9.57 9-10.609l.996 2.151c-2.433.917-3.996 3.638-3.996 5.849h3.983v10h-9.983z" /> <path d="M14.017 21v-7.391c0-5.704 3.731-9.57 8.983-10.609l.995 2.151c-2.432.917-3.995 3.638-3.995 5.849h4v10h-9.983zm-14.017 0v-7.391c0-5.704 3.748-9.57 9-10.609l.996 2.151c-2.433.917-3.996 3.638-3.996 5.849h3.983v10h-9.983z" />
+2 -2
View File
@@ -20,7 +20,7 @@ export default function DynamicText({ payload }: DynamicTextProps) {
}[textAlign] || 'text-left'; }[textAlign] || 'text-left';
return ( return (
<section className="ui-section-band bg-white relative"> <section className="ui-section-band bg-spa-light relative">
<div className={`ui-section-inner space-y-6 ${alignClass}`}> <div className={`ui-section-inner space-y-6 ${alignClass}`}>
{title && ( {title && (
<h2 className="font-serif text-3xl font-semibold text-spa-forest md:text-4xl"> <h2 className="font-serif text-3xl font-semibold text-spa-forest md:text-4xl">
@@ -28,7 +28,7 @@ export default function DynamicText({ payload }: DynamicTextProps) {
</h2> </h2>
)} )}
<div <div
className="whitespace-pre-wrap text-base font-light leading-relaxed text-gray-600 md:text-lg" className="whitespace-pre-wrap text-base font-light leading-relaxed text-spa-stone md:text-lg"
dangerouslySetInnerHTML={{ __html: content }} dangerouslySetInnerHTML={{ __html: content }}
/> />
</div> </div>
+2 -2
View File
@@ -17,13 +17,13 @@ export default function EmptyState({
actionClick actionClick
}: EmptyStateProps) { }: EmptyStateProps) {
const ButtonContent = () => ( const ButtonContent = () => (
<span className="inline-block mt-6 px-8 py-3 bg-spa-forest text-white rounded-xl text-sm font-bold uppercase tracking-widest hover:bg-spa-stone hover:shadow-lg transition-all cursor-pointer"> <span className="inline-block mt-6 px-8 py-3 bg-spa-forest text-spa-light rounded-xl text-sm font-bold uppercase tracking-widest hover:bg-spa-stone hover:shadow-lg transition-all cursor-pointer">
{actionText} {actionText}
</span> </span>
) )
return ( return (
<div className="flex flex-col items-center justify-center space-y-4 text-center p-12 bg-white border border-spa-stone/10 rounded-2xl shadow-sm max-w-lg mx-auto my-8"> <div className="flex flex-col items-center justify-center space-y-4 text-center p-12 bg-spa-light border border-spa-stone/10 rounded-2xl shadow-sm max-w-lg mx-auto my-8">
<div className="w-16 h-16 bg-spa-sage/30 rounded-full flex items-center justify-center mb-2"> <div className="w-16 h-16 bg-spa-sage/30 rounded-full flex items-center justify-center mb-2">
<PackageOpen className="w-8 h-8 text-spa-forest" /> <PackageOpen className="w-8 h-8 text-spa-forest" />
</div> </div>
+2 -2
View File
@@ -13,7 +13,7 @@ export default function ErrorState({
showHomeButton = true showHomeButton = true
}: ErrorStateProps) { }: ErrorStateProps) {
const content = ( const content = (
<div className="flex flex-col items-center justify-center space-y-4 text-center p-8 bg-white border border-rose-500/20 rounded-2xl shadow-sm max-w-md mx-auto"> <div className="flex flex-col items-center justify-center space-y-4 text-center p-8 bg-spa-light border border-rose-500/20 rounded-2xl shadow-sm max-w-md mx-auto">
<div className="w-12 h-12 bg-rose-500/10 rounded-full flex items-center justify-center"> <div className="w-12 h-12 bg-rose-500/10 rounded-full flex items-center justify-center">
<AlertCircle className="w-6 h-6 text-rose-500" /> <AlertCircle className="w-6 h-6 text-rose-500" />
</div> </div>
@@ -21,7 +21,7 @@ export default function ErrorState({
{showHomeButton && ( {showHomeButton && (
<Link <Link
to="/" to="/"
className="mt-4 px-6 py-2 bg-spa-forest text-white rounded-lg text-sm font-bold uppercase tracking-widest hover:bg-spa-stone transition-colors" className="mt-4 px-6 py-2 bg-spa-forest text-spa-light rounded-lg text-sm font-bold uppercase tracking-widest hover:bg-spa-stone transition-colors"
> >
Return Home Return Home
</Link> </Link>
+22 -22
View File
@@ -71,31 +71,31 @@ export default function Footer({ categories = [] }: FooterProps) {
}, []) }, [])
return ( return (
<footer className="bg-night-900 px-6 py-20 border-t border-white/5"> <footer className="bg-night-900 px-6 py-20 border-t border-spa-light">
<div className="ui-section-inner grid grid-cols-1 gap-12 md:grid-cols-4"> <div className="ui-section-inner grid grid-cols-1 gap-12 md:grid-cols-4">
<div className="space-y-6"> <div className="space-y-6">
<div className="text-2xl font-bold tracking-widest"> <div className="text-2xl font-bold tracking-widest">
{settings?.logoUrl ? <img src={settings.logoUrl} alt={brandName} className="h-8 md:h-10 object-contain" /> : brandName} {settings?.logoUrl ? <img src={settings.logoUrl} alt={brandName} className="h-8 md:h-10 object-contain" /> : brandName}
</div> </div>
<p className="text-sm leading-relaxed text-slate-500"> <p className="text-sm leading-relaxed text-spa-stone">
{settings?.footerDescription || t('footer.catchphrase')} {settings?.footerDescription || t('footer.catchphrase')}
</p> </p>
<div className="flex gap-4"> <div className="flex gap-4">
{settings && (settings.facebookUrl || settings.instagramUrl || settings.tiktokUrl) ? ( {settings && (settings.facebookUrl || settings.instagramUrl || settings.tiktokUrl) ? (
<> <>
{settings.facebookUrl && ( {settings.facebookUrl && (
<a href={settings.facebookUrl} target="_blank" rel="noreferrer" className="ui-chip h-9 w-9 border-white/10 bg-white/5 text-[10px] text-white hover:bg-spa-gold hover:text-night-900">FB</a> <a href={settings.facebookUrl} target="_blank" rel="noreferrer" className="ui-chip h-9 w-9 border-spa-light bg-spa-light text-[10px] text-spa-light hover:bg-spa-gold hover:text-night-900">FB</a>
)} )}
{settings.instagramUrl && ( {settings.instagramUrl && (
<a href={settings.instagramUrl} target="_blank" rel="noreferrer" className="ui-chip h-9 w-9 border-white/10 bg-white/5 text-[10px] text-white hover:bg-spa-gold hover:text-night-900">IG</a> <a href={settings.instagramUrl} target="_blank" rel="noreferrer" className="ui-chip h-9 w-9 border-spa-light bg-spa-light text-[10px] text-spa-light hover:bg-spa-gold hover:text-night-900">IG</a>
)} )}
{settings.tiktokUrl && ( {settings.tiktokUrl && (
<a href={settings.tiktokUrl} target="_blank" rel="noreferrer" className="ui-chip h-9 w-9 border-white/10 bg-white/5 text-[10px] text-white hover:bg-spa-gold hover:text-night-900">TT</a> <a href={settings.tiktokUrl} target="_blank" rel="noreferrer" className="ui-chip h-9 w-9 border-spa-light bg-spa-light text-[10px] text-spa-light hover:bg-spa-gold hover:text-night-900">TT</a>
)} )}
</> </>
) : ( ) : (
['IG', 'FB', 'TW', 'YT'].map((s) => ( ['IG', 'FB', 'TW', 'YT'].map((s) => (
<a key={s} href="#" className="ui-chip h-9 w-9 border-white/10 bg-white/5 text-[10px] text-white hover:bg-spa-gold hover:text-night-900"> <a key={s} href="#" className="ui-chip h-9 w-9 border-spa-light bg-spa-light text-[10px] text-spa-light hover:bg-spa-gold hover:text-night-900">
{s} {s}
</a> </a>
)) ))
@@ -104,30 +104,30 @@ export default function Footer({ categories = [] }: FooterProps) {
</div> </div>
<div className="space-y-4"> <div className="space-y-4">
<h4 className="text-xs font-bold uppercase tracking-widest text-white">{t('footer.explore')}</h4> <h4 className="text-xs font-bold uppercase tracking-widest text-spa-light">{t('footer.explore')}</h4>
<div className="flex flex-col space-y-2 text-sm text-slate-400"> <div className="flex flex-col space-y-2 text-sm text-spa-stone">
{exploreMenu.length > 0 ? ( {exploreMenu.length > 0 ? (
exploreMenu.map(item => ( exploreMenu.map(item => (
<Link key={item.id} to={item.url} className="hover:text-white transition-colors">{translateMenuLabel(item)}</Link> <Link key={item.id} to={item.url} className="hover:text-spa-light transition-colors">{translateMenuLabel(item)}</Link>
)) ))
) : ( ) : (
<> <>
<Link to="/" className="hover:text-white transition-colors">{t('nav.home')}</Link> <Link to="/" className="hover:text-spa-light transition-colors">{t('nav.home')}</Link>
<Link to="/shop" className="hover:text-white transition-colors">{t('nav.shop')}</Link> <Link to="/shop" className="hover:text-spa-light transition-colors">{t('nav.shop')}</Link>
<Link to="/scent-guide" className="hover:text-white transition-colors">{t('nav.scentGuide')}</Link> <Link to="/scent-guide" className="hover:text-spa-light transition-colors">{t('nav.scentGuide')}</Link>
<Link to="/about" className="hover:text-white transition-colors">{t('nav.about')}</Link> <Link to="/about" className="hover:text-spa-light transition-colors">{t('nav.about')}</Link>
<Link to="/contact" className="hover:text-white transition-colors">{t('nav.contact')}</Link> <Link to="/contact" className="hover:text-spa-light transition-colors">{t('nav.contact')}</Link>
<Link to="/faq" className="hover:text-white transition-colors">{t('nav.faq')}</Link> <Link to="/faq" className="hover:text-spa-light transition-colors">{t('nav.faq')}</Link>
</> </>
)} )}
</div> </div>
</div> </div>
<div className="space-y-4"> <div className="space-y-4">
<h4 className="text-xs font-bold uppercase tracking-widest text-white">{t('nav.collections')}</h4> <h4 className="text-xs font-bold uppercase tracking-widest text-spa-light">{t('nav.collections')}</h4>
<div className="flex flex-col space-y-2 text-sm text-slate-400"> <div className="flex flex-col space-y-2 text-sm text-spa-stone">
{categories.map((c) => ( {categories.map((c) => (
<Link key={c.id} to={`/category/${c.id}`} className="hover:text-white transition-colors"> <Link key={c.id} to={`/category/${c.id}`} className="hover:text-spa-light transition-colors">
{getLocalizedField(c.name, localStorage.getItem('app_lang') || 'en')} {getLocalizedField(c.name, localStorage.getItem('app_lang') || 'en')}
</Link> </Link>
))} ))}
@@ -135,17 +135,17 @@ export default function Footer({ categories = [] }: FooterProps) {
</div> </div>
<div className="space-y-4"> <div className="space-y-4">
<h4 className="text-xs font-bold uppercase tracking-widest text-white"> <h4 className="text-xs font-bold uppercase tracking-widest text-spa-light">
{settings?.footerSupportHeading || t('footer.support', 'Support & Legal')} {settings?.footerSupportHeading || t('footer.support', 'Support & Legal')}
</h4> </h4>
<div className="flex flex-col space-y-2 text-sm text-slate-400"> <div className="flex flex-col space-y-2 text-sm text-spa-stone">
{supportMenu.map(item => ( {supportMenu.map(item => (
<Link key={item.id} to={item.url} className="hover:text-white transition-colors">{translateMenuLabel(item)}</Link> <Link key={item.id} to={item.url} className="hover:text-spa-light transition-colors">{translateMenuLabel(item)}</Link>
))} ))}
</div> </div>
<div className="pt-4"> <div className="pt-4">
<p className="text-[10px] text-slate-600 uppercase tracking-widest"> <p className="text-[10px] text-spa-stone uppercase tracking-widest">
{settings?.footerCopyrightText || `© ${new Date().getFullYear()} ${brandName}. ${t('footer.rights')}`} {settings?.footerCopyrightText || `© ${new Date().getFullYear()} ${brandName}. ${t('footer.rights')}`}
</p> </p>
</div> </div>
+6 -6
View File
@@ -168,10 +168,10 @@ export function MobileDrawer({ isOpen, onClose, items, onOpenLang }: MobileDrawe
onClick={onClose} onClick={onClose}
/> />
<div <div
className={`absolute top-0 right-0 h-full w-80 max-w-[85vw] bg-white shadow-2xl flex flex-col transition-transform duration-300 ${isOpen ? 'translate-x-0' : 'translate-x-full'}`} className={`absolute top-0 right-0 h-full w-80 max-w-[85vw] bg-spa-light shadow-2xl flex flex-col transition-transform duration-300 ${isOpen ? 'translate-x-0' : 'translate-x-full'}`}
> >
{/* Static Top Header */} {/* Static Top Header */}
<div className="flex items-center justify-between px-6 py-5 border-b border-spa-stone/10 bg-white z-10 shrink-0"> <div className="flex items-center justify-between px-6 py-5 border-b border-spa-stone/10 bg-spa-light z-10 shrink-0">
<span className="text-sm font-bold uppercase tracking-widest text-spa-forest">Menu</span> <span className="text-sm font-bold uppercase tracking-widest text-spa-forest">Menu</span>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<button onClick={onOpenLang} className="px-2.5 py-1 rounded-md text-[10px] font-bold text-spa-forest border border-spa-forest/30 uppercase bg-spa-sage flex items-center gap-1 shrink-0"> <button onClick={onOpenLang} className="px-2.5 py-1 rounded-md text-[10px] font-bold text-spa-forest border border-spa-forest/30 uppercase bg-spa-sage flex items-center gap-1 shrink-0">
@@ -185,7 +185,7 @@ export function MobileDrawer({ isOpen, onClose, items, onOpenLang }: MobileDrawe
</div> </div>
{/* Sliding Views Container */} {/* Sliding Views Container */}
<div className="flex-1 relative overflow-hidden bg-white"> <div className="flex-1 relative overflow-hidden bg-spa-light">
{stack.map((view, index) => { {stack.map((view, index) => {
const isCurrent = index === stack.length - 1; const isCurrent = index === stack.length - 1;
const isPast = index < stack.length - 1; const isPast = index < stack.length - 1;
@@ -193,7 +193,7 @@ export function MobileDrawer({ isOpen, onClose, items, onOpenLang }: MobileDrawe
return ( return (
<div <div
key={index} key={index}
className={`absolute inset-0 flex flex-col bg-white transition-transform duration-300 ease-in-out ${ className={`absolute inset-0 flex flex-col bg-spa-light transition-transform duration-300 ease-in-out ${
isCurrent ? 'translate-x-0' : isPast ? '-translate-x-full' : 'translate-x-full' isCurrent ? 'translate-x-0' : isPast ? '-translate-x-full' : 'translate-x-full'
}`} }`}
> >
@@ -225,10 +225,10 @@ export function MobileDrawer({ isOpen, onClose, items, onOpenLang }: MobileDrawe
</div> </div>
{/* Static Bottom Footer */} {/* Static Bottom Footer */}
<div className="px-6 pb-8 pt-6 border-t border-spa-stone/10 bg-white z-10 shrink-0 space-y-3"> <div className="px-6 pb-8 pt-6 border-t border-spa-stone/10 bg-spa-light z-10 shrink-0 space-y-3">
<button <button
onClick={() => handleLinkClick('/shop')} onClick={() => handleLinkClick('/shop')}
className="block w-full py-3.5 bg-spa-forest text-white font-bold text-center rounded-xl text-xs uppercase tracking-widest hover:bg-spa-stone transition-colors duration-300 shadow-sm" className="block w-full py-3.5 bg-spa-forest text-spa-light font-bold text-center rounded-xl text-xs uppercase tracking-widest hover:bg-spa-stone transition-colors duration-300 shadow-sm"
> >
Shop Now Shop Now
</button> </button>
+10 -10
View File
@@ -153,7 +153,7 @@ export default function Navbar({ topOffsetClassName = 'top-0' }: NavbarProps) {
ref={navRef} ref={navRef}
className={`fixed ${finalTopClassName} z-50 w-full border-b border-black/5 transition-all duration-300 ${ className={`fixed ${finalTopClassName} z-50 w-full border-b border-black/5 transition-all duration-300 ${
scrolled ? 'shadow-lg shadow-black/5' : 'shadow-none' scrolled ? 'shadow-lg shadow-black/5' : 'shadow-none'
} bg-white/80 px-4 py-3.5 backdrop-blur-xl md:bg-spa-sage md:px-6 md:py-4 md:backdrop-blur-none`} } bg-spa-light px-4 py-3.5 backdrop-blur-xl md:bg-spa-sage md:px-6 md:py-4 md:backdrop-blur-none`}
> >
{/* Single-row layout: Logo (left) | Menu (center, desktop) | Actions (right) */} {/* Single-row layout: Logo (left) | Menu (center, desktop) | Actions (right) */}
<div className="w-full flex items-center justify-between gap-4"> <div className="w-full flex items-center justify-between gap-4">
@@ -193,7 +193,7 @@ export default function Navbar({ topOffsetClassName = 'top-0' }: NavbarProps) {
> >
<Heart className="w-4 h-4 group-hover:text-rose-500 transition-colors" /> <Heart className="w-4 h-4 group-hover:text-rose-500 transition-colors" />
{wishlistCount > 0 && ( {wishlistCount > 0 && (
<span className="absolute -top-1 -right-1 bg-rose-500 text-white text-[9px] font-bold w-4 h-4 rounded-full flex items-center justify-center"> <span className="absolute -top-1 -right-1 bg-rose-500 text-spa-light text-[9px] font-bold w-4 h-4 rounded-full flex items-center justify-center">
{wishlistCount} {wishlistCount}
</span> </span>
)} )}
@@ -206,7 +206,7 @@ export default function Navbar({ topOffsetClassName = 'top-0' }: NavbarProps) {
> >
<ShoppingBag className="w-4 h-4 group-hover:text-spa-forest transition-colors" /> <ShoppingBag className="w-4 h-4 group-hover:text-spa-forest transition-colors" />
{cartCount > 0 && ( {cartCount > 0 && (
<span className="absolute -top-1 -right-1 bg-rose-500 text-white text-[9px] font-bold w-4 h-4 rounded-full flex items-center justify-center"> <span className="absolute -top-1 -right-1 bg-rose-500 text-spa-light text-[9px] font-bold w-4 h-4 rounded-full flex items-center justify-center">
{cartCount} {cartCount}
</span> </span>
)} )}
@@ -215,12 +215,12 @@ export default function Navbar({ topOffsetClassName = 'top-0' }: NavbarProps) {
{isDesktop && ( {isDesktop && (
<> <>
<div className="relative group flex items-center"> <div className="relative group flex items-center">
<button className="px-3 py-2 rounded-full text-[10px] font-bold transition-all text-spa-forest border border-spa-forest/30 hover:bg-spa-sage bg-white flex items-center gap-1.5 uppercase tracking-wider"> <button className="px-3 py-2 rounded-full text-[10px] font-bold transition-all text-spa-forest border border-spa-forest/30 hover:bg-spa-sage bg-spa-light flex items-center gap-1.5 uppercase tracking-wider">
<Globe className="w-3.5 h-3.5" strokeWidth={1.5} /> <Globe className="w-3.5 h-3.5" strokeWidth={1.5} />
{LANGUAGES.find(l => i18n.language.startsWith(l.code))?.short || 'TH'} {LANGUAGES.find(l => i18n.language.startsWith(l.code))?.short || 'TH'}
</button> </button>
<div className="absolute top-full right-0 pt-2 w-36 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto transition-all duration-300"> <div className="absolute top-full right-0 pt-2 w-36 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto transition-all duration-300">
<div className="bg-white/95 backdrop-blur-xl border border-spa-stone/10 rounded-xl overflow-hidden shadow-2xl p-1.5 space-y-0.5"> <div className="bg-spa-light backdrop-blur-xl border border-spa-stone/10 rounded-xl overflow-hidden shadow-2xl p-1.5 space-y-0.5">
{LANGUAGES.map(lang => { {LANGUAGES.map(lang => {
const isActive = i18n.language.startsWith(lang.code) const isActive = i18n.language.startsWith(lang.code)
return ( return (
@@ -248,7 +248,7 @@ export default function Navbar({ topOffsetClassName = 'top-0' }: NavbarProps) {
/> />
</Link> </Link>
<div className="absolute top-full right-0 pt-3 w-36 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto transition-all duration-300"> <div className="absolute top-full right-0 pt-3 w-36 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto transition-all duration-300">
<div className="bg-white/95 backdrop-blur-xl border border-spa-stone/10 rounded-xl overflow-hidden shadow-xl p-1"> <div className="bg-spa-light backdrop-blur-xl border border-spa-stone/10 rounded-xl overflow-hidden shadow-xl p-1">
<div className="px-3 py-2 border-b border-spa-stone/10 mb-1"> <div className="px-3 py-2 border-b border-spa-stone/10 mb-1">
<p className="text-[10px] text-spa-stone/60 uppercase tracking-widest leading-tight truncate">{t('nav.signedInAs', 'Signed in as')}</p> <p className="text-[10px] text-spa-stone/60 uppercase tracking-widest leading-tight truncate">{t('nav.signedInAs', 'Signed in as')}</p>
<p className="text-xs text-spa-forest font-bold truncate">{customer.displayName}</p> <p className="text-xs text-spa-forest font-bold truncate">{customer.displayName}</p>
@@ -271,7 +271,7 @@ export default function Navbar({ topOffsetClassName = 'top-0' }: NavbarProps) {
) : ( ) : (
<button <button
onClick={loginLiff} onClick={loginLiff}
className="ml-2 px-4 py-2 rounded-full text-xs font-bold uppercase tracking-widest bg-[#00B900] text-white hover:bg-[#009900] transition-all duration-300 shadow-sm" className="ml-2 px-4 py-2 rounded-full text-xs font-bold uppercase tracking-widest bg-[#00B900] text-spa-light hover:bg-[#009900] transition-all duration-300 shadow-sm"
> >
{t('nav.login', 'LINE Login')} {t('nav.login', 'LINE Login')}
</button> </button>
@@ -317,7 +317,7 @@ export default function Navbar({ topOffsetClassName = 'top-0' }: NavbarProps) {
</div> </div>
<form onSubmit={handleSearch}> <form onSubmit={handleSearch}>
<div className="flex bg-white border-2 border-spa-stone/20 focus-within:border-spa-forest rounded-2xl overflow-hidden transition-colors shadow-sm"> <div className="flex bg-spa-light border-2 border-spa-stone/20 focus-within:border-spa-forest rounded-2xl overflow-hidden transition-colors shadow-sm">
<svg className="w-5 h-5 text-spa-stone/50 m-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg className="w-5 h-5 text-spa-stone/50 m-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg> </svg>
@@ -329,7 +329,7 @@ export default function Navbar({ topOffsetClassName = 'top-0' }: NavbarProps) {
className="bg-transparent border-none outline-none text-lg md:text-xl p-4 pl-0 w-full text-spa-forest placeholder-spa-stone/40" className="bg-transparent border-none outline-none text-lg md:text-xl p-4 pl-0 w-full text-spa-forest placeholder-spa-stone/40"
autoFocus autoFocus
/> />
<button type="submit" className="bg-spa-forest text-white px-4 md:px-6 font-bold text-xs uppercase tracking-widest shrink-0 hover:bg-spa-stone transition-colors"> <button type="submit" className="bg-spa-forest text-spa-light px-4 md:px-6 font-bold text-xs uppercase tracking-widest shrink-0 hover:bg-spa-stone transition-colors">
Go Go
</button> </button>
</div> </div>
@@ -346,7 +346,7 @@ export default function Navbar({ topOffsetClassName = 'top-0' }: NavbarProps) {
onClick={() => setLangSheetOpen(false)} onClick={() => setLangSheetOpen(false)}
/> />
<div <div
className={`absolute bottom-0 left-0 right-0 bg-white rounded-t-3xl transition-transform duration-300 shadow-2xl pb-safe ${langSheetOpen ? 'translate-y-0' : 'translate-y-full'}`} className={`absolute bottom-0 left-0 right-0 bg-spa-light rounded-t-3xl transition-transform duration-300 shadow-2xl pb-safe ${langSheetOpen ? 'translate-y-0' : 'translate-y-full'}`}
> >
<div className="flex justify-center pt-3 pb-1"> <div className="flex justify-center pt-3 pb-1">
<div className="w-12 h-1.5 bg-spa-stone/20 rounded-full" /> <div className="w-12 h-1.5 bg-spa-stone/20 rounded-full" />
+4 -4
View File
@@ -57,13 +57,13 @@ export default function ProductCard({ product, enableQuickShop = false, category
(e.target as HTMLImageElement).style.display = 'none'; (e.target as HTMLImageElement).style.display = 'none';
}} }}
/> />
<div className="ui-chip absolute left-3 top-3 border-white/20 bg-white/90 px-2.5 py-1 text-[10px] text-spa-forest shadow-sm backdrop-blur-sm"> <div className="ui-chip absolute left-3 top-3 border-spa-light bg-spa-light px-2.5 py-1 text-[10px] text-spa-forest shadow-sm backdrop-blur-sm">
{displayCategoryName} {displayCategoryName}
</div> </div>
<button <button
type="button" type="button"
onClick={handleWishlistClick} onClick={handleWishlistClick}
className="absolute right-3 top-3 z-10 rounded-full bg-white/90 p-2 shadow-sm backdrop-blur-sm transition-transform hover:scale-110 cursor-pointer" className="absolute right-3 top-3 z-10 rounded-full bg-spa-light p-2 shadow-sm backdrop-blur-sm transition-transform hover:scale-110 cursor-pointer"
> >
<Heart <Heart
className={`w-4 h-4 transition-colors ${isWished ? 'fill-rose-500 text-rose-500' : 'text-spa-stone/60 hover:text-rose-500'}`} className={`w-4 h-4 transition-colors ${isWished ? 'fill-rose-500 text-rose-500' : 'text-spa-stone/60 hover:text-rose-500'}`}
@@ -96,8 +96,8 @@ export default function ProductCard({ product, enableQuickShop = false, category
}} }}
className={`rounded-full border px-3 py-1 text-[10px] font-bold uppercase tracking-wider transition-all cursor-pointer ${ className={`rounded-full border px-3 py-1 text-[10px] font-bold uppercase tracking-wider transition-all cursor-pointer ${
isSelected isSelected
? 'border-spa-forest bg-spa-forest text-white shadow-sm' ? 'border-spa-forest bg-spa-forest text-spa-light shadow-sm'
: 'border-spa-stone/10 bg-white text-spa-stone hover:border-spa-forest/30' : 'border-spa-stone/10 bg-spa-light text-spa-stone hover:border-spa-forest/30'
}`} }`}
> >
{variant.size} {variant.size}
@@ -28,7 +28,7 @@ export default function ProductImageGallery({ images, fallback, alt = 'Product I
return ( return (
<div className="space-y-4"> <div className="space-y-4">
{/* Main Image */} {/* Main Image */}
<div className="relative rounded-2xl overflow-hidden h-[480px] group bg-white shadow-sm border border-spa-stone/10 flex items-center justify-center"> <div className="relative rounded-2xl overflow-hidden h-[480px] group bg-spa-light shadow-sm border border-spa-stone/10 flex items-center justify-center">
<img <img
src={currentImageUrl} src={currentImageUrl}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-700" className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-700"
@@ -38,7 +38,7 @@ export default function ProductImageGallery({ images, fallback, alt = 'Product I
<div className="absolute inset-0 bg-gradient-to-t from-black/10 to-transparent pointer-events-none" /> <div className="absolute inset-0 bg-gradient-to-t from-black/10 to-transparent pointer-events-none" />
{badgeText && ( {badgeText && (
<div className="absolute top-6 left-6 bg-white/90 backdrop-blur-sm px-3 py-1.5 rounded-full text-[10px] font-bold uppercase tracking-widest text-spa-forest shadow-sm pointer-events-none"> <div className="absolute top-6 left-6 bg-spa-light backdrop-blur-sm px-3 py-1.5 rounded-full text-[10px] font-bold uppercase tracking-widest text-spa-forest shadow-sm pointer-events-none">
{badgeText} {badgeText}
</div> </div>
)} )}
@@ -48,7 +48,7 @@ export default function ProductImageGallery({ images, fallback, alt = 'Product I
<> <>
<button <button
onClick={handlePrev} onClick={handlePrev}
className="absolute left-4 top-1/2 -translate-y-1/2 w-10 h-10 bg-white/80 backdrop-blur-md rounded-full flex items-center justify-center text-spa-forest opacity-0 group-hover:opacity-100 transition-opacity hover:bg-white hover:scale-110 shadow-sm" className="absolute left-4 top-1/2 -translate-y-1/2 w-10 h-10 bg-spa-light backdrop-blur-md rounded-full flex items-center justify-center text-spa-forest opacity-0 group-hover:opacity-100 transition-opacity hover:bg-spa-light hover:scale-110 shadow-sm"
aria-label="Previous image" aria-label="Previous image"
> >
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
@@ -57,7 +57,7 @@ export default function ProductImageGallery({ images, fallback, alt = 'Product I
</button> </button>
<button <button
onClick={handleNext} onClick={handleNext}
className="absolute right-4 top-1/2 -translate-y-1/2 w-10 h-10 bg-white/80 backdrop-blur-md rounded-full flex items-center justify-center text-spa-forest opacity-0 group-hover:opacity-100 transition-opacity hover:bg-white hover:scale-110 shadow-sm" className="absolute right-4 top-1/2 -translate-y-1/2 w-10 h-10 bg-spa-light backdrop-blur-md rounded-full flex items-center justify-center text-spa-forest opacity-0 group-hover:opacity-100 transition-opacity hover:bg-spa-light hover:scale-110 shadow-sm"
aria-label="Next image" aria-label="Next image"
> >
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+9 -9
View File
@@ -96,7 +96,7 @@ export default function ProductReviews({ productId }: { productId: number }) {
{/* List & Form */} {/* List & Form */}
<div className="w-full md:w-2/3 space-y-8"> <div className="w-full md:w-2/3 space-y-8">
{customer ? ( {customer ? (
<form onSubmit={handleSubmit} className="bg-white p-6 rounded-3xl border border-spa-stone/10 shadow-sm space-y-4"> <form onSubmit={handleSubmit} className="bg-spa-light p-6 rounded-3xl border border-spa-stone/10 shadow-sm space-y-4">
<h3 className="font-bold text-pop-black">Write a Review</h3> <h3 className="font-bold text-pop-black">Write a Review</h3>
<div className="flex gap-2"> <div className="flex gap-2">
{[1, 2, 3, 4, 5].map(star => ( {[1, 2, 3, 4, 5].map(star => (
@@ -115,7 +115,7 @@ export default function ProductReviews({ productId }: { productId: number }) {
<button <button
type="submit" type="submit"
disabled={submitting} disabled={submitting}
className="px-6 py-2.5 bg-spa-forest text-white text-sm font-bold tracking-widest uppercase rounded-full hover:bg-spa-stone transition-all disabled:opacity-50" className="px-6 py-2.5 bg-spa-forest text-spa-light text-sm font-bold tracking-widest uppercase rounded-full hover:bg-spa-stone transition-all disabled:opacity-50"
> >
{submitting ? 'Submitting...' : 'Submit Review'} {submitting ? 'Submitting...' : 'Submit Review'}
</button> </button>
@@ -135,8 +135,8 @@ export default function ProductReviews({ productId }: { productId: number }) {
onClick={() => { setFilterRating(null); setVisibleCount(3); }} onClick={() => { setFilterRating(null); setVisibleCount(3); }}
className={`flex-shrink-0 px-4 py-1.5 rounded-full text-xs font-bold transition-all border ${ className={`flex-shrink-0 px-4 py-1.5 rounded-full text-xs font-bold transition-all border ${
filterRating === null filterRating === null
? 'bg-spa-stone text-white border-spa-stone' ? 'bg-spa-stone text-spa-light border-spa-stone'
: 'bg-white text-spa-stone border-spa-stone/20 hover:border-spa-stone/50' : 'bg-spa-light text-spa-stone border-spa-stone/20 hover:border-spa-stone/50'
}`} }`}
> >
All ({reviews.length}) All ({reviews.length})
@@ -150,11 +150,11 @@ export default function ProductReviews({ productId }: { productId: number }) {
onClick={() => { setFilterRating(star); setVisibleCount(3); }} onClick={() => { setFilterRating(star); setVisibleCount(3); }}
className={`flex-shrink-0 flex items-center gap-1 px-4 py-1.5 rounded-full text-xs font-bold transition-all border ${ className={`flex-shrink-0 flex items-center gap-1 px-4 py-1.5 rounded-full text-xs font-bold transition-all border ${
filterRating === star filterRating === star
? 'bg-spa-stone text-white border-spa-stone' ? 'bg-spa-stone text-spa-light border-spa-stone'
: 'bg-white text-spa-stone border-spa-stone/20 hover:border-spa-stone/50' : 'bg-spa-light text-spa-stone border-spa-stone/20 hover:border-spa-stone/50'
}`} }`}
> >
{star} <Star className={`w-3 h-3 ${filterRating === star ? 'fill-white text-white' : 'fill-orange-400 text-orange-400'}`} /> ({count}) {star} <Star className={`w-3 h-3 ${filterRating === star ? 'fill-white text-spa-light' : 'fill-orange-400 text-orange-400'}`} /> ({count})
</button> </button>
); );
})} })}
@@ -174,7 +174,7 @@ export default function ProductReviews({ productId }: { productId: number }) {
{review.customer?.pictureUrl ? ( {review.customer?.pictureUrl ? (
<img src={review.customer.pictureUrl} className="w-10 h-10 rounded-full object-cover" /> <img src={review.customer.pictureUrl} className="w-10 h-10 rounded-full object-cover" />
) : ( ) : (
<div className="w-10 h-10 rounded-full bg-spa-stone/20 flex items-center justify-center text-white font-bold"> <div className="w-10 h-10 rounded-full bg-spa-stone/20 flex items-center justify-center text-spa-light font-bold">
{(review.customerName || 'A')[0].toUpperCase()} {(review.customerName || 'A')[0].toUpperCase()}
</div> </div>
)} )}
@@ -197,7 +197,7 @@ export default function ProductReviews({ productId }: { productId: number }) {
<div className="text-center pt-4"> <div className="text-center pt-4">
<button <button
onClick={() => setVisibleCount(prev => prev + 5)} onClick={() => setVisibleCount(prev => prev + 5)}
className="px-6 py-2.5 border border-spa-stone/20 text-spa-stone text-xs font-bold tracking-widest uppercase rounded-full hover:border-spa-stone hover:text-pop-black transition-all bg-white" className="px-6 py-2.5 border border-spa-stone/20 text-spa-stone text-xs font-bold tracking-widest uppercase rounded-full hover:border-spa-stone hover:text-pop-black transition-all bg-spa-light"
> >
Show More Reviews Show More Reviews
</button> </button>
@@ -129,7 +129,7 @@ export default function ContactFormSection({ payload }: ContactFormSectionProps)
</p> </p>
</div> </div>
<div className="bg-white rounded-3xl shadow-xl shadow-spa-sand/50 p-8 md:p-12 border border-spa-sage/10"> <div className="bg-spa-light rounded-3xl shadow-xl shadow-spa-sand/50 p-8 md:p-12 border border-spa-sage/10">
{isSuccess ? ( {isSuccess ? (
<div className="text-center py-12"> <div className="text-center py-12">
<div className="w-16 h-16 bg-green-100 text-green-600 rounded-full flex items-center justify-center mx-auto mb-6"> <div className="w-16 h-16 bg-green-100 text-green-600 rounded-full flex items-center justify-center mx-auto mb-6">
@@ -192,10 +192,10 @@ export default function ContactFormSection({ payload }: ContactFormSectionProps)
<button <button
type="submit" type="submit"
disabled={isSubmitting} disabled={isSubmitting}
className="w-full py-4 px-6 bg-spa-sage hover:bg-spa-sage-dark text-white rounded-xl font-medium flex items-center justify-center gap-2 transition-colors disabled:opacity-70 disabled:cursor-not-allowed" className="w-full py-4 px-6 bg-spa-sage hover:bg-spa-sage-dark text-spa-light rounded-xl font-medium flex items-center justify-center gap-2 transition-colors disabled:opacity-70 disabled:cursor-not-allowed"
> >
{isSubmitting ? ( {isSubmitting ? (
<span className="w-6 h-6 border-2 border-white/30 border-t-white rounded-full animate-spin" /> <span className="w-6 h-6 border-2 border-spa-light border-t-white rounded-full animate-spin" />
) : ( ) : (
<> <>
<Send size={18} /> <Send size={18} />
@@ -30,7 +30,7 @@ export default function ContactInfoSection({ payload }: ContactInfoSectionProps)
] as const; ] as const;
return ( return (
<section className="ui-section-band w-full bg-white px-4 md:px-8"> <section className="ui-section-band w-full bg-spa-light px-4 md:px-8">
<div className="ui-section-inner"> <div className="ui-section-inner">
{title && ( {title && (
<div className="mb-10 text-center"> <div className="mb-10 text-center">
@@ -78,7 +78,7 @@ export function ThaiAddressInput({ value, onChange }: ThaiAddressInputProps) {
if (focusedField !== field || results.length === 0) return null; if (focusedField !== field || results.length === 0) return null;
return ( return (
<ul className="absolute z-50 w-full bg-white border border-spa-stone/20 rounded-lg mt-1 max-h-60 overflow-y-auto shadow-xl"> <ul className="absolute z-50 w-full bg-spa-light border border-spa-stone/20 rounded-lg mt-1 max-h-60 overflow-y-auto shadow-xl">
{results.map((item, idx) => ( {results.map((item, idx) => (
<li <li
key={`${item.district}-${item.amphoe}-${item.province}-${item.zipcode}-${idx}`} key={`${item.district}-${item.amphoe}-${item.province}-${item.zipcode}-${idx}`}
+18 -18
View File
@@ -99,11 +99,11 @@
} }
.ui-section-subtitle { .ui-section-subtitle {
@apply mx-auto max-w-2xl text-gray-500; @apply mx-auto max-w-2xl text-spa-stone;
} }
.ui-shell-card { .ui-shell-card {
@apply rounded-3xl border border-spa-stone/10 bg-white shadow-brutal transition-all duration-300; @apply rounded-3xl border border-spa-stone/10 bg-spa-light shadow-brutal transition-all duration-300;
} }
.ui-shell-card-hover { .ui-shell-card-hover {
@@ -115,15 +115,15 @@
} }
.ui-button-primary { .ui-button-primary {
@apply inline-flex items-center justify-center rounded-full bg-spa-forest px-6 py-3 text-xs font-bold uppercase tracking-widest text-white transition-colors hover:bg-spa-forest/90; @apply inline-flex items-center justify-center rounded-full bg-spa-forest px-6 py-3 text-xs font-bold uppercase tracking-widest text-spa-light transition-colors hover:bg-spa-forest/90;
} }
.ui-button-secondary { .ui-button-secondary {
@apply inline-flex items-center justify-center rounded-full bg-white px-6 py-3 text-xs font-bold uppercase tracking-widest text-spa-forest transition-colors hover:bg-spa-sage; @apply inline-flex items-center justify-center rounded-full bg-spa-light px-6 py-3 text-xs font-bold uppercase tracking-widest text-spa-forest transition-colors hover:bg-spa-sage;
} }
.ui-input-shell { .ui-input-shell {
@apply w-full rounded-full border border-white/10 bg-white/5 px-6 py-4 text-sm text-white outline-none transition placeholder:text-white/40 focus:border-spa-gold/80; @apply w-full rounded-full border border-spa-light bg-spa-light px-6 py-4 text-sm text-spa-light outline-none transition placeholder:text-spa-light focus:border-spa-gold/80;
} }
.ui-muted-text { .ui-muted-text {
@@ -131,7 +131,7 @@
} }
.ui-hero-shell { .ui-hero-shell {
@apply relative flex min-h-[90vh] items-center justify-center overflow-hidden bg-night-900 text-white md:aspect-[21/9] md:min-h-0; @apply relative flex min-h-[90vh] items-center justify-center overflow-hidden bg-night-900 text-spa-light md:aspect-[21/9] md:min-h-0;
} }
.ui-hero-overlay { .ui-hero-overlay {
@@ -147,11 +147,11 @@
} }
.ui-hero-title { .ui-hero-title {
@apply font-serif text-5xl font-light leading-tight tracking-wide text-white drop-shadow-md md:text-7xl lg:text-8xl; @apply font-serif text-5xl font-light leading-tight tracking-wide text-spa-light drop-shadow-md md:text-7xl lg:text-8xl;
} }
.ui-hero-copy { .ui-hero-copy {
@apply mx-auto max-w-2xl pb-8 pt-4 text-lg font-light text-white/90 drop-shadow-md md:text-xl; @apply mx-auto max-w-2xl pb-8 pt-4 text-lg font-light text-spa-light drop-shadow-md md:text-xl;
} }
.ui-banner-shell { .ui-banner-shell {
@@ -163,19 +163,19 @@
} }
.ui-banner-content { .ui-banner-content {
@apply relative z-10 max-w-xl space-y-4 p-8 text-white md:p-16; @apply relative z-10 max-w-xl space-y-4 p-8 text-spa-light md:p-16;
} }
.ui-card-soft { .ui-card-soft {
@apply rounded-2xl border border-spa-stone/10 bg-white shadow-sm; @apply rounded-2xl border border-spa-stone/10 bg-spa-light shadow-sm;
} }
.ui-dark-shell { .ui-dark-shell {
@apply bg-spa-forest px-6 py-20 text-white; @apply bg-spa-forest px-6 py-20 text-spa-light;
} }
.ui-dark-card { .ui-dark-card {
@apply overflow-hidden rounded-3xl border border-white/5 bg-white/5; @apply overflow-hidden rounded-3xl border border-spa-light bg-spa-light;
} }
.ui-dark-card-title { .ui-dark-card-title {
@@ -187,11 +187,11 @@
} }
.ui-dark-link { .ui-dark-link {
@apply inline-flex items-center gap-2 text-xs font-bold uppercase tracking-widest text-spa-gold transition-colors hover:text-white; @apply inline-flex items-center gap-2 text-xs font-bold uppercase tracking-widest text-spa-gold transition-colors hover:text-spa-light;
} }
.brutal-box { .brutal-box {
@apply bg-white border border-gray-100 rounded-2xl shadow-brutal transition-all duration-300; @apply bg-spa-light border border-spa-stone/20 rounded-2xl shadow-brutal transition-all duration-300;
} }
.brutal-box-hover { .brutal-box-hover {
@@ -199,11 +199,11 @@
} }
.brutal-button { .brutal-button {
@apply px-8 py-4 bg-pop-pink text-white font-medium rounded-full shadow-brutal transition-all duration-300 hover:bg-pop-red hover:-translate-y-1 hover:shadow-brutal-hover; @apply px-8 py-4 bg-pop-pink text-spa-light font-medium rounded-full shadow-brutal transition-all duration-300 hover:bg-pop-red hover:-translate-y-1 hover:shadow-brutal-hover;
} }
.brutal-button-alt { .brutal-button-alt {
@apply px-8 py-4 bg-white text-pop-pink font-medium rounded-full border border-pop-pink shadow-brutal transition-all duration-300 hover:bg-pop-bg hover:-translate-y-1 hover:shadow-brutal-hover; @apply px-8 py-4 bg-spa-light text-pop-pink font-medium rounded-full border border-pop-pink shadow-brutal transition-all duration-300 hover:bg-pop-bg hover:-translate-y-1 hover:shadow-brutal-hover;
} }
} }
@@ -217,11 +217,11 @@
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
@apply bg-gray-300 rounded-full; @apply bg-spa-sage rounded-full;
} }
::-webkit-scrollbar-thumb:hover { ::-webkit-scrollbar-thumb:hover {
@apply bg-gray-400; @apply bg-spa-sage;
} }
/* Smooth Scrolling */ /* Smooth Scrolling */
+4 -4
View File
@@ -49,13 +49,13 @@ export default function ArticleReaderPage() {
<main className="flex-1 pt-24 pb-20"> <main className="flex-1 pt-24 pb-20">
<article className="max-w-4xl mx-auto w-full animate-fade-in relative mt-8"> <article className="max-w-4xl mx-auto w-full animate-fade-in relative mt-8">
<Link to="/scent-guide" className="absolute -left-16 xl:-left-24 top-0 mt-8 hidden lg:flex p-4 bg-white shadow-sm border border-spa-stone/10 border border-spa-stone/10 rounded-full hover:bg-white/10 transition-colors"> <Link to="/scent-guide" className="absolute -left-16 xl:-left-24 top-0 mt-8 hidden lg:flex p-4 bg-spa-light shadow-sm border border-spa-stone/10 border border-spa-stone/10 rounded-full hover:bg-spa-light transition-colors">
<ArrowLeft className="w-5 h-5 text-slate-300" /> <ArrowLeft className="w-5 h-5 text-spa-stone" />
</Link> </Link>
{/* Header */} {/* Header */}
<div className="text-center px-6 py-12 space-y-6"> <div className="text-center px-6 py-12 space-y-6">
<Link to="/scent-guide" className="lg:hidden text-slate-400 text-sm hover:text-white inline-flex items-center gap-2 mb-4"> <Link to="/scent-guide" className="lg:hidden text-spa-stone text-sm hover:text-spa-light inline-flex items-center gap-2 mb-4">
<ArrowLeft className="w-4 h-4" /> Go Back <ArrowLeft className="w-4 h-4" /> Go Back
</Link> </Link>
<p className="text-spa-forest uppercase tracking-[0.3em] font-bold text-xs"> <p className="text-spa-forest uppercase tracking-[0.3em] font-bold text-xs">
@@ -68,7 +68,7 @@ export default function ArticleReaderPage() {
{/* Cover Image */} {/* Cover Image */}
{article.coverImage && ( {article.coverImage && (
<div className="w-full aspect-[16/7] bg-white md:rounded-[2rem] overflow-hidden shadow-2xl mb-16 border border-spa-stone/10"> <div className="w-full aspect-[16/7] bg-spa-light md:rounded-[2rem] overflow-hidden shadow-2xl mb-16 border border-spa-stone/10">
<img src={article.coverImage} alt={article.title} className="w-full h-full object-cover" /> <img src={article.coverImage} alt={article.title} className="w-full h-full object-cover" />
</div> </div>
)} )}
+7 -7
View File
@@ -132,15 +132,15 @@ export default function CategoryPage() {
<div className="max-w-7xl mx-auto"> <div className="max-w-7xl mx-auto">
{/* Breadcrumb */} {/* Breadcrumb */}
<div className="flex items-center gap-2 text-xs text-spa-sage/80 uppercase tracking-widest mb-4 font-semibold"> <div className="flex items-center gap-2 text-xs text-spa-sage/80 uppercase tracking-widest mb-4 font-semibold">
<Link to="/" className="hover:text-white transition-colors">Home</Link> <Link to="/" className="hover:text-spa-light transition-colors">Home</Link>
<span>/</span> <span>/</span>
<Link to="/shop" className="hover:text-white transition-colors">Shop</Link> <Link to="/shop" className="hover:text-spa-light transition-colors">Shop</Link>
<span>/</span> <span>/</span>
<span className="text-white">{typeof category?.name === 'string' ? category.name : (category?.name as any)?.[localStorage.getItem('app_lang') || 'en'] || (category?.name as any)?.en || '...'}</span> <span className="text-spa-light">{typeof category?.name === 'string' ? category.name : (category?.name as any)?.[localStorage.getItem('app_lang') || 'en'] || (category?.name as any)?.en || '...'}</span>
</div> </div>
<h1 className="text-4xl md:text-5xl font-bold text-white"> <h1 className="text-4xl md:text-5xl font-bold text-spa-light">
{loading ? ( {loading ? (
<div className="h-10 w-48 bg-white/20 animate-pulse rounded-lg" /> <div className="h-10 w-48 bg-spa-light animate-pulse rounded-lg" />
) : ( ) : (
typeof category?.name === 'string' ? category.name : (category?.name as any)?.[i18n.language] || (category?.name as any)?.en || '' typeof category?.name === 'string' ? category.name : (category?.name as any)?.[i18n.language] || (category?.name as any)?.en || ''
)} )}
@@ -165,8 +165,8 @@ export default function CategoryPage() {
to={`/category/${cat.id}`} to={`/category/${cat.id}`}
className={`px-4 py-1.5 rounded-full text-xs font-bold uppercase tracking-widest transition-all duration-300 border ${ className={`px-4 py-1.5 rounded-full text-xs font-bold uppercase tracking-widest transition-all duration-300 border ${
cat.id === category?.id cat.id === category?.id
? 'bg-spa-forest text-white border-spa-forest shadow-md' ? 'bg-spa-forest text-spa-light border-spa-forest shadow-md'
: 'bg-white text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm' : 'bg-spa-light text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm'
}`} }`}
> >
{typeof cat.name === 'string' ? cat.name : (cat.name as any)?.[localStorage.getItem('app_lang') || 'en'] || (cat.name as any)?.en || ''} {typeof cat.name === 'string' ? cat.name : (cat.name as any)?.[localStorage.getItem('app_lang') || 'en'] || (cat.name as any)?.en || ''}
+6 -6
View File
@@ -338,7 +338,7 @@ export default function CheckoutPage() {
{/* Form Section */} {/* Form Section */}
<div className="flex-1 space-y-8 order-2 lg:order-1"> <div className="flex-1 space-y-8 order-2 lg:order-1">
<form id="checkout-form" onSubmit={handleSubmit} className="space-y-6"> <form id="checkout-form" onSubmit={handleSubmit} className="space-y-6">
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 space-y-6 shadow-sm"> <div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 space-y-6 shadow-sm">
<h2 className="text-xl font-bold uppercase tracking-widest text-spa-forest border-b border-spa-stone/10 pb-4">{t('checkout.shippingInfo')}</h2> <h2 className="text-xl font-bold uppercase tracking-widest text-spa-forest border-b border-spa-stone/10 pb-4">{t('checkout.shippingInfo')}</h2>
<div className="grid md:grid-cols-2 gap-6"> <div className="grid md:grid-cols-2 gap-6">
@@ -433,20 +433,20 @@ export default function CheckoutPage() {
<button <button
type="submit" type="submit"
disabled={loading || loadingSettings} disabled={loading || loadingSettings}
className="w-full py-4 px-6 bg-spa-forest text-white font-bold rounded-xl tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed flex lg:hidden justify-between items-center mt-4" className="w-full py-4 px-6 bg-spa-forest text-spa-light font-bold rounded-xl tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed flex lg:hidden justify-between items-center mt-4"
> >
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{loading && <Loader2 className="w-5 h-5 animate-spin" />} {loading && <Loader2 className="w-5 h-5 animate-spin" />}
<span>Proceed to Payment</span> <span>Proceed to Payment</span>
</div> </div>
<span className="text-sm border-l border-white/20 pl-4">{formatPrice(total)}</span> <span className="text-sm border-l border-spa-light pl-4">{formatPrice(total)}</span>
</button> </button>
</form> </form>
</div> </div>
{/* Summary Section */} {/* Summary Section */}
<div className="lg:w-96 space-y-6 order-1 lg:order-2"> <div className="lg:w-96 space-y-6 order-1 lg:order-2">
<div className="bg-white p-6 lg:p-8 rounded-2xl border border-spa-stone/10 shadow-sm sticky top-32 transition-all"> <div className="bg-spa-light p-6 lg:p-8 rounded-2xl border border-spa-stone/10 shadow-sm sticky top-32 transition-all">
<button <button
type="button" type="button"
onClick={() => setIsSummaryExpanded(!isSummaryExpanded)} onClick={() => setIsSummaryExpanded(!isSummaryExpanded)}
@@ -602,13 +602,13 @@ export default function CheckoutPage() {
form="checkout-form" form="checkout-form"
type="submit" type="submit"
disabled={loading || loadingSettings} disabled={loading || loadingSettings}
className="w-full mt-8 py-4 px-6 bg-spa-forest text-white font-bold rounded-xl tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed hidden lg:flex justify-between items-center" className="w-full mt-8 py-4 px-6 bg-spa-forest text-spa-light font-bold rounded-xl tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed hidden lg:flex justify-between items-center"
> >
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{loading && <Loader2 className="w-5 h-5 animate-spin" />} {loading && <Loader2 className="w-5 h-5 animate-spin" />}
<span>Proceed to Payment</span> <span>Proceed to Payment</span>
</div> </div>
<span className="text-sm border-l border-white/20 pl-4">{formatPrice(total)}</span> <span className="text-sm border-l border-spa-light pl-4">{formatPrice(total)}</span>
</button> </button>
</div> </div>
</div> </div>
+2 -2
View File
@@ -139,7 +139,7 @@ export default function CouponsPage() {
{coupons.map(coupon => ( {coupons.map(coupon => (
<div <div
key={coupon.id} key={coupon.id}
className="group relative bg-white border border-spa-stone/10 rounded-3xl overflow-hidden hover:border-spa-forest transition-all duration-500 shadow-sm hover:shadow-md" className="group relative bg-spa-light border border-spa-stone/10 rounded-3xl overflow-hidden hover:border-spa-forest transition-all duration-500 shadow-sm hover:shadow-md"
> >
{/* Decoration */} {/* Decoration */}
<div className="absolute top-0 right-0 w-32 h-32 bg-spa-sage/20 blur-3xl rounded-full -translate-y-1/2 translate-x-1/2" /> <div className="absolute top-0 right-0 w-32 h-32 bg-spa-sage/20 blur-3xl rounded-full -translate-y-1/2 translate-x-1/2" />
@@ -184,7 +184,7 @@ export default function CouponsPage() {
<button <button
onClick={() => handleUseNow(coupon.code)} onClick={() => handleUseNow(coupon.code)}
className="w-full py-4 bg-spa-forest text-white hover:bg-spa-stone font-bold rounded-xl flex items-center justify-center gap-2 transition-all duration-300 shadow-sm" className="w-full py-4 bg-spa-forest text-spa-light hover:bg-spa-stone font-bold rounded-xl flex items-center justify-center gap-2 transition-all duration-300 shadow-sm"
> >
ใช้คูปองนี้เลย ใช้คูปองนี้เลย
<ArrowRight className="w-4 h-4" /> <ArrowRight className="w-4 h-4" />
+8 -8
View File
@@ -2,7 +2,7 @@ import { Link } from 'react-router-dom'
export default function NotFoundPage() { export default function NotFoundPage() {
return ( return (
<div className="min-h-screen flex items-center justify-center px-6 bg-white"> <div className="min-h-screen flex items-center justify-center px-6 bg-spa-light">
{/* Background glow */} {/* Background glow */}
<div className="absolute inset-0 pointer-events-none overflow-hidden"> <div className="absolute inset-0 pointer-events-none overflow-hidden">
<div className="absolute top-1/3 left-1/2 -translate-x-1/2 -translate-y-1/2 w-96 h-96 bg-spa-forest/10 rounded-full blur-3xl" /> <div className="absolute top-1/3 left-1/2 -translate-x-1/2 -translate-y-1/2 w-96 h-96 bg-spa-forest/10 rounded-full blur-3xl" />
@@ -22,7 +22,7 @@ export default function NotFoundPage() {
<div className="space-y-3"> <div className="space-y-3">
<h1 className="text-3xl font-bold">Page Not Found</h1> <h1 className="text-3xl font-bold">Page Not Found</h1>
<p className="text-slate-400 leading-relaxed"> <p className="text-spa-stone leading-relaxed">
The page you're looking for seems to have drifted away like morning mist. Let's guide you back to serenity. The page you're looking for seems to have drifted away like morning mist. Let's guide you back to serenity.
</p> </p>
</div> </div>
@@ -30,23 +30,23 @@ export default function NotFoundPage() {
<div className="flex flex-col sm:flex-row gap-4 justify-center pt-2"> <div className="flex flex-col sm:flex-row gap-4 justify-center pt-2">
<Link <Link
to="/" to="/"
className="px-8 py-3.5 bg-white text-spa-forest font-bold rounded-lg tracking-widest uppercase hover:bg-spa-forest text-white hover:shadow-[0_0_25px_rgba(102,252,241,0.4)] transition-all duration-500 text-sm" className="px-8 py-3.5 bg-spa-light text-spa-forest font-bold rounded-lg tracking-widest uppercase hover:bg-spa-forest text-spa-light hover:shadow-[0_0_25px_rgba(102,252,241,0.4)] transition-all duration-500 text-sm"
> >
Go Home Go Home
</Link> </Link>
<Link <Link
to="/shop" to="/shop"
className="px-8 py-3.5 bg-white shadow-sm border border-spa-stone/10 text-white font-bold rounded-lg tracking-widest uppercase hover:bg-white/10 transition-all duration-300 border border-spa-stone/10 text-sm" className="px-8 py-3.5 bg-spa-light shadow-sm border border-spa-stone/10 text-spa-light font-bold rounded-lg tracking-widest uppercase hover:bg-spa-light transition-all duration-300 border border-spa-stone/10 text-sm"
> >
Browse Products Browse Products
</Link> </Link>
</div> </div>
<div className="pt-4 border-t border-spa-stone/10"> <div className="pt-4 border-t border-spa-stone/10">
<div className="flex justify-center gap-6 text-xs text-slate-500"> <div className="flex justify-center gap-6 text-xs text-spa-stone">
<Link to="/scent-guide" className="hover:text-white transition-colors">Scent Guide</Link> <Link to="/scent-guide" className="hover:text-spa-light transition-colors">Scent Guide</Link>
<Link to="/faq" className="hover:text-white transition-colors">FAQ</Link> <Link to="/faq" className="hover:text-spa-light transition-colors">FAQ</Link>
<Link to="/contact" className="hover:text-white transition-colors">Contact</Link> <Link to="/contact" className="hover:text-spa-light transition-colors">Contact</Link>
</div> </div>
</div> </div>
</div> </div>
+17 -17
View File
@@ -258,7 +258,7 @@ export default function OrderSuccessPage() {
</div> </div>
{/* Order Summary */} {/* Order Summary */}
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 space-y-6 shadow-sm"> <div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 space-y-6 shadow-sm">
<h2 className="text-sm font-bold uppercase tracking-widest text-spa-forest border-b border-spa-stone/10 pb-4">Order Items</h2> <h2 className="text-sm font-bold uppercase tracking-widest text-spa-forest border-b border-spa-stone/10 pb-4">Order Items</h2>
<div className="space-y-4"> <div className="space-y-4">
{order.items.map(item => ( {order.items.map(item => (
@@ -293,13 +293,13 @@ export default function OrderSuccessPage() {
{order.status === 'PENDING_PAYMENT' ? ( {order.status === 'PENDING_PAYMENT' ? (
<div className="space-y-8"> <div className="space-y-8">
{/* Payment Method Selector */} {/* Payment Method Selector */}
<div className="bg-white p-4 rounded-2xl border border-spa-stone/10 shadow-sm flex flex-col md:flex-row gap-3"> <div className="bg-spa-light p-4 rounded-2xl border border-spa-stone/10 shadow-sm flex flex-col md:flex-row gap-3">
<button <button
onClick={() => setPaymentMethod('bank')} onClick={() => setPaymentMethod('bank')}
className={`flex-1 py-4 px-6 rounded-xl font-bold flex items-center justify-center gap-3 border transition-all ${ className={`flex-1 py-4 px-6 rounded-xl font-bold flex items-center justify-center gap-3 border transition-all ${
paymentMethod === 'bank' paymentMethod === 'bank'
? 'bg-spa-forest text-white border-spa-forest shadow-sm' ? 'bg-spa-forest text-spa-light border-spa-forest shadow-sm'
: 'bg-white text-spa-stone hover:bg-spa-light border-spa-stone/10' : 'bg-spa-light text-spa-stone hover:bg-spa-light border-spa-stone/10'
}`} }`}
> >
<Landmark className="w-5 h-5" /> <Landmark className="w-5 h-5" />
@@ -309,8 +309,8 @@ export default function OrderSuccessPage() {
onClick={() => setPaymentMethod('promptpay')} onClick={() => setPaymentMethod('promptpay')}
className={`flex-1 py-4 px-6 rounded-xl font-bold flex items-center justify-center gap-3 border transition-all ${ className={`flex-1 py-4 px-6 rounded-xl font-bold flex items-center justify-center gap-3 border transition-all ${
paymentMethod === 'promptpay' paymentMethod === 'promptpay'
? 'bg-spa-forest text-white border-spa-forest shadow-sm' ? 'bg-spa-forest text-spa-light border-spa-forest shadow-sm'
: 'bg-white text-spa-stone hover:bg-spa-light border-spa-stone/10' : 'bg-spa-light text-spa-stone hover:bg-spa-light border-spa-stone/10'
}`} }`}
> >
<QrCode className="w-5 h-5" /> <QrCode className="w-5 h-5" />
@@ -320,8 +320,8 @@ export default function OrderSuccessPage() {
onClick={() => setPaymentMethod('card')} onClick={() => setPaymentMethod('card')}
className={`flex-1 py-4 px-6 rounded-xl font-bold flex items-center justify-center gap-3 border transition-all ${ className={`flex-1 py-4 px-6 rounded-xl font-bold flex items-center justify-center gap-3 border transition-all ${
paymentMethod === 'card' paymentMethod === 'card'
? 'bg-spa-forest text-white border-spa-forest shadow-sm' ? 'bg-spa-forest text-spa-light border-spa-forest shadow-sm'
: 'bg-white text-spa-stone hover:bg-spa-light border-spa-stone/10' : 'bg-spa-light text-spa-stone hover:bg-spa-light border-spa-stone/10'
}`} }`}
> >
<CreditCard className="w-5 h-5" /> <CreditCard className="w-5 h-5" />
@@ -332,7 +332,7 @@ export default function OrderSuccessPage() {
{/* Bank Transfer Layout */} {/* Bank Transfer Layout */}
{paymentMethod === 'bank' && settings && ( {paymentMethod === 'bank' && settings && (
<div className="space-y-8"> <div className="space-y-8">
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 text-center space-y-6 relative overflow-hidden shadow-sm"> <div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 text-center space-y-6 relative overflow-hidden shadow-sm">
<div className="absolute top-0 inset-x-0 h-1 bg-gradient-to-r from-transparent via-spa-forest to-transparent opacity-50" /> <div className="absolute top-0 inset-x-0 h-1 bg-gradient-to-r from-transparent via-spa-forest to-transparent opacity-50" />
<h2 className="text-xs uppercase font-bold tracking-widest text-spa-stone/80">Payment Required</h2> <h2 className="text-xs uppercase font-bold tracking-widest text-spa-stone/80">Payment Required</h2>
<div className="text-3xl font-bold text-spa-forest">{formatPrice(order.totalAmount)}</div> <div className="text-3xl font-bold text-spa-forest">{formatPrice(order.totalAmount)}</div>
@@ -348,7 +348,7 @@ export default function OrderSuccessPage() {
</div> </div>
<button <button
onClick={copyToClipboard} onClick={copyToClipboard}
className="p-2 bg-white rounded-lg hover:bg-spa-stone/10 border border-spa-stone/20 transition-colors shrink-0 shadow-sm" className="p-2 bg-spa-light rounded-lg hover:bg-spa-stone/10 border border-spa-stone/20 transition-colors shrink-0 shadow-sm"
title="Copy account number" title="Copy account number"
> >
{copied ? <CheckCircle2 className="w-5 h-5 text-emerald-500" /> : <Copy className="w-5 h-5 text-spa-stone/80" />} {copied ? <CheckCircle2 className="w-5 h-5 text-emerald-500" /> : <Copy className="w-5 h-5 text-spa-stone/80" />}
@@ -362,7 +362,7 @@ export default function OrderSuccessPage() {
<p className="text-xs text-spa-stone font-medium">Please transfer the exact amount and upload your slip below.</p> <p className="text-xs text-spa-stone font-medium">Please transfer the exact amount and upload your slip below.</p>
</div> </div>
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 space-y-6 shadow-sm"> <div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 space-y-6 shadow-sm">
<h2 className="text-sm font-bold uppercase tracking-widest text-spa-forest border-b border-spa-stone/10 pb-4">Payment Slip Verification</h2> <h2 className="text-sm font-bold uppercase tracking-widest text-spa-forest border-b border-spa-stone/10 pb-4">Payment Slip Verification</h2>
{order.paymentSlipUrl ? ( {order.paymentSlipUrl ? (
<div className="flex flex-col items-center justify-center space-y-4 py-4"> <div className="flex flex-col items-center justify-center space-y-4 py-4">
@@ -404,7 +404,7 @@ export default function OrderSuccessPage() {
{/* PromptPay Layout */} {/* PromptPay Layout */}
{paymentMethod === 'promptpay' && ( {paymentMethod === 'promptpay' && (
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 text-center space-y-6 relative overflow-hidden shadow-sm"> <div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 text-center space-y-6 relative overflow-hidden shadow-sm">
<div className="absolute top-0 inset-x-0 h-1 bg-gradient-to-r from-transparent via-spa-forest to-transparent opacity-50" /> <div className="absolute top-0 inset-x-0 h-1 bg-gradient-to-r from-transparent via-spa-forest to-transparent opacity-50" />
<h2 className="text-xs uppercase font-bold tracking-widest text-spa-stone/80">PromptPay QR Code</h2> <h2 className="text-xs uppercase font-bold tracking-widest text-spa-stone/80">PromptPay QR Code</h2>
<div className="text-3xl font-bold text-spa-forest">{formatPrice(order.totalAmount)}</div> <div className="text-3xl font-bold text-spa-forest">{formatPrice(order.totalAmount)}</div>
@@ -414,7 +414,7 @@ export default function OrderSuccessPage() {
<button <button
onClick={handleGeneratePromptPay} onClick={handleGeneratePromptPay}
disabled={generatingQr} disabled={generatingQr}
className="px-8 py-4 bg-spa-forest text-white font-bold rounded-xl tracking-widest uppercase hover:bg-spa-stone transition-all duration-300 disabled:opacity-50 flex items-center justify-center gap-3 mx-auto" className="px-8 py-4 bg-spa-forest text-spa-light font-bold rounded-xl tracking-widest uppercase hover:bg-spa-stone transition-all duration-300 disabled:opacity-50 flex items-center justify-center gap-3 mx-auto"
> >
{generatingQr ? <Loader2 className="w-5 h-5 animate-spin" /> : <QrCode className="w-5 h-5" />} {generatingQr ? <Loader2 className="w-5 h-5 animate-spin" /> : <QrCode className="w-5 h-5" />}
<span>สร้างคิวอาร์โค้ด PromptPay</span> <span>สร้างคิวอาร์โค้ด PromptPay</span>
@@ -422,7 +422,7 @@ export default function OrderSuccessPage() {
</div> </div>
) : ( ) : (
<div className="space-y-6 max-w-sm mx-auto"> <div className="space-y-6 max-w-sm mx-auto">
<div className="bg-white p-4 rounded-xl border border-spa-stone/20 inline-block shadow-sm"> <div className="bg-spa-light p-4 rounded-xl border border-spa-stone/20 inline-block shadow-sm">
<img src={qrCodeUrl} alt="PromptPay QR Code" className="w-64 h-64 object-contain mx-auto" /> <img src={qrCodeUrl} alt="PromptPay QR Code" className="w-64 h-64 object-contain mx-auto" />
</div> </div>
@@ -452,7 +452,7 @@ export default function OrderSuccessPage() {
{/* Credit Card Layout */} {/* Credit Card Layout */}
{paymentMethod === 'card' && ( {paymentMethod === 'card' && (
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 space-y-6 relative overflow-hidden shadow-sm"> <div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 space-y-6 relative overflow-hidden shadow-sm">
<div className="absolute top-0 inset-x-0 h-1 bg-gradient-to-r from-transparent via-spa-forest to-transparent opacity-50" /> <div className="absolute top-0 inset-x-0 h-1 bg-gradient-to-r from-transparent via-spa-forest to-transparent opacity-50" />
<div className="text-center space-y-2"> <div className="text-center space-y-2">
<h2 className="text-xs uppercase font-bold tracking-widest text-spa-stone/80">Credit / Debit Card</h2> <h2 className="text-xs uppercase font-bold tracking-widest text-spa-stone/80">Credit / Debit Card</h2>
@@ -527,7 +527,7 @@ export default function OrderSuccessPage() {
<button <button
type="submit" type="submit"
disabled={payingCard} disabled={payingCard}
className="w-full py-4 bg-spa-forest text-white font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone transition-all duration-300 disabled:opacity-50 flex items-center justify-center gap-2 mt-4" className="w-full py-4 bg-spa-forest text-spa-light font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone transition-all duration-300 disabled:opacity-50 flex items-center justify-center gap-2 mt-4"
> >
{payingCard ? <Loader2 className="w-5 h-5 animate-spin" /> : <CreditCard className="w-5 h-5" />} {payingCard ? <Loader2 className="w-5 h-5 animate-spin" /> : <CreditCard className="w-5 h-5" />}
<span>ชำระเงิน {formatPrice(order.totalAmount)}</span> <span>ชำระเงิน {formatPrice(order.totalAmount)}</span>
@@ -537,7 +537,7 @@ export default function OrderSuccessPage() {
)} )}
</div> </div>
) : ( ) : (
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 text-center space-y-6 shadow-sm"> <div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 text-center space-y-6 shadow-sm">
<div className="w-16 h-16 bg-emerald-500/10 rounded-full flex items-center justify-center border border-emerald-500/20 mx-auto"> <div className="w-16 h-16 bg-emerald-500/10 rounded-full flex items-center justify-center border border-emerald-500/20 mx-auto">
<CheckCircle2 className="w-8 h-8 text-emerald-500" /> <CheckCircle2 className="w-8 h-8 text-emerald-500" />
</div> </div>
+9 -9
View File
@@ -220,12 +220,12 @@ export default function ProductDetailPage() {
onClick={() => setSelectedVariant(i)} onClick={() => setSelectedVariant(i)}
className={`px-5 py-2.5 rounded-lg text-sm font-bold uppercase tracking-widest transition-all duration-300 border ${ className={`px-5 py-2.5 rounded-lg text-sm font-bold uppercase tracking-widest transition-all duration-300 border ${
selectedVariant === i selectedVariant === i
? 'bg-spa-forest text-white border-spa-forest shadow-md' ? 'bg-spa-forest text-spa-light border-spa-forest shadow-md'
: 'bg-white text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm' : 'bg-spa-light text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm'
}`} }`}
> >
{v.size} {v.size}
<span className={`block text-[10px] mt-0.5 ${selectedVariant === i ? 'text-white/80' : 'text-spa-stone/60'}`}> <span className={`block text-[10px] mt-0.5 ${selectedVariant === i ? 'text-spa-light' : 'text-spa-stone/60'}`}>
{formatPrice(v.price)} {formatPrice(v.price)}
</span> </span>
</button> </button>
@@ -237,11 +237,11 @@ export default function ProductDetailPage() {
<div className="hidden md:flex gap-4"> <div className="hidden md:flex gap-4">
<button <button
onClick={handleAddToCart} onClick={handleAddToCart}
className="flex-1 py-4 bg-spa-forest text-white font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300" className="flex-1 py-4 bg-spa-forest text-spa-light font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300"
> >
{t('cart.addToCart')} {t('cart.addToCart')}
</button> </button>
<button className="bg-white border border-spa-stone/20 text-spa-stone p-4 rounded-lg hover:border-spa-forest hover:text-spa-forest shadow-sm transition-all"> <button className="bg-spa-light border border-spa-stone/20 text-spa-stone p-4 rounded-lg hover:border-spa-forest hover:text-spa-forest shadow-sm transition-all">
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
</svg> </svg>
@@ -322,7 +322,7 @@ export default function ProductDetailPage() {
<Footer categories={categories} /> <Footer categories={categories} />
{/* Mobile Sticky Add to Cart Bar */} {/* Mobile Sticky Add to Cart Bar */}
<div className="md:hidden fixed bottom-0 left-0 right-0 p-4 bg-white/95 backdrop-blur-xl border-t border-spa-stone/10 z-40 animate-fade-in flex flex-col gap-3 shadow-[0_-10px_30px_rgba(0,0,0,0.05)]"> <div className="md:hidden fixed bottom-0 left-0 right-0 p-4 bg-spa-light backdrop-blur-xl border-t border-spa-stone/10 z-40 animate-fade-in flex flex-col gap-3 shadow-[0_-10px_30px_rgba(0,0,0,0.05)]">
{/* Mobile Variant Selector */} {/* Mobile Variant Selector */}
{product.variants && product.variants.length > 1 && ( {product.variants && product.variants.length > 1 && (
@@ -333,8 +333,8 @@ export default function ProductDetailPage() {
onClick={() => setSelectedVariant(i)} onClick={() => setSelectedVariant(i)}
className={`flex-shrink-0 px-4 py-2 rounded-lg text-[10px] font-bold uppercase tracking-widest transition-all border whitespace-nowrap ${ className={`flex-shrink-0 px-4 py-2 rounded-lg text-[10px] font-bold uppercase tracking-widest transition-all border whitespace-nowrap ${
selectedVariant === i selectedVariant === i
? 'bg-spa-forest border-spa-forest text-white' ? 'bg-spa-forest border-spa-forest text-spa-light'
: 'bg-white border-spa-stone/20 text-spa-stone' : 'bg-spa-light border-spa-stone/20 text-spa-stone'
}`} }`}
> >
{v.size} {v.size}
@@ -354,7 +354,7 @@ export default function ProductDetailPage() {
</div> </div>
<button <button
onClick={handleAddToCart} onClick={handleAddToCart}
className="flex-1 py-3.5 bg-spa-forest text-white font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone shadow-sm transition-all flex justify-center items-center gap-2" className="flex-1 py-3.5 bg-spa-forest text-spa-light font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone shadow-sm transition-all flex justify-center items-center gap-2"
> >
{t('cart.addToCart')} {t('cart.addToCart')}
</button> </button>
+13 -13
View File
@@ -303,7 +303,7 @@ export default function ProfilePage() {
{!customer ? ( {!customer ? (
/* Login CTA screen */ /* Login CTA screen */
<div className="max-w-md mx-auto text-center space-y-8 py-20 animate-fade-in bg-white p-10 rounded-3xl border border-spa-stone/10 shadow-sm mt-10"> <div className="max-w-md mx-auto text-center space-y-8 py-20 animate-fade-in bg-spa-light p-10 rounded-3xl border border-spa-stone/10 shadow-sm mt-10">
<div className="w-20 h-20 bg-spa-light rounded-full flex items-center justify-center mx-auto border border-spa-stone/10 shadow-inner"> <div className="w-20 h-20 bg-spa-light rounded-full flex items-center justify-center mx-auto border border-spa-stone/10 shadow-inner">
<User className="w-10 h-10 text-spa-stone" /> <User className="w-10 h-10 text-spa-stone" />
</div> </div>
@@ -320,7 +320,7 @@ export default function ProfilePage() {
alert('LINE LIFF System is initializing. Please refresh.') alert('LINE LIFF System is initializing. Please refresh.')
} }
}} }}
className="w-full py-4 bg-spa-forest hover:bg-spa-stone text-white font-bold rounded-xl tracking-widest uppercase transition-all duration-300 shadow-sm flex items-center justify-center gap-3" className="w-full py-4 bg-spa-forest hover:bg-spa-stone text-spa-light font-bold rounded-xl tracking-widest uppercase transition-all duration-300 shadow-sm flex items-center justify-center gap-3"
> >
<Award className="w-5 h-5" /> <Award className="w-5 h-5" />
<span>เข้าสู่ระบบผ่าน LINE</span> <span>เข้าสู่ระบบผ่าน LINE</span>
@@ -331,7 +331,7 @@ export default function ProfilePage() {
/* Logged In Dashboard Layout */ /* Logged In Dashboard Layout */
<div className="space-y-10 animate-fade-in"> <div className="space-y-10 animate-fade-in">
{/* Header Profile Banner */} {/* Header Profile Banner */}
<div className="bg-white rounded-2xl border border-spa-stone/10 p-5 sm:p-6 flex flex-col sm:flex-row justify-between items-center sm:items-center gap-4 shadow-sm relative overflow-hidden"> <div className="bg-spa-light rounded-2xl border border-spa-stone/10 p-5 sm:p-6 flex flex-col sm:flex-row justify-between items-center sm:items-center gap-4 shadow-sm relative overflow-hidden">
<div className="absolute top-0 inset-x-0 h-1 bg-gradient-to-r from-spa-sage via-spa-forest to-spa-stone opacity-40" /> <div className="absolute top-0 inset-x-0 h-1 bg-gradient-to-r from-spa-sage via-spa-forest to-spa-stone opacity-40" />
{/* User Avatar & Info */} {/* User Avatar & Info */}
@@ -459,7 +459,7 @@ export default function ProfilePage() {
<Loader2 className="w-8 h-8 text-spa-forest animate-spin" /> <Loader2 className="w-8 h-8 text-spa-forest animate-spin" />
</div> </div>
) : orders.length === 0 ? ( ) : orders.length === 0 ? (
<div className="text-center py-16 bg-white rounded-2xl border border-spa-stone/10 space-y-4 shadow-sm"> <div className="text-center py-16 bg-spa-light rounded-2xl border border-spa-stone/10 space-y-4 shadow-sm">
<Package className="w-12 h-12 text-spa-stone/40 mx-auto" /> <Package className="w-12 h-12 text-spa-stone/40 mx-auto" />
<div> <div>
<p className="font-bold text-pop-black">ไม่มีประวัติการสั่งซื้อ</p> <p className="font-bold text-pop-black">ไม่มีประวัติการสั่งซื้อ</p>
@@ -467,7 +467,7 @@ export default function ProfilePage() {
</div> </div>
<Link <Link
to="/shop" to="/shop"
className="inline-block px-6 py-2.5 bg-spa-forest hover:bg-spa-stone text-white font-bold rounded-lg text-xs uppercase tracking-wider transition-colors shadow-sm" className="inline-block px-6 py-2.5 bg-spa-forest hover:bg-spa-stone text-spa-light font-bold rounded-lg text-xs uppercase tracking-wider transition-colors shadow-sm"
> >
ไปหน้าช้อปปิ้ง ไปหน้าช้อปปิ้ง
</Link> </Link>
@@ -477,7 +477,7 @@ export default function ProfilePage() {
{orders.map(order => ( {orders.map(order => (
<div <div
key={order.id} key={order.id}
className="bg-white border border-spa-stone/10 rounded-2xl p-6 shadow-sm hover:border-spa-stone transition-all duration-300 space-y-4" className="bg-spa-light border border-spa-stone/10 rounded-2xl p-6 shadow-sm hover:border-spa-stone transition-all duration-300 space-y-4"
> >
{/* Card Header */} {/* Card Header */}
<div className="flex flex-col md:flex-row justify-between md:items-center gap-3 border-b border-spa-stone/10 pb-4"> <div className="flex flex-col md:flex-row justify-between md:items-center gap-3 border-b border-spa-stone/10 pb-4">
@@ -550,7 +550,7 @@ export default function ProfilePage() {
resetAddressForm() resetAddressForm()
setShowAddressForm(true) setShowAddressForm(true)
}} }}
className="px-4 py-2 bg-spa-forest hover:bg-spa-stone text-white font-bold rounded-lg text-xs uppercase tracking-wider transition-colors shadow-sm flex items-center gap-2" className="px-4 py-2 bg-spa-forest hover:bg-spa-stone text-spa-light font-bold rounded-lg text-xs uppercase tracking-wider transition-colors shadow-sm flex items-center gap-2"
> >
<Plus className="w-3.5 h-3.5" /> <Plus className="w-3.5 h-3.5" />
<span>เพิ่มที่อยู่ใหม่</span> <span>เพิ่มที่อยู่ใหม่</span>
@@ -560,7 +560,7 @@ export default function ProfilePage() {
{/* Address Creation/Editing Form */} {/* Address Creation/Editing Form */}
{showAddressForm && ( {showAddressForm && (
<form onSubmit={handleAddressSubmit} className="bg-white border border-spa-stone/15 p-6 rounded-2xl shadow-sm space-y-5 animate-slide-down"> <form onSubmit={handleAddressSubmit} className="bg-spa-light border border-spa-stone/15 p-6 rounded-2xl shadow-sm space-y-5 animate-slide-down">
<h3 className="text-sm font-bold uppercase tracking-widest text-spa-forest border-b border-spa-stone/10 pb-2"> <h3 className="text-sm font-bold uppercase tracking-widest text-spa-forest border-b border-spa-stone/10 pb-2">
{editingAddress ? 'แก้ไขที่อยู่จัดส่ง' : 'เพิ่มที่อยู่จัดส่งใหม่'} {editingAddress ? 'แก้ไขที่อยู่จัดส่ง' : 'เพิ่มที่อยู่จัดส่งใหม่'}
</h3> </h3>
@@ -636,7 +636,7 @@ export default function ProfilePage() {
<button <button
type="submit" type="submit"
disabled={submittingAddress} disabled={submittingAddress}
className="px-5 py-2.5 bg-spa-forest hover:bg-spa-stone text-white font-bold rounded-lg text-xs uppercase tracking-wider transition-colors disabled:opacity-50 flex items-center gap-2" className="px-5 py-2.5 bg-spa-forest hover:bg-spa-stone text-spa-light font-bold rounded-lg text-xs uppercase tracking-wider transition-colors disabled:opacity-50 flex items-center gap-2"
> >
{submittingAddress && <Loader2 className="w-3.5 h-3.5 animate-spin" />} {submittingAddress && <Loader2 className="w-3.5 h-3.5 animate-spin" />}
<span>บันทึกที่อยู่</span> <span>บันทึกที่อยู่</span>
@@ -650,7 +650,7 @@ export default function ProfilePage() {
<Loader2 className="w-8 h-8 text-spa-forest animate-spin" /> <Loader2 className="w-8 h-8 text-spa-forest animate-spin" />
</div> </div>
) : addresses.length === 0 ? ( ) : addresses.length === 0 ? (
<div className="text-center py-16 bg-white rounded-2xl border border-spa-stone/10 space-y-4 shadow-sm"> <div className="text-center py-16 bg-spa-light rounded-2xl border border-spa-stone/10 space-y-4 shadow-sm">
<MapPin className="w-12 h-12 text-spa-stone/40 mx-auto" /> <MapPin className="w-12 h-12 text-spa-stone/40 mx-auto" />
<div> <div>
<p className="font-bold text-pop-black">ไม่มีข้อมูลที่อยู่จัดส่ง</p> <p className="font-bold text-pop-black">ไม่มีข้อมูลที่อยู่จัดส่ง</p>
@@ -662,7 +662,7 @@ export default function ProfilePage() {
{addresses.map(addr => ( {addresses.map(addr => (
<div <div
key={addr.id} key={addr.id}
className={`bg-white border rounded-2xl p-5 shadow-sm space-y-4 transition-all duration-300 relative ${ className={`bg-spa-light border rounded-2xl p-5 shadow-sm space-y-4 transition-all duration-300 relative ${
addr.isDefault addr.isDefault
? 'border-spa-forest ring-1 ring-spa-forest/20' ? 'border-spa-forest ring-1 ring-spa-forest/20'
: 'border-spa-stone/10 hover:border-spa-stone' : 'border-spa-stone/10 hover:border-spa-stone'
@@ -729,7 +729,7 @@ export default function ProfilePage() {
<span>ข้อมูลติดต่อสมาชิก</span> <span>ข้อมูลติดต่อสมาชิก</span>
</h2> </h2>
<form onSubmit={handleSettingsSubmit} className="bg-white border border-spa-stone/10 rounded-2xl p-6 shadow-sm max-w-lg space-y-5"> <form onSubmit={handleSettingsSubmit} className="bg-spa-light border border-spa-stone/10 rounded-2xl p-6 shadow-sm max-w-lg space-y-5">
{settingsSuccess && ( {settingsSuccess && (
<div className="p-4 bg-emerald-500/10 border border-emerald-500/20 text-emerald-600 font-bold rounded-xl text-xs text-center flex items-center justify-center gap-2"> <div className="p-4 bg-emerald-500/10 border border-emerald-500/20 text-emerald-600 font-bold rounded-xl text-xs text-center flex items-center justify-center gap-2">
<Check className="w-4 h-4" /> <Check className="w-4 h-4" />
@@ -763,7 +763,7 @@ export default function ProfilePage() {
<button <button
type="submit" type="submit"
disabled={submittingSettings} disabled={submittingSettings}
className="w-full py-3 bg-spa-forest hover:bg-spa-stone text-white font-bold rounded-lg text-xs uppercase tracking-widest transition-colors disabled:opacity-50 flex items-center justify-center gap-2" className="w-full py-3 bg-spa-forest hover:bg-spa-stone text-spa-light font-bold rounded-lg text-xs uppercase tracking-widest transition-colors disabled:opacity-50 flex items-center justify-center gap-2"
> >
{submittingSettings ? <Loader2 className="w-4 h-4 animate-spin" /> : <Check className="w-4 h-4" />} {submittingSettings ? <Loader2 className="w-4 h-4 animate-spin" /> : <Check className="w-4 h-4" />}
<span>บันทึกข้อมูลติดต่อ</span> <span>บันทึกข้อมูลติดต่อ</span>
+7 -7
View File
@@ -59,10 +59,10 @@ export default function ScentGuidePage() {
/> />
</div> </div>
) : ( ) : (
<div className="pt-32 pb-16 px-6 text-center space-y-4 border-b border-spa-stone/10 bg-white"> <div className="pt-32 pb-16 px-6 text-center space-y-4 border-b border-spa-stone/10 bg-spa-light">
<p className="text-spa-forest uppercase tracking-[0.4em] text-xs font-semibold opacity-70">Journal</p> <p className="text-spa-forest uppercase tracking-[0.4em] text-xs font-semibold opacity-70">Journal</p>
<h1 className="text-5xl font-bold">Scent Guide</h1> <h1 className="text-5xl font-bold">Scent Guide</h1>
<p className="text-slate-400 max-w-lg mx-auto"> <p className="text-spa-stone max-w-lg mx-auto">
Explore our collection of articles, guides, and sensory knowledge. Explore our collection of articles, guides, and sensory knowledge.
</p> </p>
</div> </div>
@@ -70,7 +70,7 @@ export default function ScentGuidePage() {
<div className="flex-1 max-w-7xl mx-auto px-6 py-16 w-full"> <div className="flex-1 max-w-7xl mx-auto px-6 py-16 w-full">
{articles.length === 0 ? ( {articles.length === 0 ? (
<div className="text-center text-slate-500 italic py-20"> <div className="text-center text-spa-stone italic py-20">
Articles coming soon. Check back later! Articles coming soon. Check back later!
</div> </div>
) : ( ) : (
@@ -81,12 +81,12 @@ export default function ScentGuidePage() {
to={`/article/${article.slug}`} to={`/article/${article.slug}`}
className="group block bg-pop-bg rounded-2xl overflow-hidden border border-spa-stone/10 hover:border-spa-forest transition-all duration-300 hover:-translate-y-1 hover:shadow-2xl flex flex-col" className="group block bg-pop-bg rounded-2xl overflow-hidden border border-spa-stone/10 hover:border-spa-forest transition-all duration-300 hover:-translate-y-1 hover:shadow-2xl flex flex-col"
> >
<div className="aspect-[4/3] bg-white overflow-hidden shrink-0"> <div className="aspect-[4/3] bg-spa-light overflow-hidden shrink-0">
{article.coverImage ? ( {article.coverImage ? (
<img src={article.coverImage} alt={article.title} className="w-full h-full object-cover opacity-80 group-hover:opacity-100 group-hover:scale-105 transition-all duration-500" /> <img src={article.coverImage} alt={article.title} className="w-full h-full object-cover opacity-80 group-hover:opacity-100 group-hover:scale-105 transition-all duration-500" />
) : ( ) : (
<div className="w-full h-full bg-white/5 flex items-center justify-center"> <div className="w-full h-full bg-spa-light flex items-center justify-center">
<span className="text-slate-600 text-sm tracking-widest uppercase">No Image</span> <span className="text-spa-stone text-sm tracking-widest uppercase">No Image</span>
</div> </div>
)} )}
</div> </div>
@@ -96,7 +96,7 @@ export default function ScentGuidePage() {
</p> </p>
<h3 className="text-xl font-bold leading-tight group-hover:text-spa-forest transition-colors">{article.title}</h3> <h3 className="text-xl font-bold leading-tight group-hover:text-spa-forest transition-colors">{article.title}</h3>
{/* Remove HTML tags for purely excerpt preview */} {/* Remove HTML tags for purely excerpt preview */}
<div className="text-slate-400 text-sm line-clamp-3" dangerouslySetInnerHTML={{ __html: article.content }} /> <div className="text-spa-stone text-sm line-clamp-3" dangerouslySetInnerHTML={{ __html: article.content }} />
</div> </div>
</Link> </Link>
))} ))}
+3 -3
View File
@@ -100,7 +100,7 @@ export default function SearchPage() {
<h1 className="text-5xl font-bold text-pop-black">Search Products</h1> <h1 className="text-5xl font-bold text-pop-black">Search Products</h1>
<form onSubmit={handleSubmit} className="relative"> <form onSubmit={handleSubmit} className="relative">
<div className="flex bg-white border border-spa-stone/20 rounded-2xl overflow-hidden shadow-sm focus-within:border-spa-forest focus-within:ring-1 focus-within:ring-spa-forest transition-all"> <div className="flex bg-spa-light border border-spa-stone/20 rounded-2xl overflow-hidden shadow-sm focus-within:border-spa-forest focus-within:ring-1 focus-within:ring-spa-forest transition-all">
<svg className="w-5 h-5 text-spa-stone m-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg className="w-5 h-5 text-spa-stone m-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg> </svg>
@@ -114,7 +114,7 @@ export default function SearchPage() {
/> />
<button <button
type="submit" type="submit"
className="bg-spa-forest text-white px-8 font-bold text-xs uppercase tracking-widest hover:bg-spa-stone transition-colors shrink-0" className="bg-spa-forest text-spa-light px-8 font-bold text-xs uppercase tracking-widest hover:bg-spa-stone transition-colors shrink-0"
> >
Search Search
</button> </button>
@@ -127,7 +127,7 @@ export default function SearchPage() {
<Link <Link
key={cat.id} key={cat.id}
to={`/search?q=${encodeURIComponent(typeof cat.name === 'string' ? cat.name : (cat.name as any)?.[i18n.language] || (cat.name as any)?.en || '')}`} to={`/search?q=${encodeURIComponent(typeof cat.name === 'string' ? cat.name : (cat.name as any)?.[i18n.language] || (cat.name as any)?.en || '')}`}
className="bg-white border border-spa-stone/20 px-4 py-1.5 rounded-full text-xs font-medium text-spa-stone hover:border-spa-forest hover:text-spa-forest shadow-sm transition-all duration-300" className="bg-spa-light border border-spa-stone/20 px-4 py-1.5 rounded-full text-xs font-medium text-spa-stone hover:border-spa-forest hover:text-spa-forest shadow-sm transition-all duration-300"
> >
{typeof cat.name === 'string' ? cat.name : (cat.name as any)?.[i18n.language] || (cat.name as any)?.en || ''} {typeof cat.name === 'string' ? cat.name : (cat.name as any)?.[i18n.language] || (cat.name as any)?.en || ''}
</Link> </Link>
+6 -6
View File
@@ -154,7 +154,7 @@ export default function ShopPage() {
{/* Search */} {/* Search */}
<div className="max-w-md mx-auto mt-6"> <div className="max-w-md mx-auto mt-6">
<div className="flex bg-white border border-spa-stone/20 rounded-xl overflow-hidden shadow-sm focus-within:border-spa-forest focus-within:ring-1 focus-within:ring-spa-forest transition-all"> <div className="flex bg-spa-light border border-spa-stone/20 rounded-xl overflow-hidden shadow-sm focus-within:border-spa-forest focus-within:ring-1 focus-within:ring-spa-forest transition-all">
<svg className="w-4 h-4 text-spa-stone m-3.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg className="w-4 h-4 text-spa-stone m-3.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg> </svg>
@@ -173,7 +173,7 @@ export default function ShopPage() {
{/* Render Search bar below Hero block if Hero is configured */} {/* Render Search bar below Hero block if Hero is configured */}
{heroSections.length > 0 && ( {heroSections.length > 0 && (
<div className="max-w-md mx-auto mt-8 px-6"> <div className="max-w-md mx-auto mt-8 px-6">
<div className="flex bg-white border border-spa-stone/20 rounded-xl overflow-hidden shadow-sm focus-within:border-spa-forest focus-within:ring-1 focus-within:ring-spa-forest transition-all"> <div className="flex bg-spa-light border border-spa-stone/20 rounded-xl overflow-hidden shadow-sm focus-within:border-spa-forest focus-within:ring-1 focus-within:ring-spa-forest transition-all">
<svg className="w-4 h-4 text-spa-stone m-3.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg className="w-4 h-4 text-spa-stone m-3.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg> </svg>
@@ -195,8 +195,8 @@ export default function ShopPage() {
onClick={() => setActiveCategory(null)} onClick={() => setActiveCategory(null)}
className={`px-5 py-2 rounded-full text-xs font-bold uppercase tracking-widest transition-all duration-300 border ${ className={`px-5 py-2 rounded-full text-xs font-bold uppercase tracking-widest transition-all duration-300 border ${
activeCategory === null activeCategory === null
? 'bg-spa-forest text-white border-spa-forest shadow-md' ? 'bg-spa-forest text-spa-light border-spa-forest shadow-md'
: 'bg-white text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm' : 'bg-spa-light text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm'
}`} }`}
> >
All All
@@ -207,8 +207,8 @@ export default function ShopPage() {
onClick={() => setActiveCategory(cat.id)} onClick={() => setActiveCategory(cat.id)}
className={`px-5 py-2 rounded-full text-xs font-bold uppercase tracking-widest transition-all duration-300 border ${ className={`px-5 py-2 rounded-full text-xs font-bold uppercase tracking-widest transition-all duration-300 border ${
activeCategory === cat.id activeCategory === cat.id
? 'bg-spa-forest text-white border-spa-forest shadow-md' ? 'bg-spa-forest text-spa-light border-spa-forest shadow-md'
: 'bg-white text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm' : 'bg-spa-light text-spa-stone border-spa-stone/20 hover:border-spa-forest hover:text-spa-forest shadow-sm'
}`} }`}
> >
{typeof cat.name === 'string' ? cat.name : (cat.name as any)?.[i18n.language] || (cat.name as any)?.en || ''} {typeof cat.name === 'string' ? cat.name : (cat.name as any)?.[i18n.language] || (cat.name as any)?.en || ''}
+6 -6
View File
@@ -144,7 +144,7 @@ export default function TrackOrderPage() {
<div className="grid md:grid-cols-2 gap-12"> <div className="grid md:grid-cols-2 gap-12">
{/* Tracking Form */} {/* Tracking Form */}
<div className="bg-white p-8 rounded-2xl border border-spa-stone/10 space-y-6 self-start shadow-sm"> <div className="bg-spa-light p-8 rounded-2xl border border-spa-stone/10 space-y-6 self-start shadow-sm">
<h2 className="text-lg font-bold uppercase tracking-widest border-b border-spa-stone/10 pb-4 flex items-center gap-2 text-spa-forest"> <h2 className="text-lg font-bold uppercase tracking-widest border-b border-spa-stone/10 pb-4 flex items-center gap-2 text-spa-forest">
<Search className="w-5 h-5" /> Manual Search <Search className="w-5 h-5" /> Manual Search
</h2> </h2>
@@ -183,7 +183,7 @@ export default function TrackOrderPage() {
<button <button
type="submit" type="submit"
disabled={loading} disabled={loading}
className="w-full py-4 bg-spa-forest text-white font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300 disabled:opacity-50 flex items-center justify-center gap-2" className="w-full py-4 bg-spa-forest text-spa-light font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone hover:shadow-lg transition-all duration-300 disabled:opacity-50 flex items-center justify-center gap-2"
> >
{loading ? <Loader2 className="w-5 h-5 animate-spin" /> : 'Find Order'} {loading ? <Loader2 className="w-5 h-5 animate-spin" /> : 'Find Order'}
</button> </button>
@@ -214,7 +214,7 @@ export default function TrackOrderPage() {
<Link <Link
key={order.id} key={order.id}
to={`/order/${order.id}`} to={`/order/${order.id}`}
className="flex justify-between items-center p-5 bg-white rounded-xl border border-spa-stone/10 shadow-sm hover:border-spa-forest transition-all group" className="flex justify-between items-center p-5 bg-spa-light rounded-xl border border-spa-stone/10 shadow-sm hover:border-spa-forest transition-all group"
> >
<div> <div>
<div className="flex items-center gap-2 mb-1"> <div className="flex items-center gap-2 mb-1">
@@ -235,7 +235,7 @@ export default function TrackOrderPage() {
<p className="text-[10px] text-spa-stone uppercase">{order.items.length} items</p> <p className="text-[10px] text-spa-stone uppercase">{order.items.length} items</p>
</div> </div>
<div className="w-10 h-10 rounded-full bg-spa-light flex items-center justify-center group-hover:bg-spa-forest transition-colors shrink-0"> <div className="w-10 h-10 rounded-full bg-spa-light flex items-center justify-center group-hover:bg-spa-forest transition-colors shrink-0">
<ChevronRight className="w-5 h-5 text-spa-stone/80 group-hover:text-white" /> <ChevronRight className="w-5 h-5 text-spa-stone/80 group-hover:text-spa-light" />
</div> </div>
</div> </div>
</Link> </Link>
@@ -254,14 +254,14 @@ export default function TrackOrderPage() {
<Link <Link
key={id} key={id}
to={`/order/${id}`} to={`/order/${id}`}
className="flex justify-between items-center p-5 bg-white rounded-xl border border-spa-stone/10 shadow-sm hover:border-spa-forest transition-all group" className="flex justify-between items-center p-5 bg-spa-light rounded-xl border border-spa-stone/10 shadow-sm hover:border-spa-forest transition-all group"
> >
<div> <div>
<p className="text-xs text-spa-stone/80 uppercase tracking-widest mb-1 font-semibold">Order</p> <p className="text-xs text-spa-stone/80 uppercase tracking-widest mb-1 font-semibold">Order</p>
<p className="text-xl font-bold font-mono text-spa-forest">#{id.toString().padStart(4, '0')}</p> <p className="text-xl font-bold font-mono text-spa-forest">#{id.toString().padStart(4, '0')}</p>
</div> </div>
<div className="w-10 h-10 rounded-full bg-spa-light flex items-center justify-center group-hover:bg-spa-forest transition-colors"> <div className="w-10 h-10 rounded-full bg-spa-light flex items-center justify-center group-hover:bg-spa-forest transition-colors">
<ChevronRight className="w-5 h-5 text-spa-stone/80 group-hover:text-white" /> <ChevronRight className="w-5 h-5 text-spa-stone/80 group-hover:text-spa-light" />
</div> </div>
</Link> </Link>
))} ))}
+2 -2
View File
@@ -76,7 +76,7 @@ export default function WishlistPage() {
)} )}
{items.length === 0 ? ( {items.length === 0 ? (
<div className="text-center py-24 bg-white shadow-sm border border-spa-stone/10 rounded-3xl max-w-2xl mx-auto space-y-6"> <div className="text-center py-24 bg-spa-light shadow-sm border border-spa-stone/10 rounded-3xl max-w-2xl mx-auto space-y-6">
<div className="w-20 h-20 bg-spa-light rounded-full flex items-center justify-center mx-auto"> <div className="w-20 h-20 bg-spa-light rounded-full flex items-center justify-center mx-auto">
<Heart className="w-10 h-10 text-spa-stone/30" /> <Heart className="w-10 h-10 text-spa-stone/30" />
</div> </div>
@@ -85,7 +85,7 @@ export default function WishlistPage() {
<div className="pt-4"> <div className="pt-4">
<Link <Link
to="/shop" to="/shop"
className="inline-block px-8 py-3.5 bg-spa-forest text-white font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone transition-all duration-300 shadow-sm" className="inline-block px-8 py-3.5 bg-spa-forest text-spa-light font-bold rounded-lg tracking-widest uppercase hover:bg-spa-stone transition-all duration-300 shadow-sm"
> >
Browse Shop Browse Shop
</Link> </Link>
+1 -1
View File
@@ -105,7 +105,7 @@ export default async function AboutPage({ params }: { params: Promise<{ lang: st
<h2 className="text-4xl font-bold text-text-main">Ready to find your scent?</h2> <h2 className="text-4xl font-bold text-text-main">Ready to find your scent?</h2>
<p className="mx-auto max-w-md text-muted-text">Let our Scent Guide help you discover the perfect blend for your moment.</p> <p className="mx-auto max-w-md text-muted-text">Let our Scent Guide help you discover the perfect blend for your moment.</p>
<div className="flex flex-col justify-center gap-4 pt-4 sm:flex-row"> <div className="flex flex-col justify-center gap-4 pt-4 sm:flex-row">
<Link href="/scent-guide" className="rounded-full bg-text-main px-10 py-4 font-bold uppercase tracking-widest text-white transition hover:bg-brand-primary"> <Link href="/scent-guide" className="rounded-full bg-text-main px-10 py-4 font-bold uppercase tracking-widest text-surface-card transition hover:bg-brand-primary">
Take the Scent Guide Take the Scent Guide
</Link> </Link>
<Link href="/shop" className="rounded-full border border-brand-primary bg-surface-card px-10 py-4 font-bold uppercase tracking-widest text-brand-primary transition hover:bg-surface-page"> <Link href="/shop" className="rounded-full border border-brand-primary bg-surface-card px-10 py-4 font-bold uppercase tracking-widest text-brand-primary transition hover:bg-surface-page">
@@ -124,7 +124,7 @@ export default async function CategoryPage({ params }: { params: Promise<{ id: s
href={`/category/${item.id}`} href={`/category/${item.id}`}
className={`rounded-full px-5 py-2 text-xs font-bold uppercase tracking-widest transition ${ className={`rounded-full px-5 py-2 text-xs font-bold uppercase tracking-widest transition ${
isActive isActive
? 'bg-text-main text-white' ? 'bg-text-main text-surface-card'
: 'border border-line-primary/20 bg-surface-card text-muted-text hover:border-brand-primary hover:text-brand-primary' : 'border border-line-primary/20 bg-surface-card text-muted-text hover:border-brand-primary hover:text-brand-primary'
}`} }`}
> >
+2 -2
View File
@@ -75,7 +75,7 @@ export default async function CouponsPage({ params }: { params: Promise<{ lang:
<p className="mb-6 text-muted-text">กรุณากลับมาตรวจสอบโปรโมชั่นใหม่ในภายหลัง</p> <p className="mb-6 text-muted-text">กรุณากลับมาตรวจสอบโปรโมชั่นใหม่ในภายหลัง</p>
<Link <Link
href="/shop" href="/shop"
className="inline-flex rounded-full bg-brand-primary px-8 py-3 font-bold text-white transition hover:bg-brand-primary-hover" className="inline-flex rounded-full bg-brand-primary px-8 py-3 font-bold text-surface-card transition hover:bg-brand-primary-hover"
> >
ไปช้อปปิ้งกันก่อน ไปช้อปปิ้งกันก่อน
</Link> </Link>
@@ -116,7 +116,7 @@ export default async function CouponsPage({ params }: { params: Promise<{ lang:
<Link <Link
href={`/shop?coupon=${encodeURIComponent(coupon.code)}`} href={`/shop?coupon=${encodeURIComponent(coupon.code)}`}
className="flex w-full items-center justify-center gap-2 rounded-full bg-text-main py-4 font-bold text-white transition hover:bg-brand-primary" className="flex w-full items-center justify-center gap-2 rounded-full bg-text-main py-4 font-bold text-surface-card transition hover:bg-brand-primary"
> >
ช้อปพร้อมใช้คูปองเลย ช้อปพร้อมใช้คูปองเลย
<ArrowRight className="h-4 w-4" /> <ArrowRight className="h-4 w-4" />
+2 -2
View File
@@ -83,7 +83,7 @@ export default function FaqPage() {
onClick={() => setActiveCategory(category)} onClick={() => setActiveCategory(category)}
className={`flex items-center gap-2 rounded-full px-5 py-2 text-xs font-bold uppercase tracking-widest transition-all duration-300 ${ className={`flex items-center gap-2 rounded-full px-5 py-2 text-xs font-bold uppercase tracking-widest transition-all duration-300 ${
activeCategory === category activeCategory === category
? 'ui-tab-button-active bg-text-main text-white shadow-card' ? 'ui-tab-button-active bg-text-main text-surface-card shadow-card'
: 'ui-tab-button-inactive border border-line-primary/20 bg-surface-card hover:border-brand-primary hover:text-brand-primary' : 'ui-tab-button-inactive border border-line-primary/20 bg-surface-card hover:border-brand-primary hover:text-brand-primary'
}`} }`}
> >
@@ -119,7 +119,7 @@ export default function FaqPage() {
<div className="text-3xl">💬</div> <div className="text-3xl">💬</div>
<h3 className="text-xl font-bold text-text-main">Still have questions?</h3> <h3 className="text-xl font-bold text-text-main">Still have questions?</h3>
<p className="text-sm text-muted-text">Our team is here to help — usually responds within 2 hours.</p> <p className="text-sm text-muted-text">Our team is here to help — usually responds within 2 hours.</p>
<Link href="/contact" className="inline-block rounded-full bg-text-main px-8 py-3 text-xs font-bold uppercase tracking-widest text-white transition-colors duration-300 hover:bg-brand-primary"> <Link href="/contact" className="inline-block rounded-full bg-text-main px-8 py-3 text-xs font-bold uppercase tracking-widest text-surface-card transition-colors duration-300 hover:bg-brand-primary">
Contact Us Contact Us
</Link> </Link>
</div> </div>
@@ -182,7 +182,7 @@ export default async function OrderStatusPage({ params }: { params: Promise<{ id
<Link href="/track" className="rounded-full bg-surface-card px-6 py-3 font-semibold text-text-main shadow-card transition hover:text-brand-primary"> <Link href="/track" className="rounded-full bg-surface-card px-6 py-3 font-semibold text-text-main shadow-card transition hover:text-brand-primary">
ค้นหาออเดอร์อื่น ค้นหาออเดอร์อื่น
</Link> </Link>
<Link href="/shop" className="rounded-full bg-brand-primary px-6 py-3 font-semibold text-white transition hover:bg-brand-primary-hover"> <Link href="/shop" className="rounded-full bg-brand-primary px-6 py-3 font-semibold text-surface-card transition hover:bg-brand-primary-hover">
กลับไปช้อปต่อ กลับไปช้อปต่อ
</Link> </Link>
</div> </div>
+1 -1
View File
@@ -57,7 +57,7 @@ export default async function SearchPage({ searchParams, params }: { searchParam
placeholder="Search by scent or product name..." placeholder="Search by scent or product name..."
className="min-w-0 flex-1 px-5 py-3 text-sm text-text-main outline-none placeholder:text-muted-text/70" className="min-w-0 flex-1 px-5 py-3 text-sm text-text-main outline-none placeholder:text-muted-text/70"
/> />
<button className="bg-text-main px-6 py-3 text-sm font-bold uppercase tracking-widest text-white transition hover:bg-brand-primary"> <button className="bg-text-main px-6 py-3 text-sm font-bold uppercase tracking-widest text-surface-card transition hover:bg-brand-primary">
Search Search
</button> </button>
</form> </form>
+1 -1
View File
@@ -61,7 +61,7 @@ export default async function ShopPage({ searchParams, params }: { searchParams:
<div className="mx-auto max-w-7xl space-y-10 px-6 py-12"> <div className="mx-auto max-w-7xl space-y-10 px-6 py-12">
<div className="flex flex-wrap gap-3"> <div className="flex flex-wrap gap-3">
<Link className="rounded-full bg-text-main px-5 py-2 text-xs font-bold uppercase tracking-widest text-white transition hover:bg-brand-primary" href="/shop"> <Link className="rounded-full bg-text-main px-5 py-2 text-xs font-bold uppercase tracking-widest text-surface-card transition hover:bg-brand-primary" href="/shop">
All All
</Link> </Link>
{categories.map((category) => { {categories.map((category) => {
+36 -36
View File
@@ -10,7 +10,7 @@
--color-brand-soft: #D8BFD8; --color-brand-soft: #D8BFD8;
--color-surface-page: #FFF0F5; --color-surface-page: #FFF0F5;
--color-surface-nav-rest: #F9F8F5; --color-surface-nav-rest: #F9F8F5;
--color-surface-card: #FFFFFF; --color-surface-card: var(--color-surface-card);
--color-text-main: #333333; --color-text-main: #333333;
--color-muted-text: #666666; --color-muted-text: #666666;
--color-line-primary: #00B900; --color-line-primary: #00B900;
@@ -91,7 +91,7 @@
@layer components { @layer components {
.brutal-box { .brutal-box {
@apply bg-white border border-gray-100 rounded-2xl shadow-brutal transition-all duration-300; @apply bg-surface-card border border-line-primary/20 rounded-2xl shadow-brutal transition-all duration-300;
} }
.brutal-box-hover { .brutal-box-hover {
@@ -99,15 +99,15 @@
} }
.brutal-button { .brutal-button {
@apply px-8 py-4 bg-brand-primary text-white font-medium rounded-full shadow-brutal transition-all duration-300 hover:bg-brand-primary-hover hover:-translate-y-1 hover:shadow-brutal-hover; @apply px-8 py-4 bg-brand-primary text-surface-card font-medium rounded-full shadow-brutal transition-all duration-300 hover:bg-brand-primary-hover hover:-translate-y-1 hover:shadow-brutal-hover;
} }
.brutal-button-alt { .brutal-button-alt {
@apply px-8 py-4 bg-white text-brand-primary font-medium rounded-full border border-brand-primary shadow-brutal transition-all duration-300 hover:bg-surface-page hover:-translate-y-1 hover:shadow-brutal-hover; @apply px-8 py-4 bg-surface-card text-brand-primary font-medium rounded-full border border-brand-primary shadow-brutal transition-all duration-300 hover:bg-surface-page hover:-translate-y-1 hover:shadow-brutal-hover;
} }
.ui-card { .ui-card {
@apply rounded-2xl border border-gray-100 bg-surface-card shadow-card transition-all duration-300; @apply rounded-2xl border border-line-primary/20 bg-surface-card shadow-card transition-all duration-300;
} }
.ui-card-hover { .ui-card-hover {
@@ -115,15 +115,15 @@
} }
.ui-button-primary { .ui-button-primary {
@apply inline-flex items-center justify-center rounded-full bg-text-main px-6 py-3 text-xs font-bold uppercase tracking-widest text-white transition-colors hover:bg-brand-primary; @apply inline-flex items-center justify-center rounded-full bg-text-main px-6 py-3 text-xs font-bold uppercase tracking-widest text-surface-card transition-colors hover:bg-brand-primary;
} }
.ui-button-brand { .ui-button-brand {
@apply inline-flex items-center justify-center rounded-full bg-brand-primary px-6 py-3 text-xs font-bold uppercase tracking-widest text-white transition-colors hover:bg-brand-primary-hover; @apply inline-flex items-center justify-center rounded-full bg-brand-primary px-6 py-3 text-xs font-bold uppercase tracking-widest text-surface-card transition-colors hover:bg-brand-primary-hover;
} }
.ui-button-line { .ui-button-line {
@apply inline-flex items-center justify-center rounded-full bg-line-primary px-4 py-2 text-xs font-bold uppercase tracking-widest text-white shadow-sm transition-colors hover:bg-line-primary-hover; @apply inline-flex items-center justify-center rounded-full bg-line-primary px-4 py-2 text-xs font-bold uppercase tracking-widest text-surface-card shadow-sm transition-colors hover:bg-line-primary-hover;
} }
.ui-icon-button { .ui-icon-button {
@@ -135,11 +135,11 @@
} }
.ui-nav-chip { .ui-nav-chip {
@apply flex items-center gap-1.5 rounded-full border border-brand-primary/30 bg-white px-3 py-2 text-[10px] font-bold uppercase tracking-wider text-text-main transition-all hover:bg-surface-page hover:text-brand-primary; @apply flex items-center gap-1.5 rounded-full border border-brand-primary/30 bg-surface-card px-3 py-2 text-[10px] font-bold uppercase tracking-wider text-text-main transition-all hover:bg-surface-page hover:text-brand-primary;
} }
.ui-nav-panel { .ui-nav-panel {
@apply overflow-hidden rounded-xl border border-text-main/10 bg-white/95 shadow-2xl backdrop-blur-xl; @apply overflow-hidden rounded-xl border border-text-main/10 bg-surface-card shadow-2xl backdrop-blur-xl;
} }
.ui-menu-link { .ui-menu-link {
@@ -159,11 +159,11 @@
} }
.ui-muted-text { .ui-muted-text {
@apply text-gray-600; @apply text-muted-text;
} }
.ui-input-shell { .ui-input-shell {
@apply rounded-2xl border border-gray-200 bg-surface-page text-text-main outline-none transition focus:border-brand-primary focus:ring-2 focus:ring-brand-primary/20; @apply rounded-2xl border border-line-primary/20 bg-surface-page text-text-main outline-none transition focus:border-brand-primary focus:ring-2 focus:ring-brand-primary/20;
} }
.ui-footer-link { .ui-footer-link {
@@ -171,7 +171,7 @@
} }
.ui-footer-social { .ui-footer-social {
@apply flex h-9 w-9 items-center justify-center rounded-full border border-gray-200 bg-surface-page text-[10px] font-bold text-text-main transition-all duration-300 hover:border-brand-primary hover:bg-brand-primary hover:text-white; @apply flex h-9 w-9 items-center justify-center rounded-full border border-line-primary/20 bg-surface-page text-[10px] font-bold text-text-main transition-all duration-300 hover:border-brand-primary hover:bg-brand-primary hover:text-surface-card;
} }
.ui-section-band { .ui-section-band {
@@ -187,11 +187,11 @@
} }
.ui-section-subtitle { .ui-section-subtitle {
@apply text-gray-500; @apply text-muted-text;
} }
.ui-section-card { .ui-section-card {
@apply rounded-3xl bg-white shadow-card; @apply rounded-3xl bg-surface-card shadow-card;
} }
.ui-section-card-muted { .ui-section-card-muted {
@@ -215,7 +215,7 @@
justify-content: center; justify-content: center;
overflow: hidden; overflow: hidden;
background: var(--color-text-main); background: var(--color-text-main);
color: #fff; color: var(--color-surface-card);
} }
.ui-hero-overlay { .ui-hero-overlay {
@@ -236,7 +236,7 @@
} }
.ui-hero-title { .ui-hero-title {
color: #fff; color: var(--color-surface-card);
font-family: var(--font-display-locale); font-family: var(--font-display-locale);
font-size: 3rem; font-size: 3rem;
font-weight: 300; font-weight: 300;
@@ -274,7 +274,7 @@
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
padding: 1rem 2rem; padding: 1rem 2rem;
color: #fff; color: var(--color-surface-card);
font-size: 0.875rem; font-size: 0.875rem;
font-weight: 500; font-weight: 500;
letter-spacing: 0.1em; letter-spacing: 0.1em;
@@ -308,7 +308,7 @@
z-index: 10; z-index: 10;
max-width: 36rem; max-width: 36rem;
padding: 2rem; padding: 2rem;
color: #fff; color: var(--color-surface-card);
} }
.ui-banner-content > * + * { .ui-banner-content > * + * {
@@ -318,7 +318,7 @@
.ui-section-dark { .ui-section-dark {
background: var(--color-text-main); background: var(--color-text-main);
padding: 5rem 1.5rem; padding: 5rem 1.5rem;
color: #fff; color: var(--color-surface-card);
} }
.ui-section-dark-card { .ui-section-dark-card {
@@ -329,7 +329,7 @@
} }
.ui-section-dark-card-title { .ui-section-dark-card-title {
color: #fff; color: var(--color-surface-card);
font-size: 2.25rem; font-size: 2.25rem;
font-weight: 600; font-weight: 600;
line-height: 2.5rem; line-height: 2.5rem;
@@ -389,7 +389,7 @@
} }
.ui-panel { .ui-panel {
@apply rounded-3xl bg-white shadow-card; @apply rounded-3xl bg-surface-card shadow-card;
} }
.ui-panel-muted { .ui-panel-muted {
@@ -397,11 +397,11 @@
} }
.ui-panel-border { .ui-panel-border {
@apply rounded-3xl border border-gray-100 bg-white shadow-card; @apply rounded-3xl border border-line-primary/20 bg-surface-card shadow-card;
} }
.ui-panel-header { .ui-panel-header {
@apply flex items-center gap-3 border-b border-gray-100 pb-5; @apply flex items-center gap-3 border-b border-line-primary/20 pb-5;
} }
.ui-panel-title { .ui-panel-title {
@@ -409,31 +409,31 @@
} }
.ui-panel-subtitle { .ui-panel-subtitle {
@apply text-sm text-gray-500; @apply text-sm text-muted-text;
} }
.ui-form-label { .ui-form-label {
@apply text-xs font-bold uppercase tracking-[0.18em] text-gray-500; @apply text-xs font-bold uppercase tracking-[0.18em] text-muted-text;
} }
.ui-form-shell { .ui-form-shell {
@apply w-full rounded-2xl border border-gray-200 bg-surface-page px-4 py-3 text-sm text-text-main outline-none transition focus:border-brand-primary focus:ring-2 focus:ring-brand-primary/20; @apply w-full rounded-2xl border border-line-primary/20 bg-surface-page px-4 py-3 text-sm text-text-main outline-none transition focus:border-brand-primary focus:ring-2 focus:ring-brand-primary/20;
} }
.ui-form-shell-light { .ui-form-shell-light {
@apply w-full rounded-2xl border border-gray-200 bg-white px-4 py-3 text-sm text-text-main outline-none transition focus:border-brand-primary focus:ring-2 focus:ring-brand-primary/20; @apply w-full rounded-2xl border border-line-primary/20 bg-surface-card px-4 py-3 text-sm text-text-main outline-none transition focus:border-brand-primary focus:ring-2 focus:ring-brand-primary/20;
} }
.ui-form-inline-button { .ui-form-inline-button {
@apply inline-flex items-center justify-center gap-2 rounded-full bg-text-main px-6 py-4 text-sm font-bold uppercase tracking-[0.16em] text-white transition hover:bg-brand-primary disabled:cursor-not-allowed disabled:opacity-60; @apply inline-flex items-center justify-center gap-2 rounded-full bg-text-main px-6 py-4 text-sm font-bold uppercase tracking-[0.16em] text-surface-card transition hover:bg-brand-primary disabled:cursor-not-allowed disabled:opacity-60;
} }
.ui-form-inline-button-sm { .ui-form-inline-button-sm {
@apply inline-flex items-center justify-center gap-2 rounded-full bg-text-main px-5 py-2 text-sm font-semibold text-white transition hover:bg-brand-primary disabled:cursor-not-allowed disabled:opacity-60; @apply inline-flex items-center justify-center gap-2 rounded-full bg-text-main px-5 py-2 text-sm font-semibold text-surface-card transition hover:bg-brand-primary disabled:cursor-not-allowed disabled:opacity-60;
} }
.ui-form-secondary-button { .ui-form-secondary-button {
@apply rounded-full border border-gray-200 px-5 py-2 text-sm font-semibold text-gray-600 transition hover:text-brand-primary; @apply rounded-full border border-line-primary/20 px-5 py-2 text-sm font-semibold text-muted-text transition hover:text-brand-primary;
} }
.ui-form-danger-button { .ui-form-danger-button {
@@ -441,7 +441,7 @@
} }
.ui-form-checkbox { .ui-form-checkbox {
@apply h-4 w-4 rounded border-gray-300 text-brand-primary; @apply h-4 w-4 rounded border-line-primary/20 text-brand-primary;
} }
.ui-status-badge { .ui-status-badge {
@@ -523,7 +523,7 @@
} }
.ui-tab-button-inactive { .ui-tab-button-inactive {
@apply text-gray-500 hover:text-text-main; @apply text-muted-text hover:text-text-main;
} }
.ui-tab-count { .ui-tab-count {
@@ -531,7 +531,7 @@
} }
.ui-empty-panel { .ui-empty-panel {
@apply rounded-3xl bg-white px-6 py-16 text-center shadow-card; @apply rounded-3xl bg-surface-card px-6 py-16 text-center shadow-card;
} }
} }
@@ -545,11 +545,11 @@
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
@apply bg-gray-300 rounded-full; @apply bg-surface-nav-rest rounded-full;
} }
::-webkit-scrollbar-thumb:hover { ::-webkit-scrollbar-thumb:hover {
@apply bg-gray-400; @apply bg-surface-nav-rest;
} }
/* Smooth Scrolling */ /* Smooth Scrolling */
@@ -70,12 +70,12 @@ export default function AddToCartSection({ product }: Props) {
onClick={() => setSelectedVariant(index)} onClick={() => setSelectedVariant(index)}
className={`rounded-xl border px-5 py-3 text-sm font-bold uppercase tracking-widest transition ${ className={`rounded-xl border px-5 py-3 text-sm font-bold uppercase tracking-widest transition ${
selectedVariant === index selectedVariant === index
? 'border-brand-primary bg-brand-primary text-white shadow-card' ? 'border-brand-primary bg-brand-primary text-surface-card shadow-card'
: 'border-line-primary/20 bg-surface-card text-muted-text hover:border-brand-primary hover:text-brand-primary' : 'border-line-primary/20 bg-surface-card text-muted-text hover:border-brand-primary hover:text-brand-primary'
}`} }`}
> >
{variant.size} {variant.size}
<span className={`mt-1 block text-[10px] ${selectedVariant === index ? 'text-white/80' : 'text-muted-text/70'}`}> <span className={`mt-1 block text-[10px] ${selectedVariant === index ? 'text-surface-card' : 'text-muted-text/70'}`}>
{formatPrice(variant.price)} {formatPrice(variant.price)}
</span> </span>
</button> </button>
@@ -124,7 +124,7 @@ export default function AddToCartSection({ product }: Props) {
onClick={() => setSelectedVariant(index)} onClick={() => setSelectedVariant(index)}
className={`flex-shrink-0 rounded-full border px-4 py-2 text-[10px] font-bold uppercase tracking-widest transition ${ className={`flex-shrink-0 rounded-full border px-4 py-2 text-[10px] font-bold uppercase tracking-widest transition ${
selectedVariant === index selectedVariant === index
? 'border-brand-primary bg-brand-primary text-white' ? 'border-brand-primary bg-brand-primary text-surface-card'
: 'border-line-primary/20 bg-surface-card text-muted-text' : 'border-line-primary/20 bg-surface-card text-muted-text'
}`} }`}
> >
+1 -1
View File
@@ -83,7 +83,7 @@ export default function CartDrawer() {
<span className="text-brand-primary">{formatPrice(getCartTotal())}</span> <span className="text-brand-primary">{formatPrice(getCartTotal())}</span>
</div> </div>
<p className="text-center text-xs text-muted-text">{t('cart.shippingNote')}</p> <p className="text-center text-xs text-muted-text">{t('cart.shippingNote')}</p>
<Link href="/checkout" onClick={() => toggleCart(false)} className="block w-full rounded-full bg-text-main py-4 text-center text-sm font-bold uppercase tracking-widest text-white transition hover:bg-brand-primary"> <Link href="/checkout" onClick={() => toggleCart(false)} className="block w-full rounded-full bg-text-main py-4 text-center text-sm font-bold uppercase tracking-widest text-surface-card transition hover:bg-brand-primary">
{t('cart.proceed')} {t('cart.proceed')}
</Link> </Link>
</div> </div>
@@ -401,7 +401,7 @@ export default function CheckoutClient() {
<ShoppingBag className="mx-auto h-14 w-14 text-brand-primary" /> <ShoppingBag className="mx-auto h-14 w-14 text-brand-primary" />
<h2 className="mt-5 text-3xl font-semibold text-text-main">ตะกร้าสินค้าว่าง</h2> <h2 className="mt-5 text-3xl font-semibold text-text-main">ตะกร้าสินค้าว่าง</h2>
<p className="mt-3 text-muted-text">เลือกสินค้าที่คุณชอบก่อน แล้วกลับมายืนยันคำสั่งซื้อที่หน้านี้ได้เลย</p> <p className="mt-3 text-muted-text">เลือกสินค้าที่คุณชอบก่อน แล้วกลับมายืนยันคำสั่งซื้อที่หน้านี้ได้เลย</p>
<Link href="/shop" className="mt-8 inline-flex rounded-full bg-text-main px-8 py-4 text-sm font-bold uppercase tracking-[0.16em] text-white transition hover:bg-brand-primary"> <Link href="/shop" className="mt-8 inline-flex rounded-full bg-text-main px-8 py-4 text-sm font-bold uppercase tracking-[0.16em] text-surface-card transition hover:bg-brand-primary">
กลับไปเลือกสินค้า กลับไปเลือกสินค้า
</Link> </Link>
</div> </div>
@@ -642,7 +642,7 @@ export default function CheckoutClient() {
type="button" type="button"
onClick={applyCoupon} onClick={applyCoupon}
disabled={couponLoading || !couponCode.trim()} disabled={couponLoading || !couponCode.trim()}
className="rounded-2xl bg-text-main px-4 py-3 text-xs font-bold uppercase tracking-widest text-white transition hover:bg-brand-primary disabled:opacity-50" className="rounded-2xl bg-text-main px-4 py-3 text-xs font-bold uppercase tracking-widest text-surface-card transition hover:bg-brand-primary disabled:opacity-50"
> >
{couponLoading ? <Loader2 className="h-4 w-4 animate-spin" /> : 'ใช้'} {couponLoading ? <Loader2 className="h-4 w-4 animate-spin" /> : 'ใช้'}
</button> </button>
@@ -756,7 +756,7 @@ export default function CheckoutClient() {
type="submit" type="submit"
form="checkout-form" form="checkout-form"
disabled={submitting || loadingSettings} disabled={submitting || loadingSettings}
className="hidden w-full items-center justify-between rounded-full bg-text-main px-6 py-4 text-sm font-bold uppercase tracking-[0.16em] text-white transition hover:bg-brand-primary disabled:cursor-not-allowed disabled:opacity-60 lg:flex" className="hidden w-full items-center justify-between rounded-full bg-text-main px-6 py-4 text-sm font-bold uppercase tracking-[0.16em] text-surface-card transition hover:bg-brand-primary disabled:cursor-not-allowed disabled:opacity-60 lg:flex"
> >
<span className="flex items-center gap-2"> <span className="flex items-center gap-2">
{submitting && <Loader2 className="h-5 w-5 animate-spin" />} {submitting && <Loader2 className="h-5 w-5 animate-spin" />}
+3 -3
View File
@@ -231,7 +231,7 @@ export default function Navbar({ categories = [], initialMenu = [], settings = n
> >
<Heart className="h-4 w-4 transition-colors" /> <Heart className="h-4 w-4 transition-colors" />
{wishlistCount > 0 && ( {wishlistCount > 0 && (
<span className="absolute -right-1 -top-1 flex h-4 w-4 items-center justify-center rounded-full bg-brand-primary text-[9px] font-bold text-white"> <span className="absolute -right-1 -top-1 flex h-4 w-4 items-center justify-center rounded-full bg-brand-primary text-[9px] font-bold text-surface-card">
{wishlistCount} {wishlistCount}
</span> </span>
)} )}
@@ -247,7 +247,7 @@ export default function Navbar({ categories = [], initialMenu = [], settings = n
> >
<ShoppingBag className="h-4 w-4 transition-colors" /> <ShoppingBag className="h-4 w-4 transition-colors" />
{cartCount > 0 && ( {cartCount > 0 && (
<span className="absolute -right-1 -top-1 flex h-4 w-4 items-center justify-center rounded-full bg-brand-primary text-[9px] font-bold text-white"> <span className="absolute -right-1 -top-1 flex h-4 w-4 items-center justify-center rounded-full bg-brand-primary text-[9px] font-bold text-surface-card">
{cartCount} {cartCount}
</span> </span>
)} )}
@@ -353,7 +353,7 @@ export default function Navbar({ categories = [], initialMenu = [], settings = n
className="w-full border-none bg-transparent p-4 pl-0 text-lg text-text-main outline-none placeholder:text-text-main/35 md:text-xl" className="w-full border-none bg-transparent p-4 pl-0 text-lg text-text-main outline-none placeholder:text-text-main/35 md:text-xl"
autoFocus autoFocus
/> />
<button type="submit" className="shrink-0 bg-text-main px-4 text-xs font-bold uppercase tracking-widest text-white transition-colors hover:bg-brand-primary md:px-6"> <button type="submit" className="shrink-0 bg-text-main px-4 text-xs font-bold uppercase tracking-widest text-surface-card transition-colors hover:bg-brand-primary md:px-6">
Go Go
</button> </button>
</div> </div>
@@ -294,7 +294,7 @@ export default function ProfileClient() {
<button <button
type="button" type="button"
onClick={handleLineLogin} onClick={handleLineLogin}
className="mt-8 flex w-full items-center justify-center gap-3 rounded-full bg-line-primary px-6 py-4 text-sm font-bold uppercase tracking-[0.16em] text-white transition hover:bg-line-primary-hover" className="mt-8 flex w-full items-center justify-center gap-3 rounded-full bg-line-primary px-6 py-4 text-sm font-bold uppercase tracking-[0.16em] text-surface-card transition hover:bg-line-primary-hover"
> >
<Award className="h-5 w-5" /> <Award className="h-5 w-5" />
เข้าสู่ระบบผ่าน LINE เข้าสู่ระบบผ่าน LINE
@@ -435,7 +435,7 @@ export default function ProfileClient() {
สมุดที่อยู่จัดส่ง สมุดที่อยู่จัดส่ง
</h2> </h2>
{!showAddressForm && ( {!showAddressForm && (
<button type="button" onClick={() => handleStartAddress()} className="inline-flex items-center justify-center gap-2 rounded-full bg-text-main px-5 py-3 text-xs font-bold uppercase tracking-[0.16em] text-white transition hover:bg-brand-primary"> <button type="button" onClick={() => handleStartAddress()} className="inline-flex items-center justify-center gap-2 rounded-full bg-text-main px-5 py-3 text-xs font-bold uppercase tracking-[0.16em] text-surface-card transition hover:bg-brand-primary">
<Plus className="h-4 w-4" /> <Plus className="h-4 w-4" />
เพิ่มที่อยู่ใหม่ เพิ่มที่อยู่ใหม่
</button> </button>
@@ -474,7 +474,7 @@ export default function ProfileClient() {
<button type="button" onClick={resetAddressForm} className="ui-form-secondary-button"> <button type="button" onClick={resetAddressForm} className="ui-form-secondary-button">
ยกเลิก ยกเลิก
</button> </button>
<button type="submit" disabled={submittingAddress} className="inline-flex items-center gap-2 rounded-full bg-brand-primary px-5 py-2 text-sm font-semibold text-white disabled:opacity-60"> <button type="submit" disabled={submittingAddress} className="inline-flex items-center gap-2 rounded-full bg-brand-primary px-5 py-2 text-sm font-semibold text-surface-card disabled:opacity-60">
{submittingAddress && <Loader2 className="h-4 w-4 animate-spin" />} {submittingAddress && <Loader2 className="h-4 w-4 animate-spin" />}
บันทึกที่อยู่ บันทึกที่อยู่
</button> </button>
@@ -534,7 +534,7 @@ export default function ProfileClient() {
)} )}
<TextInput label="อีเมล" value={settingsForm.email} onChange={(email) => setSettingsForm((current) => ({ ...current, email }))} type="email" /> <TextInput label="อีเมล" value={settingsForm.email} onChange={(email) => setSettingsForm((current) => ({ ...current, email }))} type="email" />
<TextInput label="เบอร์โทรศัพท์" value={settingsForm.phone} onChange={(phone) => setSettingsForm((current) => ({ ...current, phone }))} type="tel" /> <TextInput label="เบอร์โทรศัพท์" value={settingsForm.phone} onChange={(phone) => setSettingsForm((current) => ({ ...current, phone }))} type="tel" />
<button type="submit" disabled={submittingSettings} className="inline-flex w-full items-center justify-center gap-2 rounded-full bg-brand-primary px-6 py-3 text-sm font-bold uppercase tracking-[0.16em] text-white disabled:opacity-60"> <button type="submit" disabled={submittingSettings} className="inline-flex w-full items-center justify-center gap-2 rounded-full bg-brand-primary px-6 py-3 text-sm font-bold uppercase tracking-[0.16em] text-surface-card disabled:opacity-60">
{submittingSettings ? <Loader2 className="h-4 w-4 animate-spin" /> : <Check className="h-4 w-4" />} {submittingSettings ? <Loader2 className="h-4 w-4 animate-spin" /> : <Check className="h-4 w-4" />}
บันทึกข้อมูลติดต่อ บันทึกข้อมูลติดต่อ
</button> </button>
@@ -598,7 +598,7 @@ function EmptyPanel({
<h3 className="text-xl font-semibold text-text-main">{title}</h3> <h3 className="text-xl font-semibold text-text-main">{title}</h3>
<p className="mx-auto mt-2 max-w-md text-sm text-muted-text">{description}</p> <p className="mx-auto mt-2 max-w-md text-sm text-muted-text">{description}</p>
{actionHref && actionText && ( {actionHref && actionText && (
<Link href={actionHref} className="mt-6 inline-flex rounded-full bg-brand-primary px-6 py-3 text-sm font-bold text-white"> <Link href={actionHref} className="mt-6 inline-flex rounded-full bg-brand-primary px-6 py-3 text-sm font-bold text-surface-card">
{actionText} {actionText}
</Link> </Link>
)} )}
@@ -174,7 +174,7 @@ export default function TrackOrderClient() {
<p className="text-xs font-bold uppercase tracking-[0.22em] text-muted-text/70">Order</p> <p className="text-xs font-bold uppercase tracking-[0.22em] text-muted-text/70">Order</p>
<p className="mt-1 font-mono text-2xl font-bold text-text-main">{orderLabel(id)}</p> <p className="mt-1 font-mono text-2xl font-bold text-text-main">{orderLabel(id)}</p>
</div> </div>
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-surface-page text-text-main transition group-hover:bg-brand-primary group-hover:text-white"> <div className="flex h-10 w-10 items-center justify-center rounded-full bg-surface-page text-text-main transition group-hover:bg-brand-primary group-hover:text-surface-card">
<ChevronRight className="h-5 w-5" /> <ChevronRight className="h-5 w-5" />
</div> </div>
</Link> </Link>
@@ -21,7 +21,7 @@ export default function WishlistClient() {
</p> </p>
<Link <Link
href="/shop" href="/shop"
className="mt-8 inline-flex rounded-full bg-brand-primary px-8 py-3 text-sm font-bold uppercase tracking-[0.18em] text-white transition hover:bg-brand-primary-hover" className="mt-8 inline-flex rounded-full bg-brand-primary px-8 py-3 text-sm font-bold uppercase tracking-[0.18em] text-surface-card transition hover:bg-brand-primary-hover"
> >
Browse Shop Browse Shop
</Link> </Link>
@@ -80,7 +80,7 @@ function AnnouncementBar({ payload, lang }: { payload: Record<string, unknown>,
return ( return (
<section <section
className={`announcement-bar absolute left-0 top-0 z-[60] w-full overflow-hidden px-4 py-3 text-center text-sm font-semibold tracking-wide ${backgroundColor ? '' : 'bg-text-main'} ${textColor ? '' : 'text-white'}`} className={`announcement-bar absolute left-0 top-0 z-[60] w-full overflow-hidden px-4 py-3 text-center text-sm font-semibold tracking-wide ${backgroundColor ? '' : 'bg-text-main'} ${textColor ? '' : 'text-surface-card'}`}
style={{ backgroundColor, color: textColor }} style={{ backgroundColor, color: textColor }}
> >
<Swiper <Swiper
@@ -125,7 +125,7 @@ function HeroSection({ payload, lang }: { payload: Record<string, unknown>, lang
<div className="relative z-10 mx-auto mt-16 w-full max-w-4xl space-y-6 px-8 text-center md:mt-0"> <div className="relative z-10 mx-auto mt-16 w-full max-w-4xl space-y-6 px-8 text-center md:mt-0">
<div className="space-y-6"> <div className="space-y-6">
{tagline && ( {tagline && (
<p className="text-xs font-semibold uppercase tracking-[0.3em] text-white drop-shadow-md md:text-sm"> <p className="text-xs font-semibold uppercase tracking-[0.3em] text-surface-card drop-shadow-md md:text-sm">
{tagline} {tagline}
</p> </p>
)} )}
@@ -209,10 +209,10 @@ function CategoriesSection({
className="absolute inset-0 h-full w-full object-cover transition duration-700 group-hover:scale-105" className="absolute inset-0 h-full w-full object-cover transition duration-700 group-hover:scale-105"
/> />
<div className="absolute inset-0 bg-gradient-to-t from-text-main/65 to-transparent" /> <div className="absolute inset-0 bg-gradient-to-t from-text-main/65 to-transparent" />
<div className="absolute bottom-5 left-5 right-5 text-white"> <div className="absolute bottom-5 left-5 right-5 text-surface-card">
<span className="block text-lg font-semibold">{name}</span> <span className="block text-lg font-semibold">{name}</span>
{category._count && ( {category._count && (
<span className="text-sm text-white/80"> <span className="text-sm text-surface-card">
{category._count.products} {productsLabel[resolvedLang] ?? productsLabel.en} {category._count.products} {productsLabel[resolvedLang] ?? productsLabel.en}
</span> </span>
)} )}
@@ -290,7 +290,7 @@ function BannerSection({ payload, lang }: { payload: Record<string, unknown>, la
<div className="ui-banner-overlay" /> <div className="ui-banner-overlay" />
<div className="ui-banner-content"> <div className="ui-banner-content">
{title && <h2 className="text-3xl font-semibold md:text-5xl">{title}</h2>} {title && <h2 className="text-3xl font-semibold md:text-5xl">{title}</h2>}
{description && <p className="text-white/90">{description}</p>} {description && <p className="text-surface-card">{description}</p>}
{buttonText && <span className="inline-flex rounded-full bg-surface-card px-6 py-3 font-semibold text-text-main">{buttonText}</span>} {buttonText && <span className="inline-flex rounded-full bg-surface-card px-6 py-3 font-semibold text-text-main">{buttonText}</span>}
</div> </div>
</div> </div>
@@ -332,8 +332,8 @@ function NewsletterSection({ payload, lang }: { payload: Record<string, unknown>
<section className="ui-section-dark"> <section className="ui-section-dark">
<div className="mx-auto grid max-w-5xl gap-8 md:grid-cols-[1fr_auto] md:items-end"> <div className="mx-auto grid max-w-5xl gap-8 md:grid-cols-[1fr_auto] md:items-end">
<div className="space-y-3"> <div className="space-y-3">
<h2 className="text-3xl font-semibold text-white md:text-4xl">{title}</h2> <h2 className="text-3xl font-semibold text-surface-card md:text-4xl">{title}</h2>
{description && <p className="max-w-2xl text-white/75">{description}</p>} {description && <p className="max-w-2xl text-surface-card">{description}</p>}
</div> </div>
<form className="flex flex-col gap-3 sm:flex-row"> <form className="flex flex-col gap-3 sm:flex-row">
<input className="ui-form-shell min-w-0 rounded-full" placeholder={placeholder} type="email" /> <input className="ui-form-shell min-w-0 rounded-full" placeholder={placeholder} type="email" />
@@ -381,7 +381,7 @@ function EditorialTileSection({ payload, lang }: { payload: Record<string, unkno
<div className="h-px w-14 bg-brand-primary" /> <div className="h-px w-14 bg-brand-primary" />
{description && <p className="whitespace-pre-line text-base leading-relaxed text-muted-text md:text-lg" style={{ color: textColor }}>{description}</p>} {description && <p className="whitespace-pre-line text-base leading-relaxed text-muted-text md:text-lg" style={{ color: textColor }}>{description}</p>}
{buttonText && buttonLink && ( {buttonText && buttonLink && (
<Link href={buttonLink} className="ui-section-link inline-flex rounded-full border border-current px-8 py-3 text-xs font-bold uppercase tracking-[0.22em] transition hover:bg-brand-primary hover:text-white"> <Link href={buttonLink} className="ui-section-link inline-flex rounded-full border border-current px-8 py-3 text-xs font-bold uppercase tracking-[0.22em] transition hover:bg-brand-primary hover:text-surface-card">
{buttonText} {buttonText}
</Link> </Link>
)} )}
@@ -403,7 +403,7 @@ function EditorialCarouselSection({ payload, lang }: { payload: Record<string, u
<div className="mx-auto max-w-7xl space-y-12"> <div className="mx-auto max-w-7xl space-y-12">
{title && ( {title && (
<div className="mx-auto max-w-3xl space-y-4 text-center"> <div className="mx-auto max-w-3xl space-y-4 text-center">
<h2 className="text-4xl font-semibold text-white md:text-5xl">{renderAccentTitle(title, 'ui-accent-text not-italic')}</h2> <h2 className="text-4xl font-semibold text-surface-card md:text-5xl">{renderAccentTitle(title, 'ui-accent-text not-italic')}</h2>
<div className="mx-auto h-px w-16 bg-brand-accent" /> <div className="mx-auto h-px w-16 bg-brand-accent" />
</div> </div>
)} )}
@@ -485,9 +485,9 @@ function HeroArticleSection({ payload, lang }: { payload: Record<string, unknown
<div className="relative z-10 mx-auto max-w-4xl space-y-6"> <div className="relative z-10 mx-auto max-w-4xl space-y-6">
{category && <p className="text-xs font-bold uppercase tracking-[0.28em] text-brand-accent">{category}</p>} {category && <p className="text-xs font-bold uppercase tracking-[0.28em] text-brand-accent">{category}</p>}
<h1 className="ui-hero-title">{title}</h1> <h1 className="ui-hero-title">{title}</h1>
{subtitle && <p className="mx-auto max-w-2xl text-lg text-white/85 md:text-xl">{subtitle}</p>} {subtitle && <p className="mx-auto max-w-2xl text-lg text-surface-card md:text-xl">{subtitle}</p>}
{(author || date) && ( {(author || date) && (
<p className="text-xs font-bold uppercase tracking-[0.22em] text-white/70"> <p className="text-xs font-bold uppercase tracking-[0.22em] text-surface-card">
{[author && `${authorPrefix[resolvedLang] ?? authorPrefix.en} ${author}`, date].filter(Boolean).join(' / ')} {[author && `${authorPrefix[resolvedLang] ?? authorPrefix.en} ${author}`, date].filter(Boolean).join(' / ')}
</p> </p>
)} )}
@@ -213,7 +213,7 @@ export function MobileDrawer({
<Link <Link
href="/shop" href="/shop"
onClick={onClose} onClick={onClose}
className="block w-full rounded-xl bg-text-main py-3.5 text-center text-xs font-bold uppercase tracking-widest text-white shadow-sm transition-colors hover:bg-brand-primary" className="block w-full rounded-xl bg-text-main py-3.5 text-center text-xs font-bold uppercase tracking-widest text-surface-card shadow-sm transition-colors hover:bg-brand-primary"
> >
Shop Now Shop Now
</Link> </Link>