Composer & AI Ad Generator

Content Calendar

Leads & Landing Pages

Landing page generates a downloadable HTML file you can upload to Neocities or another host. Leads are stored locally unless you hook up a backend.

Analytics (Simulated)

Total Posts: 0
Drafts: 0
Scheduled: 0
Leads Captured: 0

Tip: Connect a backend to capture real analytics and let AI analyze past post performance.

`; //const blob = new Blob([html], {type:'text/html'}); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'royalia-landing.html'; a.click(); URL.revokeObjectURL(url); alert('Landing page generated. Upload the downloaded file to Neocities or another host to use it live. Note: to capture leads centrally, point the form to your backend endpoint.'); }); // --- leads viewer & export --- viewLeads.addEventListener('click', ()=>{ const leads = state.leads.slice().reverse(); if(leads.length===0) return alert('No leads captured yet.'); const txt = leads.map(l=>`${l.name} — ${l.email} — ${l.phone || ''} — ${new Date(l.createdAt).toLocaleString()}`).join('\n'); alert('Leads:\n\n'+txt); }); exportLeads.addEventListener('click', ()=>{ if(state.leads.length===0) return alert('No leads to export.'); const csv = ['name,email,phone,createdAt', ...state.leads.map(l=>`"${(l.name||'').replace(/"/g,'""')}","${(l.email||'').replace(/"/g,'""')}","${(l.phone||'').replace(/"/g,'""')}","${l.createdAt}"`)].join('\n'); const blob = new Blob([csv], {type:'text/csv'}); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href=url; a.download='royalia-leads.csv'; a.click(); URL.revokeObjectURL(url); }); // --- lead capture from internal demo landing page (optional) --- // For demo, let users add a lead manually document.addEventListener('keydown', (e)=>{ if(e.ctrlKey && e.key==='l'){ const name=prompt('Lead name'); const email=prompt('Lead email'); if(!email) return alert('Email required'); state.leads.push({id:uid('lead'),name,email,phone:'',createdAt:new Date().toISOString()}); save('royalia_leads', state.leads); updateStats(); alert('Lead added (demo)'); }}); // --- data export/reset --- exportDataBtn.addEventListener('click', ()=>{ const dump = JSON.stringify(state,null,2); const blob=new Blob([dump],{type:'application/json'}); const a=document.createElement('a'); a.href=URL.createObjectURL(blob); a.download='royalia-data.json'; a.click(); URL.revokeObjectURL(a.href); }); resetBtn.addEventListener('click', ()=>{ if(confirm('Reset all local data?')){ localStorage.removeItem('royalia_business'); localStorage.removeItem('royalia_social'); localStorage.removeItem('royalia_partners'); localStorage.removeItem('royalia_posts'); localStorage.removeItem('royalia_leads'); location.reload(); }}); // --- preview landing (open generated file in new window) --- previewLanding.addEventListener('click', ()=>{ createLanding.click(); }); // --- boot --- init(); // ----------------------------- // Helpful: Example Node.js/Express backend templates (use on Vercel/Render/Heroku). // Save this snippet to a separate project and deploy. Replace placeholders with your keys. // ----------------------------- /* // server.js (Example) const express = require('express'); const fetch = require('node-fetch'); const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.json()); // Environment variables required: OPENAI_API_KEY, INSTAGRAM_CLIENT_ID, INSTAGRAM_CLIENT_SECRET, OAUTH_REDIRECT_BASE // Simple OpenAI proxy (do NOT expose your OpenAI key in the frontend) app.post('/api/openai', async (req,res)=>{ const prompt = req.body.prompt || 'Hello'; const r = await fetch('https://api.openai.com/v1/chat/completions',{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer '+process.env.OPENAI_API_KEY},body:JSON.stringify({model:'gpt-4o-mini',messages:[{role:'user',content:prompt}],max_tokens:400})}); const data = await r.json(); res.json({text: data.choices?.[0]?.message?.content || (data.choices?.[0]?.text) || JSON.stringify(data)}); }); // OAuth example start (Instagram via Facebook): redirect user to platform app.get('/api/oauth/instagram', (req,res)=>{ const redirectUri = encodeURIComponent(process.env.OAUTH_REDIRECT_BASE + '/api/oauth/callback/instagram'); const clientId = process.env.INSTAGRAM_CLIENT_ID; const url = `https://www.facebook.com/v17.0/dialog/oauth?client_id=${clientId}&redirect_uri=${redirectUri}&scope=instagram_basic,pages_show_list`; res.redirect(url); }); // OAuth callback (exchange code for token) - this endpoint should be configured as the redirect URI app.get('/api/oauth/callback/instagram', async (req,res)=>{ const code = req.query.code; // Exchange code for access token with Facebook Graph API flow // Save tokens to your DB and then redirect to a success page that postMessage()s to the popup window res.send(''); }); // Store leads // Connect to MongoDB or Postgres and implement secure storage app.listen(process.env.PORT||3000, ()=>console.log('Server running')); */ // ----------------------------- // Notes & next steps to enable full functionality: // 1) Deploy the Node backend above, implement real OAuth token exchange, store tokens in DB. // 2) Implement endpoints: /api/openai (proxy), /api/oauth/* (redirects + callbacks), /api/post (post to IG/FB/TikTok using tokens), /api/leads (POST leads from landing pages). // 3) Update the constants at top of this file to point to your deployed backend endpoints. // 4) On Neocities, upload this index.html. The frontend will be fully functional for composition, scheduling (client-side), partner management, and landing page generation. // 5) For production, use HTTPS-enabled hosting for backend, keep your API keys secret, and implement user authentication (JWT) on the backend.