Siteβ―Builder
Editing:
indexworks.php
writable 0666
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Ultimate Prompt Playground v6 (Full)</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"> <!-- Marked.js: tiny Markdown β HTML converter --> <script src="https://cdn.jsdelivr.net/npm/marked@12/marked.min.js"></script> <style> body{max-width:900px;margin:2rem auto;font-family:system-ui,sans-serif;} h1{text-align:center;margin-bottom:1.5rem;} /* BUSINESS PROFILE CARD */ .biz-card{background:#f9fafb;border:1px solid #ccc;border-radius:6px; padding:1rem;margin-bottom:1.5rem;display:flex;align-items:center;gap:1rem;} .biz-card h2{margin:0;font-size:1.5rem;} .biz-details{display:flex;flex-direction:column;gap:.25rem;} .biz-details p{margin:0;font-size:1rem;} .biz-icon{font-size:1.5rem;color:#6c48ff;} /* PROMPT CARD */ .prompt-card{position:relative;background:#fff;border:1px solid #ddd;border-radius:8px; padding:1rem;margin-bottom:1.5rem;} /* PROMPT TEXT */ .prompt-text{ /* respect \n produced by marked; also wrap long lines */ white-space:pre-wrap; line-height:1.6; } /* Headings & lists inside prompts rendered by marked */ .prompt-text h2 {font-size:1.25rem;margin:1rem 0 .5rem;} .prompt-text ul, .prompt-text ol {margin:.5rem 0 .5rem 1.25rem;} .prompt-text li {margin:.25rem 0;} .prompt-text strong {font-weight:700;} /* TOKENS */ .token{display:inline-flex;background:#e8e0ff;color:#5c3bff;padding:.3rem .6rem;border-radius:4px; cursor:pointer;user-select:none;flex:0 1 auto;min-width:0;white-space:normal; overflow-wrap:break-word;word-break:break-word;margin-bottom:.3rem;} .token.placeholder{opacity:.6;} /* TOOLBAR */ .toolbar{position:absolute;background:#fff;border:1px solid #ccc;border-radius:6px; box-shadow:0 2px 12px rgba(0,0,0,.1);padding:.8rem;display:flex;flex-direction:column; gap:.6rem;z-index:10;width:300px;} .toolbar label{font-size:.9rem;font-weight:600;margin-bottom:.3rem;} .toolbar input[type="text"],.toolbar select,.toolbar textarea{ width:100%;padding:.4rem;border:1px solid #999;border-radius:4px;font-size:1rem;} .toolbar select{max-height:200px;overflow:auto;} .toolbar textarea{resize:vertical;} /* CHECKBOX LIST */ .checkbox-list{display:flex;flex-direction:column;gap:.4rem;max-height:200px; overflow:auto;padding-right:.2rem;} .checkbox-list label{display:flex;align-items:center;gap:.6rem;padding:.4rem .6rem;background:#f0f4ff; border-radius:4px;cursor:pointer;transition:background .2s;} .checkbox-list label:hover{background:#e0e8ff;} .checkbox-list input[type="checkbox"]{accent-color:#3b82f6;width:1.2em;height:1.2em;flex-shrink:0;} /* AI BUTTONS */ .ai-btns{display:flex;gap:.6rem;margin-top:1rem;} .ai-btns a{flex:1;text-align:center;padding:.7rem;border-radius:6px;color:#fff;text-decoration:none;font-weight:600;} .ai-btns a.chatgpt{background:#6c48ff;} .ai-btns a.perplexity{background:#1ca7ec;} .ai-btns a.copilot{background:#00c853;color:#173E22;} .ai-btns a:hover{filter:brightness(1.1);} </style> </head> <body> <h1>Promptinator By Melanie AI</h1> <!-- Business Profile Card --> <div id="biz-profile" class="biz-card" hidden> <div class="biz-icon">π’</div> <div class="biz-details"> <h2></h2> <p>π <span class="biz-address"></span></p> <p>π <span class="biz-phone"></span></p> </div> </div> <div id="app"></div> <script> (async()=>{ const SEP=' β’ '; const RX=/\[(?:([ABCDI]?)-)?([^~|\-\]]+)(?:-([^~]*?))?(?:~([^~]*?)~)?\]/g; /* ---------- Load business data (optional) ---------- */ const params=new URLSearchParams(location.search); const ph=params.get('ph')||''; let biz={}; try{biz=await fetch(`/ph/${ph}/business.json`).then(r=>r.json());}catch{} function formatPhone(num){ const d=(num||'').replace(/\D/g,''); return d.length===10?`(${d.slice(0,3)}) ${d.slice(3,6)}-${d.slice(6)}`:num; } /* ---------- Populate business card ---------- */ const profile=document.getElementById('biz-profile'); if(biz.name){ profile.querySelector('h2').textContent=biz.name; profile.querySelector('.biz-address').textContent=biz.address||''; profile.querySelector('.biz-phone').textContent=formatPhone(biz.phone); profile.hidden=false; } /* ---------- Load prompts ---------- */ let prompts=[]; try{ prompts=await fetch('prompts.json').then(r=>r.json()).then(a=>a.map(o=>o.prompt)); }catch{} const app=document.getElementById('app'); function placeToolbar(tb,tok){ const card=tok.closest('.prompt-card'); const tr=tok.getBoundingClientRect(), cr=card.getBoundingClientRect(); tb.style.top =(tr.bottom-cr.top)+'px'; tb.style.left=(tr.left -cr.left)+'px'; } for(const tpl of prompts){ /* ---- build initial state ---- */ const meta=[], state={}; ['name','slogan','description','address','city','state','zip','phone','website'] .forEach(k=>state[k]=biz[k]||''); state.service =Array.isArray(biz.tags) ? biz.tags.slice(0,1):[]; state.location=Array.isArray(biz.location_tags) ? biz.location_tags.slice(0,1):[]; tpl.replace(RX,(m,cmd='',lab,ops='',def='')=>{ lab=lab.trim();let opts=[]; if(cmd==='C'){ if(lab==='service') opts=[...(biz.tags||[])]; else if(lab==='location') opts=[...(biz.location_tags||[])]; else opts=ops.split('|').filter(Boolean); state[lab]=def ? def.split(',').map(v=>v.trim()) : (opts.length?[opts[0]]:[]); }else if(cmd==='B'){ opts=ops.split('|').filter(Boolean); state[lab]=def||opts[0]||''; }else if(cmd==='D'){ if(ops.includes('|')){ opts=ops.split('|').filter(Boolean); state[lab]=def||opts[0]||''; }else{ state[lab]=def||state[lab]||''; } }else if(cmd==='I'){ opts=ops.split('|').filter(Boolean); state[lab]=def||state[lab]||''; }else{ state[lab]=def||state[lab]||''; } meta.push({cmd:cmd||'A',lab,opts,rawOps:ops,defaultVal:def}); return ''; }); /* ---- create card ---- */ const card=document.createElement('div'); card.className='prompt-card'; card.innerHTML=` <div class="prompt-text"></div> <div class="ai-btns"> <a class="chatgpt" data-base="https://chatgpt.com/?prompt=" target="_blank" rel="noopener">ChatGPT</a> <a class="perplexity" data-base="https://www.perplexity.ai/search?q=" target="_blank" rel="noopener">Perplexity</a> <a class="copilot" data-base="https://copilot.microsoft.com/?q=" target="_blank" rel="noopener">Copilot</a> </div>`; app.append(card); const tb=document.createElement('div'); tb.className='toolbar'; tb.style.display='none'; card.append(tb); /* ---- rendering helpers ---- */ function renderText(){ const cont=card.querySelector('.prompt-text'); /* substitute tokens β span tags (HTML) first */ const substituted=tpl.replace(RX,(m,cmd='',lab)=>{ const key=lab.trim(), idx=meta.findIndex(x=>x.lab===key); if(cmd==='C') return (state[key]||[]).map(tag=>`<span class="token" data-i="${idx}">${tag}</span>`).join(' '); return `<span class="token" data-i="${idx}">${state[key]||''}</span>`; }); /* convert Markdown (with inline token spans) to HTML */ const html=marked.parse(substituted); cont.innerHTML=html; /* reβattach click handlers */ cont.querySelectorAll('.token').forEach(t=>t.onclick=onTokenClick); } function rebuild(){ renderText(); const out=tpl.replace(RX,(m,cmd='',lab)=>{ const v=state[lab.trim()]; return cmd==='C'?(v||[]).join(SEP):v||''; }); card.querySelectorAll('.ai-btns a') .forEach(a=>a.href=a.dataset.base+encodeURIComponent(out)); } renderText(); rebuild(); /* ---- token click handler ---- */ function onTokenClick(e){ const tok=e.currentTarget, idx=+tok.dataset.i; const {cmd,lab,opts,rawOps,defaultVal}=meta[idx]; tb.innerHTML=''; placeToolbar(tb,tok); tb.style.display='flex'; document.addEventListener('mousedown',function off(ev){ if(!tb.contains(ev.target) && ev.target!==tok){ tb.style.display='none'; document.removeEventListener('mousedown',off); } }); const labelEl=document.createElement('label'); labelEl.textContent=lab.replace(/_/g,' '); tb.append(labelEl); if(cmd==='C'){ /* checkboxes */ const list=document.createElement('div'); list.className='checkbox-list'; opts.forEach(o=>{ const lb=document.createElement('label'); const cb=document.createElement('input'); cb.type='checkbox'; cb.value=o; cb.checked=(state[lab]||[]).includes(o); cb.onchange=()=>{ state[lab]=[...list.querySelectorAll('input:checked')].map(i=>i.value); rebuild(); }; lb.append(cb,' ',o); list.append(lb); }); tb.append(list); }else if(cmd==='B'){ /* radio buttons */ opts.forEach(o=>{ const lb=document.createElement('label'); const rd=document.createElement('input'); rd.type='radio'; rd.name=lab; rd.value=o; rd.checked=(state[lab]===o); rd.onchange=()=>{state[lab]=o; rebuild(); tb.style.display='none';}; lb.append(rd,' ',o); tb.append(lb); }); }else if(cmd==='D'){ /* dropdowns */ const sel=document.createElement('select'); if(opts.length){ /* text dropdown */ opts.forEach(o=>{ const op=document.createElement('option'); op.value=o; op.textContent=o; if(o===state[lab]) op.selected=true; sel.append(op); }); }else{ /* numeric dropdown */ const max=parseInt(rawOps||defaultVal,10)||0; for(let i=1;i<=max;i++){ const op=document.createElement('option'); op.value=String(i); op.textContent=i; if(String(i)===state[lab]) op.selected=true; sel.append(op); } } sel.onchange=()=>{state[lab]=sel.value; rebuild(); tb.style.display='none';}; tb.append(sel); }else if(cmd==='I'){ /* iframe URL picker */ if(opts.length){ const select=document.createElement('select'); const placeholder=document.createElement('option'); placeholder.disabled=true; placeholder.selected=true; placeholder.textContent=state[lab]||'Pick a site'; select.append(placeholder); opts.forEach(url=>{const op=document.createElement('option'); op.value=url; op.textContent=url; select.append(op);}); const iframe=document.createElement('iframe'); iframe.hidden=true; iframe.style.width='100%'; iframe.style.height='200px'; const btn=document.createElement('button'); btn.textContent='Use site'; btn.style.marginTop='.6rem'; select.onchange=()=>{iframe.hidden=false; iframe.src=select.value;}; btn.onclick=()=>{state[lab]=select.value; rebuild(); tb.style.display='none';}; tb.append(select,iframe,btn); }else{ /* numeric Iβtoken */ const inp=document.createElement('input'); inp.type='number'; inp.value=state[lab]||''; inp.oninput=()=>{state[lab]=inp.value; rebuild();}; tb.append(inp); } }else{ /* Aβtokens or default: textarea */ const field=cmd==='A' ? (()=>{const t=document.createElement('textarea'); t.rows=4; return t;})() : (()=>{const i=document.createElement('input'); i.type='text'; return i;})(); field.value=state[lab]||''; field.oninput=()=>{state[lab]=field.value; rebuild();}; tb.append(field); } } } /* ---------- Tutorial Section (unchanged) ---------- */ const tuto=document.createElement('section'); tuto.style.cssText='margin-top:2rem;padding:1rem;border-top:1px solid #ddd;'; tuto.innerHTML=` <h2>Shortcode Tutorial</h2> <ul> <li><strong>A-tokens (Free Text)</strong>: <code>[A-key-~default~]</code> β textarea preset.</li> <li><strong>B-tokens (Single Choice)</strong>: <code>[B-key-|opt1|opt2|~default~]</code> β radio buttons.</li> <li><strong>C-tokens (Multi-Select)</strong>: <code>[C-key-|opt1|opt2|]</code> or dynamic <code>[C-service-]</code>,<code>[C-location-]</code> β checkboxes.</li> <li><strong>D-tokens (Dropdown)</strong>: <code>[D-key-5~3~]</code> β numeric 1β¦5 dropdown default 3; <code>[D-key-|a|b|~b~]</code> β text dropdown.</li> <li><strong>I-tokens (Iframe Preview)</strong>: <code>[I-key-|url1|url2|β¦]</code> β URL select + iframe preview + button.</li> </ul>`; app.append(tuto); })(); </script> </body> </html>
Save changes
Create folder
writable 0777
Create
Cancel