the rest
This commit is contained in:
176
internal/tmpl/home.tmpl
Normal file
176
internal/tmpl/home.tmpl
Normal file
@@ -0,0 +1,176 @@
|
||||
{{define "home.tmpl"}}
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Home - Decor By Hannahs</title>
|
||||
<link rel="stylesheet" href="/static/css/styles.css">
|
||||
<script>
|
||||
(function() {
|
||||
const savedTheme = localStorage.getItem('theme') || 'light';
|
||||
document.documentElement.setAttribute('data-theme', savedTheme);
|
||||
})();
|
||||
</script>
|
||||
<script src="/static/js/alpine.js" defer></script>
|
||||
<script src="/static/htmx/htmx.min.js" defer></script>
|
||||
<script src="/static/js/drawer.js" defer></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{{template "header" .}}
|
||||
|
||||
<main>
|
||||
<div class="hero" style="position: relative;">
|
||||
<img src="/assets/party-icons/penguin-wearing-party-hat.png" alt="Party penguin" style="position: absolute; top: 20px; right: 10%; width: 100px; height: 100px; opacity: 0.8; animation: float 3s ease-in-out infinite;">
|
||||
<img src="/assets/party-icons/jester-hat.png" alt="Jester hat" style="position: absolute; bottom: 20px; left: 10%; width: 80px; height: 80px; opacity: 0.8; animation: float 4s ease-in-out infinite; animation-delay: 1s;">
|
||||
<h1>Welcome to Decor By Hannah's</h1>
|
||||
<p>We take care of all the headache for your party decorations so you don't have to</p>
|
||||
<div style="display: flex; gap: 1rem; justify-content: center; margin-top: 2rem; flex-wrap: wrap;">
|
||||
<a href="/catalog" class="btn btn-primary">Browse Services</a>
|
||||
<a href="/booking" class="btn btn-outline">Book Now</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0px); }
|
||||
50% { transform: translateY(-20px); }
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="grid grid-cols-3" style="margin-top: 4rem;">
|
||||
<div class="card" style="position: relative; overflow: visible;">
|
||||
<img src="/assets/party-icons/party-hat.png" alt="Party hat" style="position: absolute; top: -50px; left: -45px; width: 80px; height: 80px; transform: rotate(-25deg); z-index: 10;"> <div class="card-header">
|
||||
<h3 class="card-title">Professional Setup</h3>
|
||||
<p class="card-description">Expert decoration services</p>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<p>Our experienced team handles everything from setup to teardown, ensuring your event looks perfect.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="position: relative; overflow: visible;">
|
||||
<img src="/assets/party-icons/birthday-cake.png" alt="Birthday cake" style="position: absolute; bottom: -15px; left: -15px; width: 70px; height: 70px; z-index: 10;">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Custom Themes</h3>
|
||||
<p class="card-description">Tailored to your vision</p>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<p>Choose from our curated themes or work with us to create something uniquely yours.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="position: relative; overflow: visible;">
|
||||
<img src="/assets/party-icons/happy-sun-wearing-party-hat.png" alt="Happy sun" style="position: absolute; top: -25px; right: -10px; width: 90px; height: 90px; z-index: 10;">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Stress-Free Planning</h3>
|
||||
<p class="card-description">We handle the details</p>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<p>Focus on enjoying your event while we take care of all the decoration logistics.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ if .Photos }}
|
||||
<div style="margin-top: 4rem;">
|
||||
<h2 style="font-size: 2rem; font-weight: 700; text-align: center; margin-bottom: 2rem;">See Our Work</h2>
|
||||
<div class="carousel" id="carousel">
|
||||
<div class="carousel-container">
|
||||
<div class="carousel-track" id="carouselTrack">
|
||||
{{ range .Photos }}
|
||||
<div class="carousel-slide">
|
||||
<img src="{{ .URL }}" alt="{{ if .Caption }}{{ .Caption }}{{ else }}Gallery photo{{ end }}" style="width: 100%; height: 500px; object-fit: cover; border-radius: var(--radius);">
|
||||
{{ if .Caption }}
|
||||
<p style="text-align: center; margin-top: 1rem; color: hsl(var(--muted-foreground));">{{ .Caption }}</p>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
<button class="carousel-btn carousel-btn-prev" id="prevBtn" aria-label="Previous slide">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"></polyline></svg>
|
||||
</button>
|
||||
<button class="carousel-btn carousel-btn-next" id="nextBtn" aria-label="Next slide">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>
|
||||
</button>
|
||||
<div class="carousel-indicators" id="indicators"></div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</main>
|
||||
|
||||
{{template "footer"}}
|
||||
|
||||
{{template "theme-script"}}
|
||||
<script>
|
||||
(function() {
|
||||
const track = document.getElementById('carouselTrack');
|
||||
if (!track) return;
|
||||
|
||||
const prevBtn = document.getElementById('prevBtn');
|
||||
const nextBtn = document.getElementById('nextBtn');
|
||||
const indicators = document.getElementById('indicators');
|
||||
const slides = track.querySelectorAll('.carousel-slide');
|
||||
const totalSlides = slides.length;
|
||||
let currentSlide = 0;
|
||||
let autoplayInterval;
|
||||
|
||||
if (totalSlides === 0) return;
|
||||
|
||||
for (let i = 0; i < totalSlides; i++) {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'carousel-indicator';
|
||||
btn.setAttribute('aria-label', `Go to slide ${i + 1}`);
|
||||
btn.addEventListener('click', () => goToSlide(i));
|
||||
indicators.appendChild(btn);
|
||||
}
|
||||
|
||||
function updateCarousel() {
|
||||
track.style.transform = `translateX(-${currentSlide * 100}%)`;
|
||||
const indicatorBtns = indicators.querySelectorAll('.carousel-indicator');
|
||||
indicatorBtns.forEach((btn, i) => {
|
||||
btn.classList.toggle('active', i === currentSlide);
|
||||
});
|
||||
}
|
||||
|
||||
function goToSlide(index) {
|
||||
currentSlide = index;
|
||||
updateCarousel();
|
||||
resetAutoplay();
|
||||
}
|
||||
|
||||
function nextSlide() {
|
||||
currentSlide = (currentSlide + 1) % totalSlides;
|
||||
updateCarousel();
|
||||
}
|
||||
|
||||
function prevSlide() {
|
||||
currentSlide = (currentSlide - 1 + totalSlides) % totalSlides;
|
||||
updateCarousel();
|
||||
resetAutoplay();
|
||||
}
|
||||
|
||||
function startAutoplay() {
|
||||
autoplayInterval = setInterval(nextSlide, 5000);
|
||||
}
|
||||
|
||||
function resetAutoplay() {
|
||||
clearInterval(autoplayInterval);
|
||||
startAutoplay();
|
||||
}
|
||||
|
||||
prevBtn.addEventListener('click', prevSlide);
|
||||
nextBtn.addEventListener('click', () => {
|
||||
nextSlide();
|
||||
resetAutoplay();
|
||||
});
|
||||
|
||||
updateCarousel();
|
||||
startAutoplay();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
Reference in New Issue
Block a user