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:
221
layouts/membership/single.html
Normal file
221
layouts/membership/single.html
Normal file
@@ -0,0 +1,221 @@
|
||||
{{ define "main" }}
|
||||
<div class="bg-gray-900 min-h-screen py-16 px-4 sm:px-6 lg:px-8" x-data="membershipPage()">
|
||||
<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">Become a Member</h1>
|
||||
<p class="text-xl text-gray-300 max-w-2xl mx-auto">
|
||||
Unlock exclusive access to premium content, unlimited downloads, and direct communication with Dr. Jones.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Benefits Section -->
|
||||
<div class="bg-gray-800 rounded-lg p-8 mb-8 border border-gray-700">
|
||||
<h2 class="text-2xl font-bold text-gray-100 mb-6">Member Benefits</h2>
|
||||
<div class="grid md:grid-cols-2 gap-6">
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="flex-shrink-0 w-8 h-8 bg-primary rounded-full flex items-center justify-center">
|
||||
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-gray-100 mb-2">Unlimited Downloads</h3>
|
||||
<p class="text-gray-300">Access and download all resources from the library without limits.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="flex-shrink-0 w-8 h-8 bg-primary rounded-full flex items-center justify-center">
|
||||
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-gray-100 mb-2">Direct Email Access</h3>
|
||||
<p class="text-gray-300">Get my direct email address and submit contact forms for personalized help.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="flex-shrink-0 w-8 h-8 bg-primary rounded-full flex items-center justify-center">
|
||||
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-gray-100 mb-2">Member Testimonials</h3>
|
||||
<p class="text-gray-300">Read and share success stories from other growers using the sterile method.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="flex-shrink-0 w-8 h-8 bg-primary rounded-full flex items-center justify-center">
|
||||
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-gray-100 mb-2">Priority Support</h3>
|
||||
<p class="text-gray-300">Members get priority responses and access to exclusive content updates.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buy Me a Coffee Section -->
|
||||
<div class="bg-gradient-to-r from-[#FFDD00] to-[#FFCC00] rounded-lg p-8 mb-8 text-center">
|
||||
<h2 class="text-3xl font-bold text-gray-900 mb-4">Support the Method</h2>
|
||||
<p class="text-lg text-gray-800 mb-6">
|
||||
Membership requires a $5 minimum donation via Buy Me a Coffee. This helps support continued development of sterile hydroponic protocols and resources.
|
||||
</p>
|
||||
<a href="https://www.buymeacoffee.com/r26xrthzttg" target="_blank" rel="noopener noreferrer"
|
||||
class="inline-flex items-center px-8 py-4 bg-gray-900 hover:bg-gray-800 text-white rounded-lg font-bold text-lg transition-colors shadow-lg">
|
||||
<svg class="w-6 h-6 mr-3" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M18.5 3H6c-1.1 0-2 .9-2 2v5.71c0 3.83 2.95 7.18 6.78 7.29 3.96.12 7.22-3.06 7.22-7v-1h.5c1.38 0 2.5-1.12 2.5-2.5S19.88 3 18.5 3zM16 5v3H6V5h10zm2.5 5H18V5h.5c.28 0 .5.22.5.5s-.22.5-.5.5zM4 19h16v2H4v-2z"/>
|
||||
</svg>
|
||||
Donate $5 Minimum
|
||||
</a>
|
||||
<p class="text-sm text-gray-700 mt-4 italic">After completing your donation, return here to sign up for membership.</p>
|
||||
</div>
|
||||
|
||||
<!-- Login/Register Tabs -->
|
||||
<div class="bg-gray-800 rounded-lg border border-gray-700 overflow-hidden">
|
||||
<div class="border-b border-gray-700 flex">
|
||||
<button @click="activeTab = 'login'"
|
||||
:class="activeTab === 'login' ? 'bg-primary text-white' : 'text-gray-300 hover:text-gray-100'"
|
||||
class="flex-1 px-6 py-4 font-medium transition-colors">
|
||||
Login
|
||||
</button>
|
||||
<button @click="activeTab = 'register'"
|
||||
:class="activeTab === 'register' ? 'bg-primary text-white' : 'text-gray-300 hover:text-gray-100'"
|
||||
class="flex-1 px-6 py-4 font-medium transition-colors">
|
||||
Sign Up
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="p-8">
|
||||
<!-- Login Form -->
|
||||
<div x-show="activeTab === 'login'" x-transition>
|
||||
<form @submit.prevent="handleLogin()" class="space-y-6">
|
||||
<div>
|
||||
<label for="login-email" class="block text-sm font-medium text-gray-300 mb-2">Email</label>
|
||||
<input type="email" id="login-email" x-model="loginEmail" 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="login-password" class="block text-sm font-medium text-gray-300 mb-2">Password</label>
|
||||
<input type="password" id="login-password" x-model="loginPassword" 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 x-show="loginError" class="bg-red-900/50 border border-red-700 rounded-lg p-4 text-red-200">
|
||||
<p x-text="loginError"></p>
|
||||
</div>
|
||||
<button type="submit"
|
||||
:disabled="loginLoading"
|
||||
class="w-full px-6 py-3 bg-primary hover:bg-emerald-700 text-white font-semibold rounded-lg transition-colors disabled:opacity-50">
|
||||
<span x-show="!loginLoading">Login</span>
|
||||
<span x-show="loginLoading">Logging in...</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Register Form -->
|
||||
<div x-show="activeTab === 'register'" x-transition>
|
||||
<form @submit.prevent="handleRegister()" class="space-y-6">
|
||||
<div>
|
||||
<label for="register-name" class="block text-sm font-medium text-gray-300 mb-2">Full Name</label>
|
||||
<input type="text" id="register-name" x-model="registerName" 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="register-email" class="block text-sm font-medium text-gray-300 mb-2">Email</label>
|
||||
<input type="email" id="register-email" x-model="registerEmail" 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="register-password" class="block text-sm font-medium text-gray-300 mb-2">Password</label>
|
||||
<input type="password" id="register-password" x-model="registerPassword" required minlength="8"
|
||||
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">
|
||||
<p class="mt-1 text-sm text-gray-400">Must be at least 8 characters</p>
|
||||
</div>
|
||||
<div x-show="registerError" class="bg-red-900/50 border border-red-700 rounded-lg p-4 text-red-200">
|
||||
<p x-text="registerError"></p>
|
||||
</div>
|
||||
<div x-show="registerSuccess" class="bg-green-900/50 border border-green-700 rounded-lg p-4 text-green-200">
|
||||
<p x-text="registerSuccess"></p>
|
||||
</div>
|
||||
<button type="submit"
|
||||
:disabled="registerLoading"
|
||||
class="w-full px-6 py-3 bg-primary hover:bg-emerald-700 text-white font-semibold rounded-lg transition-colors disabled:opacity-50">
|
||||
<span x-show="!registerLoading">Sign Up</span>
|
||||
<span x-show="registerLoading">Creating account...</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Status Message -->
|
||||
<div x-show="statusMessage" class="mt-6 p-4 rounded-lg"
|
||||
:class="statusMessageType === 'success' ? 'bg-green-900/50 border border-green-700 text-green-200' : 'bg-blue-900/50 border border-blue-700 text-blue-200'">
|
||||
<p x-text="statusMessage"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function membershipPage() {
|
||||
return {
|
||||
activeTab: 'login',
|
||||
loginEmail: '',
|
||||
loginPassword: '',
|
||||
loginError: '',
|
||||
loginLoading: false,
|
||||
registerName: '',
|
||||
registerEmail: '',
|
||||
registerPassword: '',
|
||||
registerError: '',
|
||||
registerSuccess: '',
|
||||
registerLoading: false,
|
||||
statusMessage: '',
|
||||
statusMessageType: 'info',
|
||||
|
||||
async handleLogin() {
|
||||
this.loginError = '';
|
||||
this.loginLoading = true;
|
||||
|
||||
const result = await window.MembershipAPI.login(this.loginEmail, this.loginPassword);
|
||||
|
||||
this.loginLoading = false;
|
||||
|
||||
if (result.success) {
|
||||
this.statusMessage = 'Login successful! Redirecting...';
|
||||
this.statusMessageType = 'success';
|
||||
setTimeout(() => {
|
||||
window.location.href = '/';
|
||||
}, 1500);
|
||||
} else {
|
||||
this.loginError = result.error || 'Login failed';
|
||||
}
|
||||
},
|
||||
|
||||
async handleRegister() {
|
||||
this.registerError = '';
|
||||
this.registerSuccess = '';
|
||||
this.registerLoading = true;
|
||||
|
||||
const result = await window.MembershipAPI.register(this.registerEmail, this.registerPassword, this.registerName);
|
||||
|
||||
this.registerLoading = false;
|
||||
|
||||
if (result.success) {
|
||||
this.registerSuccess = result.message || 'Registration successful! Your membership is pending approval. You will receive an email when approved.';
|
||||
this.registerEmail = '';
|
||||
this.registerPassword = '';
|
||||
this.registerName = '';
|
||||
} else {
|
||||
this.registerError = result.error || 'Registration failed';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{{ end }}
|
||||
|
||||
Reference in New Issue
Block a user