Files
dealplustech-astro/src/layouts/BaseLayout.astro
2026-04-02 22:28:58 +07:00

410 lines
18 KiB
Plaintext

---
import '../styles/global.css';
interface Props {
title: string;
description?: string;
image?: string;
canonicalURL?: string;
}
const { title, description = 'ผู้เชี่ยวชาญระบบน้ำ ให้คำแนะนำและจำหน่ายท่อ PPR ตราช้าง ท่อพีพีอาร์ ท่อ PPR ท่อ HDPE Thai PPR รั้วตาข่าย คุณภาพสูง ราคาถูก', image = '/images/logo/dealplustech-logo.png', canonicalURL = Astro.url } = Astro.props;
const siteName = 'Deal Plus Tech';
const siteUrl = 'https://dealplustech.co.th';
---
<!doctype html>
<html lang="th">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content={Astro.generator} />
<!-- SEO Meta Tags -->
<title>{title} | {siteName}</title>
<meta name="title" content={`${title} | ${siteName}`} />
<meta name="description" content={description} />
<meta name="keywords" content="ท่อ PPR, ท่อ HDPE, ท่อ PVC, ระบบน้ำ, รั้วตาข่าย, อุปกรณ์ท่อ, วาล์ว, ปั๊มน้ำ" />
<link rel="canonical" href={canonicalURL} />
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website" />
<meta property="og:url" content={canonicalURL} />
<meta property="og:title" content={`${title} | ${siteName}`} />
<meta property="og:description" content={description} />
<meta property="og:image" content={new URL(image, siteUrl)} />
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content={canonicalURL} />
<meta property="twitter:title" content={`${title} | ${siteName}`} />
<meta property="twitter:description" content={description} />
<meta property="twitter:image" content={new URL(image, siteUrl)} />
<!-- Structured Data - Organization -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Deal Plus Tech",
"alternateName": "ดีล พลัส เทค",
"url": "https://dealplustech.co.th",
"logo": "https://dealplustech.co.th/images/logo/dealplustech-logo.png",
"description": "ผู้เชี่ยวชาญระบบน้ำ ให้คำแนะนำและจำหน่ายท่อ PPR ตราช้าง ท่อพีพีอาร์ ท่อ HDPE รั้วตาข่าย คุณภาพสูง ราคาถูก",
"address": {
"@type": "PostalAddress",
"streetAddress": "9/69 ซอยนครลุง 17 แขวงบางไผ่ เขตบางแค",
"addressLocality": "กรุงเทพมหานคร",
"postalCode": "10160",
"addressCountry": "TH"
},
"telephone": "+6690-555-1415",
"email": "dealplustech@gmail.com",
"sameAs": [
"https://www.facebook.com/Dealplustech/"
]
}
</script>
<!-- Structured Data - WebSite with Search -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "Deal Plus Tech",
"url": "https://dealplustech.co.th",
"potentialAction": {
"@type": "SearchAction",
"target": "https://dealplustech.co.th/all-products?q={search_term_string}",
"query-input": "required name=search_term_string"
}
}
</script>
<!-- Structured Data - LocalBusiness -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "Deal Plus Tech",
"image": "https://dealplustech.co.th/images/logo/dealplustech-logo.png",
"priceRange": "฿฿",
"address": {
"@type": "PostalAddress",
"streetAddress": "9/69 ซอยนครลุง 17 แขวงบางไผ่ เขตบางแค",
"addressLocality": "กรุงเทพมหานคร",
"postalCode": "10160",
"addressCountry": "TH"
},
"telephone": "+6690-555-1415",
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
"opens": "08:30",
"closes": "17:30"
}
]
}
</script>
<!-- Favicon -->
<link rel="icon" type="image/png" href="/favicon.ico" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<!-- Preconnect to Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
</head>
<body class="flex flex-col min-h-screen">
<slot name="header" />
<main class="flex-grow">
<slot />
</main>
<slot name="footer" />
<!-- Cookie Consent Banner -->
<div id="cookie-consent" class="fixed bottom-0 left-0 right-0 z-50 bg-secondary-900 text-white p-4 sm:p-6 pb-[env(safe-area-inset-bottom)] shadow-2xl transform translate-y-full transition-transform duration-500">
<div class="container-custom max-w-6xl">
<div class="flex flex-col md:flex-row items-center justify-between gap-6">
<div class="flex-1">
<h3 class="text-xl font-bold mb-2">เราใช้คุกกี้เพื่อประสบการณ์ที่ดีที่สุด</h3>
<p class="text-secondary-300 text-lg">
เว็บไซต์ของเราใช้คุกกี้เพื่อเพิ่มประสิทธิภาพการใช้งาน วิเคราะห์การจราจร และแสดงเนื้อหาที่เหมาะสม
คุณสามารถยอมรับหรือปฏิเสธคุกกี้บางประเภทได้
</p>
</div>
<div class="flex flex-wrap gap-4">
<button id="consent-reject" class="btn-secondary px-6 py-3 text-sm">
ปฏิเสธทั้งหมด
</button>
<button id="consent-accept" class="btn-primary px-6 py-3 text-sm">
ยอมรับทั้งหมด
</button>
</div>
</div>
</div>
</div>
<!-- Consent Preferences Modal -->
<div id="consent-modal" class="fixed inset-0 z-50 bg-black/50 backdrop-blur-sm hidden">
<div class="flex items-center justify-center min-h-screen p-4">
<div class="bg-white rounded-2xl shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-y-auto">
<div class="p-6 md:p-8">
<div class="flex justify-between items-center mb-6">
<h2 class="text-2xl font-bold text-secondary-900">การตั้งค่าคุกกี้</h2>
<button id="modal-close" class="text-secondary-500 hover:text-secondary-700 text-2xl">&times;</button>
</div>
<div class="space-y-6">
<div class="border border-secondary-200 rounded-xl p-4">
<div class="flex justify-between items-start mb-2">
<div>
<h3 class="font-semibold text-lg text-secondary-900">คุกกี้ที่จำเป็น</h3>
<p class="text-secondary-600 text-lg">จำเป็นสำหรับการทำงานของเว็บไซต์ ไม่สามารถปิดได้</p>
</div>
<label class="relative inline-flex items-center cursor-not-allowed">
<input type="checkbox" checked disabled class="sr-only peer" />
<div class="w-11 h-6 bg-primary-500 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-primary-100 rounded-full peer"></div>
</label>
</div>
</div>
<div class="border border-secondary-200 rounded-xl p-4">
<div class="flex justify-between items-start mb-2">
<div>
<h3 class="font-semibold text-lg text-secondary-900">คุกกี้ประสิทธิภาพ</h3>
<p class="text-secondary-600 text-lg">ช่วยเราวิเคราะห์การใช้งานเว็บไซต์</p>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" id="consent-analytics" class="sr-only peer" />
<div class="w-11 h-6 bg-secondary-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-primary-100 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-primary-500"></div>
</label>
</div>
</div>
<div class="border border-secondary-200 rounded-xl p-4">
<div class="flex justify-between items-start mb-2">
<div>
<h3 class="font-semibold text-lg text-secondary-900">คุกกี้การตลาด</h3>
<p class="text-secondary-600 text-lg">ใช้สำหรับแสดงโฆษณาที่เกี่ยวข้อง</p>
</div>
<label class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" id="consent-marketing" class="sr-only peer" />
<div class="w-11 h-6 bg-secondary-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-primary-100 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-primary-500"></div>
</label>
</div>
</div>
</div>
<div class="flex gap-4 mt-8">
<button id="consent-save" class="btn-primary flex-1 py-3">
บันทึกการตั้งค่า
</button>
</div>
<p class="text-secondary-500 text-sm mt-6 text-center">
คุณสามารถเปลี่ยนการตั้งค่าคุกกี้ได้ตลอดเวลา การใช้บริการนี้ถือว่าคุณยอมรับ
<a href="/privacy-policy" class="text-primary-500 hover:underline">นโยบายความเป็นส่วนตัว</a> ของเรา
</p>
</div>
</div>
</div>
</div>
<!-- Umami Analytics (conditionally loaded) -->
<script is:inline>
const consent = JSON.parse(localStorage.getItem('consent-preferences') || '{}');
if (consent.analytics) {
const script = document.createElement('script');
script.defer = true;
script.src = 'https://analytics.dealplustech.co.th/script.js';
script.setAttribute('data-website-id', import.meta.env.UMAMI_WEBSITE_ID || '');
document.head.appendChild(script);
}
</script>
<!-- Consent Management Script -->
<script>
(function() {
const consent = JSON.parse(localStorage.getItem('consent-preferences') || '{}');
const hasConsent = consent.timestamp !== undefined;
if (!hasConsent) {
setTimeout(() => {
document.getElementById('cookie-consent').classList.remove('translate-y-full');
}, 1000);
}
document.getElementById('consent-accept')?.addEventListener('click', () => {
saveConsent({ essential: true, analytics: true, marketing: true });
});
document.getElementById('consent-reject')?.addEventListener('click', () => {
saveConsent({ essential: true, analytics: false, marketing: false });
});
document.getElementById('modal-close')?.addEventListener('click', () => {
document.getElementById('consent-modal').classList.add('hidden');
});
document.getElementById('consent-save')?.addEventListener('click', () => {
const analytics = document.getElementById('consent-analytics')?.checked || false;
const marketing = document.getElementById('consent-marketing')?.checked || false;
saveConsent({ essential: true, analytics, marketing });
});
function saveConsent(preferences) {
// Get or generate sessionId
let sessionId = localStorage.getItem('consent-session-id');
if (!sessionId) {
sessionId = crypto.randomUUID();
localStorage.setItem('consent-session-id', sessionId);
}
const consentData = {
...preferences,
sessionId,
timestamp: Date.now(),
policyVersion: '1.0',
userAgent: navigator.userAgent
};
localStorage.setItem('consent-preferences', JSON.stringify(consentData));
fetch('/api/consent', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(consentData)
}).catch(console.error);
document.getElementById('cookie-consent').classList.add('translate-y-full');
document.getElementById('consent-modal').classList.add('hidden');
if (preferences.analytics && !window.umami) {
const script = document.createElement('script');
script.defer = true;
script.src = 'https://analytics.dealplustech.co.th/script.js';
script.setAttribute('data-website-id', import.meta.env.UMAMI_WEBSITE_ID || '');
document.head.appendChild(script);
}
}
window.openConsentPreferences = function() {
document.getElementById('consent-modal').classList.remove('hidden');
};
})();
</script>
<!-- Enhanced Scroll Animation Initialization -->
<script>
// Intersection Observer for scroll animations
(function() {
// Check for reduced motion preference
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (prefersReducedMotion) {
// If user prefers reduced motion, show all elements immediately
document.querySelectorAll('.stagger-item, .stagger-from-left, .stagger-from-right, .stagger-scale, .fade-reveal, .img-reveal, .animate-on-scroll').forEach(el => {
el.classList.add('revealed', 'visible');
});
return;
}
const observerOptions = {
root: null,
rootMargin: '0px 0px -50px 0px',
threshold: 0.1
};
const animationObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('revealed', 'visible');
// Unobserve after animation to save resources
animationObserver.unobserve(entry.target);
}
});
}, observerOptions);
// Observe all animated elements
const animatedSelectors = [
'.stagger-item',
'.stagger-from-left',
'.stagger-from-right',
'.stagger-scale',
'.fade-reveal',
'.img-reveal',
'.animate-on-scroll'
];
animatedSelectors.forEach(selector => {
document.querySelectorAll(selector).forEach(el => {
animationObserver.observe(el);
});
});
// Image lazy load with skeleton
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
const src = img.dataset.src;
if (src) {
img.src = src;
img.removeAttribute('data-src');
img.onload = () => {
img.classList.remove('skeleton-image');
img.classList.add('loaded');
};
img.onerror = () => {
img.classList.remove('skeleton-image');
img.classList.add('error');
};
}
imageObserver.unobserve(img);
}
});
}, { rootMargin: '50px' });
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});
// Stagger animation for children within containers
document.querySelectorAll('.stagger-container').forEach(container => {
const children = container.querySelectorAll('.stagger-item');
children.forEach((child, index) => {
if (!child.hasAttribute('data-delay')) {
child.setAttribute('data-delay', String((index % 8) + 1));
}
});
});
})();
// Smooth scroll for anchor links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href');
if (targetId && targetId !== '#') {
const target = document.querySelector(targetId);
if (target) {
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
}
});
});
</script>
</body>
</html>