dodey917's picture
Create a software product page with hero demo video, features comparison table, integration logos, API documentation link, use cases with examples, security certifications, customer stories, and free trial signup.
b7f5767 verified
// Theme toggle with persistence
(function initTheme() {
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const saved = localStorage.getItem('theme'); // 'light' | 'dark'
const root = document.documentElement;
const setTheme = (mode) => {
if (mode === 'dark') {
root.classList.add('dark');
} else {
root.classList.remove('dark');
}
localStorage.setItem('theme', mode);
// Update icon
const iconEl = document.querySelector('#themeToggle i');
if (iconEl) {
iconEl.setAttribute('data-feather', mode === 'dark' ? 'sun' : 'moon');
if (window.feather) feather.replace();
}
};
setTheme(saved || (prefersDark ? 'dark' : 'light'));
})();
document.getElementById('themeToggle')?.addEventListener('click', () => {
const isDark = document.documentElement.classList.contains('dark');
const next = isDark ? 'light' : 'dark';
if (next === 'dark') {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
localStorage.setItem('theme', next);
const iconEl = document.querySelector('#themeToggle i');
if (iconEl) {
iconEl.setAttribute('data-feather', next === 'dark' ? 'sun' : 'moon');
if (window.feather) feather.replace();
}
});
// Year in footer
document.getElementById('year').textContent = new Date().getFullYear();
// Copy buttons
document.querySelectorAll('button[data-copy]').forEach((btn) => {
btn.addEventListener('click', async () => {
const sel = btn.getAttribute('data-copy');
const codeEl = document.querySelector(sel);
const text = codeEl?.innerText || '';
try {
await navigator.clipboard.writeText(text);
const label = btn.querySelector('.copy-label');
if (label) label.textContent = 'Copied!';
setTimeout(() => {
if (label) label.textContent = 'Copy';
}, 1500);
} catch (e) {
console.error('Copy failed', e);
}
});
});
// Signup form handlers (both CTA sections)
function handleSignup(formId, messageId) {
const form = document.getElementById(formId);
const msg = document.getElementById(messageId);
if (!form) return;
form.addEventListener('submit', async (e) => {
e.preventDefault();
const email = form.querySelector('input[type="email"]')?.value?.trim();
const password = form.querySelector('input[type="password"]')?.value;
if (!email) return;
if (formId === 'signupModalForm' && password && password.length < 8) {
if (msg) msg.textContent = 'Password must be at least 8 characters.';
return;
}
// Simulate async signup
if (msg) msg.textContent = 'Creating your workspace...';
await new Promise((r) => setTimeout(r, 900));
if (msg) msg.textContent = 'Success! Check your email to verify your account.';
// Close modal if applicable
if (formId === 'signupModalForm') closeSignupModal();
// Reset form
form.reset();
});
}
handleSignup('signupForm', 'formMessage');
handleSignup('signupModalForm', 'modalMessage');
// Signup modal
const openSignupButtons = ['openSignupTop', 'openSignupHero', 'openSignupPricing']
.map((id) => document.getElementById(id))
.filter(Boolean);
const modal = document.getElementById('signupModal');
const closeBtn = document.getElementById('closeSignup');
function openSignupModal() {
modal?.classList.remove('hidden');
modal?.classList.add('flex');
document.getElementById('modalEmail')?.focus();
}
function closeSignupModal() {
modal?.classList.add('hidden');
modal?.classList.remove('flex');
}
openSignupButtons.forEach((btn) => btn.addEventListener('click', openSignupModal));
closeBtn?.addEventListener('click', closeSignupModal);
modal?.addEventListener('click', (e) => {
if (e.target === modal) closeSignupModal();
});
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') closeSignupModal();
});
// Pause video when modal opens/closes
const heroVideo = document.getElementById('heroVideo');
const observer = new MutationObserver(() => {
if (modal?.classList.contains('hidden') === false && !heroVideo?.paused) {
heroVideo?.pause();
}
});
observer.observe(modal, { attributes: true, attributeFilter: ['class'] });