Initial commit: site code, layouts, content (images added separately)
Fixes duplicate placeholder cover image on the 3 newest blog posts, broken aspect-ratio classes on the albums listing page, and a non-responsive fixed sidebar on the chat page.
This commit is contained in:
159
layouts/testimonials/single.html
Normal file
159
layouts/testimonials/single.html
Normal file
@@ -0,0 +1,159 @@
|
||||
{{ define "main" }}
|
||||
<div class="bg-gray-900 min-h-screen py-16 px-4 sm:px-6 lg:px-8" x-data="testimonialsPage()" x-init="initTestimonials()">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<div class="text-center mb-12">
|
||||
<h1 class="text-4xl font-extrabold text-gray-100 tracking-tight sm:text-5xl mb-4">Member Testimonials</h1>
|
||||
<p class="text-xl text-gray-300 max-w-2xl mx-auto">
|
||||
Real stories from growers who have transformed their gardens using the sterile hydroponic method.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Paywall Message -->
|
||||
<div class="paywall-message bg-gray-800 rounded-lg p-8 border border-gray-700 text-center mb-8" style="display: none;">
|
||||
<h2 class="text-2xl font-bold text-gray-100 mb-4">Members Only Content</h2>
|
||||
<p class="text-gray-300 mb-6">
|
||||
Testimonials are available exclusively to members. Sign up to read success stories and share your own experience.
|
||||
</p>
|
||||
<a href="/membership/" class="inline-flex items-center px-6 py-3 bg-primary hover:bg-emerald-700 text-white font-semibold rounded-lg transition-colors">
|
||||
Become a Member
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Testimonials Content -->
|
||||
<div class="paywall-content">
|
||||
<!-- Submit Testimonial Form (Members Only) -->
|
||||
<div class="membership-only bg-gray-800 rounded-lg p-8 mb-8 border border-gray-700" style="display: none;">
|
||||
<h2 class="text-2xl font-bold text-gray-100 mb-6">Share Your Story</h2>
|
||||
<form @submit.prevent="submitTestimonial()" class="space-y-6">
|
||||
<div>
|
||||
<label for="author-name" class="block text-sm font-medium text-gray-300 mb-2">Your Name</label>
|
||||
<input type="text" id="author-name" x-model="authorName" required
|
||||
class="w-full px-4 py-3 bg-gray-900 border border-gray-700 rounded-lg text-gray-100 focus:ring-2 focus:ring-primary focus:border-transparent">
|
||||
</div>
|
||||
<div>
|
||||
<label for="testimonial-content" class="block text-sm font-medium text-gray-300 mb-2">Your Testimonial</label>
|
||||
<textarea id="testimonial-content" x-model="testimonialContent" required rows="6"
|
||||
class="w-full px-4 py-3 bg-gray-900 border border-gray-700 rounded-lg text-gray-100 focus:ring-2 focus:ring-primary focus:border-transparent"></textarea>
|
||||
</div>
|
||||
<div x-show="submitError" class="bg-red-900/50 border border-red-700 rounded-lg p-4 text-red-200">
|
||||
<p x-text="submitError"></p>
|
||||
</div>
|
||||
<div x-show="submitSuccess" class="bg-green-900/50 border border-green-700 rounded-lg p-4 text-green-200">
|
||||
<p x-text="submitSuccess"></p>
|
||||
</div>
|
||||
<button type="submit"
|
||||
:disabled="submitLoading"
|
||||
class="px-6 py-3 bg-primary hover:bg-emerald-700 text-white font-semibold rounded-lg transition-colors disabled:opacity-50">
|
||||
<span x-show="!submitLoading">Submit Testimonial</span>
|
||||
<span x-show="submitLoading">Submitting...</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Testimonials List -->
|
||||
<div class="space-y-6">
|
||||
<div x-show="loading" class="text-center text-gray-400 py-12">
|
||||
Loading testimonials...
|
||||
</div>
|
||||
<div x-show="error" class="bg-red-900/50 border border-red-700 rounded-lg p-4 text-red-200">
|
||||
<p x-text="error"></p>
|
||||
</div>
|
||||
<template x-for="testimonial in testimonials" :key="testimonial.id">
|
||||
<div class="bg-gray-800 rounded-lg p-6 border border-gray-700">
|
||||
<div class="flex items-start justify-between mb-4">
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-gray-100" x-text="testimonial.author_name"></h3>
|
||||
<p class="text-sm text-gray-400" x-text="new Date(testimonial.created_at).toLocaleDateString()"></p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-gray-300 leading-relaxed" x-text="testimonial.content"></p>
|
||||
</div>
|
||||
</template>
|
||||
<div x-show="!loading && !error && testimonials.length === 0" class="text-center text-gray-400 py-12">
|
||||
<p>No testimonials yet. Be the first to share your success story!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function testimonialsPage() {
|
||||
return {
|
||||
testimonials: [],
|
||||
loading: true,
|
||||
error: '',
|
||||
authorName: '',
|
||||
testimonialContent: '',
|
||||
submitError: '',
|
||||
submitSuccess: '',
|
||||
submitLoading: false,
|
||||
|
||||
initTestimonials() {
|
||||
// Check auth and show/hide paywall
|
||||
const authState = window.MembershipAPI.getAuthState();
|
||||
const paywallMessage = document.querySelector('.paywall-message');
|
||||
const paywallContent = document.querySelector('.paywall-content');
|
||||
const membershipOnly = document.querySelectorAll('.membership-only');
|
||||
|
||||
if (!authState.authenticated) {
|
||||
if (paywallMessage) paywallMessage.style.display = 'block';
|
||||
if (paywallContent) paywallContent.style.display = 'none';
|
||||
membershipOnly.forEach(el => el.style.display = 'none');
|
||||
this.loading = false;
|
||||
} else {
|
||||
if (paywallMessage) paywallMessage.style.display = 'none';
|
||||
if (paywallContent) paywallContent.style.display = 'block';
|
||||
membershipOnly.forEach(el => el.style.display = 'block');
|
||||
this.loadTestimonials();
|
||||
}
|
||||
},
|
||||
|
||||
async loadTestimonials() {
|
||||
this.loading = true;
|
||||
this.error = '';
|
||||
|
||||
const authState = window.MembershipAPI.getAuthState();
|
||||
if (!authState.authenticated) {
|
||||
this.loading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await window.MembershipAPI.loadTestimonials();
|
||||
this.loading = false;
|
||||
|
||||
if (result.success) {
|
||||
this.testimonials = result.testimonials || [];
|
||||
} else {
|
||||
this.error = result.error || 'Failed to load testimonials';
|
||||
}
|
||||
},
|
||||
|
||||
async submitTestimonial() {
|
||||
if (!this.authorName || !this.testimonialContent) {
|
||||
this.submitError = 'Please fill in all fields';
|
||||
return;
|
||||
}
|
||||
|
||||
this.submitError = '';
|
||||
this.submitSuccess = '';
|
||||
this.submitLoading = true;
|
||||
|
||||
const result = await window.MembershipAPI.submitTestimonial(this.testimonialContent, this.authorName);
|
||||
this.submitLoading = false;
|
||||
|
||||
if (result.success) {
|
||||
this.submitSuccess = result.message || 'Testimonial submitted successfully!';
|
||||
this.authorName = '';
|
||||
this.testimonialContent = '';
|
||||
// Reload testimonials after a delay
|
||||
setTimeout(() => this.loadTestimonials(), 2000);
|
||||
} else {
|
||||
this.submitError = result.error || 'Failed to submit testimonial';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{{ end }}
|
||||
|
||||
Reference in New Issue
Block a user