RTSDA-Website/astro-church-website/src/pages/sermons.astro
Benjamin Slingo b1796b0475 Fix light mode visibility and sermon page filtering
- Implement dual theme system with separate Tailwind configs for light/dark modes
- Add dynamic stylesheet switching based on system preference
- Fix light mode text visibility by using darker colors on light backgrounds
- Resolve sermon page bug where all content loaded on initial render
- Add build scripts for theme compilation
- Update recurring event type formatting consistency
2025-08-23 14:27:42 -04:00

264 lines
10 KiB
Plaintext

---
import MainLayout from '../layouts/MainLayout.astro';
import { getChurchName, fetchSermonsJson, fetchLivestreamArchiveJson } from '../lib/bindings.js';
let churchName = 'Church';
let sermons = [];
let livestreams = [];
try {
churchName = getChurchName();
// Get regular sermons
const sermonsJson = fetchSermonsJson();
const parsedSermons = JSON.parse(sermonsJson);
sermons = Array.isArray(parsedSermons) ? parsedSermons : (parsedSermons.items || []);
// Get livestream archive
const livestreamsJson = fetchLivestreamArchiveJson();
const parsedLivestreams = JSON.parse(livestreamsJson);
livestreams = Array.isArray(parsedLivestreams) ? parsedLivestreams : (parsedLivestreams.items || []);
} catch (e) {
console.error('Failed to load sermons:', e);
}
// Combine all content for display
const allContent = [...sermons, ...livestreams];
---
<MainLayout title={`Sermons - ${churchName}`} description="Listen to our recent sermons and be inspired by God's Word">
<!-- Sermons Hero -->
<section class="py-16 bg-heavenly-gradient text-white">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h1 class="text-4xl lg:text-6xl font-bold mb-6">Sermons</h1>
<p class="text-xl text-blue-100 max-w-2xl mx-auto">
Be inspired and encouraged through messages from God's Word
</p>
</div>
</section>
<!-- Sermons Grid -->
<section class="py-16 bg-white dark:bg-gray-900">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<!-- Filter Tabs -->
<div class="mb-12">
<div class="flex flex-wrap justify-center gap-2">
<button class="filter-btn active" data-filter="sermons">
<i data-lucide="mic" class="w-4 h-4 mr-2"></i>
Sermons
</button>
<button class="filter-btn" data-filter="livestream">
<i data-lucide="video" class="w-4 h-4 mr-2"></i>
LiveStream Archive
</button>
<button class="filter-btn" data-filter="recent">
<i data-lucide="clock" class="w-4 h-4 mr-2"></i>
Recent Messages
</button>
</div>
</div>
{allContent.length > 0 ? (
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-8" id="sermons-grid">
{allContent.map(item => {
const isLivestream = livestreams.includes(item);
const category = isLivestream ? 'livestream' : 'sermon';
// Hide non-sermon items by default since "Sermons" tab is active
const hideByDefault = category !== 'sermon';
return (
<div
class={`sermon-card bg-gradient-to-br from-gray-50 to-blue-50 dark:from-gray-800 dark:to-gray-700 rounded-2xl p-6 hover:shadow-lg transition-all duration-300 hover:-translate-y-1 group${hideByDefault ? ' hidden' : ''}`}
data-animate
data-category={category}
data-speaker={item.speaker}
data-date={item.date}
>
<div class="w-16 h-16 bg-gradient-to-br from-primary-500 to-primary-600 rounded-2xl flex items-center justify-center mb-4 group-hover:scale-110 transition-transform">
<i data-lucide="play" class="w-8 h-8 text-white"></i>
</div>
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-3 line-clamp-2">{item.title}</h3>
<div class="space-y-2 mb-4">
{item.speaker && (
<div class="flex items-center space-x-2 text-gray-600 dark:text-gray-300">
<i data-lucide="user" class="w-4 h-4"></i>
<span class="text-sm">{item.speaker}</span>
</div>
)}
{item.date && (
<div class="flex items-center space-x-2 text-gray-600 dark:text-gray-300">
<i data-lucide="calendar" class="w-4 h-4"></i>
<span class="text-sm">{item.date}</span>
</div>
)}
{item.duration && (
<div class="flex items-center space-x-2 text-gray-600 dark:text-gray-300">
<i data-lucide="clock" class="w-4 h-4"></i>
<span class="text-sm">{item.duration}</span>
</div>
)}
{livestreams.includes(item) && (
<div class="flex items-center space-x-2 text-purple-600 dark:text-purple-400">
<i data-lucide="radio" class="w-4 h-4"></i>
<span class="text-sm font-medium">LiveStream Archive</span>
</div>
)}
</div>
{item.description && (
<p class="text-gray-600 dark:text-gray-300 mb-4 leading-relaxed text-sm line-clamp-3">{item.description}</p>
)}
<div class="flex space-x-2">
{item.videoUrl && (
<a href={item.videoUrl} target="_blank" rel="noopener" class="flex-1 inline-flex items-center justify-center space-x-2 bg-primary-600 text-white px-4 py-2 rounded-xl font-medium hover:bg-primary-700 transition-colors text-sm">
<i data-lucide="play" class="w-4 h-4"></i>
<span>Watch</span>
</a>
)}
{item.audioUrl && (
<a href={item.audioUrl} target="_blank" rel="noopener" class="flex-1 inline-flex items-center justify-center space-x-2 bg-purple-600 text-white px-4 py-2 rounded-xl font-medium hover:bg-purple-700 transition-colors text-sm">
<i data-lucide="headphones" class="w-4 h-4"></i>
<span>Listen</span>
</a>
)}
{item.downloadUrl && (
<a href={item.downloadUrl} download class="inline-flex items-center justify-center p-2 bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-300 rounded-xl hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors">
<i data-lucide="download" class="w-4 h-4"></i>
</a>
)}
</div>
</div>
)
})}
</div>
) : (
<div class="text-center py-16">
<div class="w-24 h-24 bg-gray-100 dark:bg-gray-800 rounded-2xl flex items-center justify-center mx-auto mb-6">
<i data-lucide="headphones" class="w-12 h-12 text-gray-400"></i>
</div>
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-4">No Sermons Available</h3>
<p class="text-gray-600 dark:text-gray-300 mb-8">
Check back soon for new messages from God's Word
</p>
<a href="/live" class="inline-flex items-center space-x-2 bg-primary-600 text-white px-8 py-4 rounded-2xl font-semibold hover:bg-primary-700 transition-colors">
<i data-lucide="video" class="w-5 h-5"></i>
<span>Watch Live Services</span>
</a>
</div>
)}
</div>
</section>
<!-- Call to Action -->
<section class="py-16 bg-gray-50 dark:bg-gray-800">
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h2 class="text-3xl font-bold text-gray-900 dark:text-white mb-6">Stay Connected</h2>
<p class="text-xl text-gray-600 dark:text-gray-300 mb-8">
Don't miss our weekly messages. Join us for live services or subscribe to our updates.
</p>
<div class="flex flex-col sm:flex-row gap-4 justify-center">
<a href="/live" class="inline-flex items-center space-x-2 bg-primary-600 text-white px-8 py-4 rounded-2xl font-semibold hover:bg-primary-700 transition-colors">
<i data-lucide="video" class="w-5 h-5"></i>
<span>Watch Live</span>
</a>
<a href="/events" class="inline-flex items-center space-x-2 border-2 border-primary-600 text-primary-600 dark:text-primary-400 px-8 py-4 rounded-2xl font-semibold hover:bg-primary-600 hover:text-white transition-colors">
<i data-lucide="calendar" class="w-5 h-5"></i>
<span>View Events</span>
</a>
</div>
</div>
</section>
</MainLayout>
<style>
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.line-clamp-3 {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.filter-btn {
@apply px-6 py-3 rounded-xl font-medium transition-all duration-200 border-2;
@apply border-gray-200 dark:border-gray-700 text-gray-600 dark:text-gray-300;
@apply hover:border-primary-500 hover:text-primary-600 dark:hover:text-primary-400;
}
.filter-btn.active {
@apply bg-primary-600 border-primary-600 text-white;
@apply hover:bg-primary-700 hover:border-primary-700;
}
.sermon-card.hidden {
display: none;
}
.sermon-card {
animation: fadeIn 0.3s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
<script>
document.addEventListener('DOMContentLoaded', () => {
const filterButtons = document.querySelectorAll('.filter-btn');
const sermonCards = document.querySelectorAll('.sermon-card');
filterButtons.forEach(button => {
button.addEventListener('click', () => {
// Update active button
filterButtons.forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
const filter = button.dataset.filter;
// Filter sermon cards
sermonCards.forEach(card => {
const category = card.dataset.category;
const date = new Date(card.dataset.date);
const isRecent = (Date.now() - date.getTime()) < (90 * 24 * 60 * 60 * 1000); // 90 days
let shouldShow = false;
if (filter === 'sermons') {
shouldShow = category === 'sermon';
} else if (filter === 'livestream') {
shouldShow = category === 'livestream';
} else if (filter === 'recent') {
shouldShow = isRecent;
}
if (shouldShow) {
card.classList.remove('hidden');
} else {
card.classList.add('hidden');
}
});
});
});
});
</script>