/* /assets/js/main.js - PromptVerse AI */ 'use strict'; const PV = { siteUrl: $('meta[name="site-url"]').attr('content') || '', csrf: $('meta[name="csrf-token"]').attr('content') || '', // ── Toast ────────────────────────────────────────────────────────────────── toast(msg, type = 'success', duration = 3500) { const id = 'toast_' + Date.now(); const icon = type === 'success' ? 'bi-check-circle-fill text-success' : type === 'error' ? 'bi-x-circle-fill text-danger' : 'bi-info-circle-fill text-primary'; const cls = type === 'success' ? 'success-toast' : type === 'error' ? 'error-toast' : ''; const html = ` `; $('#toastContainer').append(html); setTimeout(() => $('#' + id).remove(), duration); }, // ── Copy countdown + voice ───────────────────────────────────────────────── copyCountdown(promptId, promptText) { const modal = new bootstrap.Modal(document.getElementById('copyModal')); const circle = document.getElementById('countdownCircle'); const textEl = document.getElementById('countdownText'); const display = document.getElementById('countdownDisplay'); const progress = document.getElementById('copyProgress'); const total = 339.3; // 2πr let seconds = 5; modal.show(); textEl.textContent = seconds; display.textContent = seconds; progress.style.width = '100%'; const tick = setInterval(() => { seconds--; const pct = (seconds / 5); circle.style.strokeDashoffset = total * (1 - pct); progress.style.width = (pct * 100) + '%'; textEl.textContent = seconds; display.textContent = seconds; if (seconds <= 0) { clearInterval(tick); modal.hide(); PV.doCopy(promptId, promptText); } }, 1000); // Cancel on modal hide document.getElementById('copyModal').addEventListener('hide.bs.modal', () => { clearInterval(tick); }, { once: true }); }, doCopy(promptId, promptText) { // Copy to clipboard navigator.clipboard.writeText(promptText).then(() => { PV.toast('Prompt copied! Paste it into your AI tool.', 'success'); PV.voiceBangla('আপনার প্রম্পট কপি হয়েছে'); PV.trackCopy(promptId); }).catch(() => { // Fallback const ta = document.createElement('textarea'); ta.value = promptText; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); try { document.execCommand('copy'); PV.toast('Prompt copied!', 'success'); PV.voiceBangla('আপনার প্রম্পট কপি হয়েছে'); PV.trackCopy(promptId); } catch { PV.toast('Copy failed. Please copy manually.', 'error'); } document.body.removeChild(ta); }); }, // ── Voice Notification ───────────────────────────────────────────────────── voiceBangla(text) { if (!('speechSynthesis' in window)) return; window.speechSynthesis.cancel(); const utt = new SpeechSynthesisUtterance(text); utt.lang = 'bn-BD'; utt.volume = 1; utt.rate = 0.9; utt.pitch = 1; // Try Bengali voice const voices = window.speechSynthesis.getVoices(); const bnVoice = voices.find(v => v.lang.includes('bn') || v.name.toLowerCase().includes('bangla')); if (bnVoice) utt.voice = bnVoice; window.speechSynthesis.speak(utt); }, // ── Track copy via AJAX ──────────────────────────────────────────────────── trackCopy(promptId) { $.post(PV.siteUrl + '/ajax/copy.php', { prompt_id: promptId, csrf: PV.csrf }) .done(res => { try { const d = JSON.parse(res); if (d.copy_count !== undefined) { // Update copy count on page $(`.copy-count-${promptId}`).text(d.copy_count); } } catch {} }); }, // ── Lazy loading ─────────────────────────────────────────────────────────── initLazy() { if ('IntersectionObserver' in window) { const obs = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) { const img = e.target; img.src = img.dataset.src; img.classList.add('loaded'); obs.unobserve(img); } }); }, { rootMargin: '200px' }); document.querySelectorAll('img.lazy').forEach(img => obs.observe(img)); } else { document.querySelectorAll('img.lazy').forEach(img => { img.src = img.dataset.src; img.classList.add('loaded'); }); } }, // ── Skeleton → Cards ─────────────────────────────────────────────────────── hideSkeleton() { $('.skeleton-grid').fadeOut(200, function() { $(this).remove(); }); $('#promptGrid').fadeIn(300); }, // ── Infinite scroll / AJAX search ───────────────────────────────────────── initSearch() { let searchTimer; $('#liveSearch').on('input', function() { clearTimeout(searchTimer); const q = $(this).val().trim(); if (q.length < 2) { $('#liveResults').hide(); return; } searchTimer = setTimeout(() => { $.get(PV.siteUrl + '/ajax/search.php', { q }, (res) => { try { const d = JSON.parse(res); if (d.results && d.results.length) { let html = ''; d.results.forEach(p => { html += `
${p.title}
${p.cat_name}
`; }); $('#liveResults').html(html).show(); } else { $('#liveResults').html('
No results found
').show(); } } catch {} }); }, 400); }); $(document).on('click', function(e) { if (!$(e.target).closest('#searchWrapper').length) $('#liveResults').hide(); }); }, // ── Init ────────────────────────────────────────────────────────────────── init() { this.initLazy(); this.initSearch(); // Load voices if ('speechSynthesis' in window) { window.speechSynthesis.onvoiceschanged = () => {}; window.speechSynthesis.getVoices(); } } }; $(document).ready(function() { PV.init(); // Copy button click $(document).on('click', '.btn-copy-prompt', function() { const promptId = $(this).data('id'); const promptText = $(this).data('prompt'); PV.copyCountdown(promptId, promptText); }); // Quick copy (no countdown) $(document).on('click', '.btn-quick-copy', function() { const text = $(this).data('text'); navigator.clipboard.writeText(text).then(() => PV.toast('Copied!', 'success')); }); // Navbar scroll effect $(window).on('scroll', function() { if ($(this).scrollTop() > 60) { $('#mainNav').addClass('scrolled'); } else { $('#mainNav').removeClass('scrolled'); } }); // Category filter buttons $(document).on('click', '.filter-btn[data-filter]', function() { $('.filter-btn[data-filter]').removeClass('active'); $(this).addClass('active'); const filter = $(this).data('filter'); const url = new URL(window.location.href); if (filter === 'all') { url.searchParams.delete('sort'); } else { url.searchParams.set('sort', filter); } url.searchParams.delete('page'); window.location.href = url.toString(); }); // Image zoom on detail page $('#detailImage').on('click', function() { $(this).toggleClass('zoomed'); }); // Share buttons $(document).on('click', '.share-btn', function(e) { e.preventDefault(); window.open($(this).attr('href'), '_blank', 'width=600,height=400'); }); // Animate cards on scroll const animObserver = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('fade-up'); animObserver.unobserve(e.target); } }); }, { threshold: 0.1 }); document.querySelectorAll('.prompt-card').forEach(c => animObserver.observe(c)); }); /* ── FAVORITES (localStorage) ────────────────────── */ (function(){ const KEY='pv_favorites'; function get(){try{return JSON.parse(localStorage.getItem(KEY)||'[]');}catch{return[];}} function save(a){localStorage.setItem(KEY,JSON.stringify(a));if(typeof window.pvUpdateFavBadge==='function')window.pvUpdateFavBadge();} function has(id){return get().some(f=>f.id==id);} function syncBtn(btn){ if(!btn)return; const i=btn.querySelector('i'); if(has(btn.dataset.id)){ btn.style.background='rgba(229,57,53,.2)'; btn.style.borderColor='rgba(229,57,53,.5)'; btn.classList.add('active'); if(i){i.classList.remove('bi-heart');i.classList.add('bi-heart-fill');} } else { btn.style.background='rgba(0,0,0,.65)'; btn.style.borderColor='rgba(229,57,53,.3)'; btn.classList.remove('active'); if(i){i.classList.remove('bi-heart-fill');i.classList.add('bi-heart');} } } function init(){ document.querySelectorAll('.btn-fav-prompt').forEach(btn=>{ syncBtn(btn); if(btn._pvFavBound)return; btn._pvFavBound=true; btn.addEventListener('click',function(e){ e.preventDefault();e.stopPropagation(); const id=this.dataset.id; if(has(id)){ save(get().filter(f=>f.id!=id)); PV.toast('Favorites থেকে সরানো হয়েছে','info'); } else { const favs=get().filter(f=>f.id!=id); favs.unshift({id,slug:this.dataset.slug,title:this.dataset.title, caption:this.dataset.caption||'',ai_model:this.dataset.ai||'',image:this.dataset.image||''}); save(favs); PV.toast('❤️ Favorites-এ যোগ হয়েছে!','success'); const ic=this.querySelector('i'); if(ic){ic.style.transform='scale(1.5)';setTimeout(()=>ic.style.transform='',280);} } document.querySelectorAll('.btn-fav-prompt[data-id="'+id+'"]').forEach(b=>syncBtn(b)); }); }); } if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init); else init(); window.pvInitFavBtns=init; })();