diff --git a/public/app.js b/public/app.js index 83caffd..fd258dc 100644 --- a/public/app.js +++ b/public/app.js @@ -62,6 +62,27 @@ const sampleBacklog = { { title: 'AI explains why an idea moved', description: 'Every ranking should show a reason, risk, and what evidence would change the decision.', labels: ['Trust', 'AI'], impact: 9, effort: 6, confidence: 6, urgency: 8 } ] }; +const aiReadyPrompt = `You are preparing features for Rank / Prioritix, a prioritization workbench that imports Prioritix Feature Set v1 JSON. Convert my messy backlog, notes, stakeholder requests, or product ideas into valid JSON only — no markdown, no commentary. + +Return this exact shape: +{ + "format": "prioritix-feature-set-v1", + "name": "Short project or backlog name", + "features": [ + { + "title": "Clear feature title", + "description": "Plain-language reason this feature matters and what outcome it supports.", + "labels": ["Category", "Optional second category"], + "impact": 1-10, + "effort": 1-10, + "confidence": 1-10, + "urgency": 1-10, + "notes": "Risks, assumptions, dependencies, or evidence that would change the ranking." + } + ] +} + +Scoring guidance: impact means user/business value, effort means delivery difficulty, confidence means how sure the evidence is, urgency means time sensitivity. Use the full 1-10 range honestly. Split vague bundles into separate features. Merge duplicates. Label polish as polish, bets as validation/research, and must-have product work as core. If evidence is weak, lower confidence rather than pretending. Keep titles short enough to scan on a card.`; function loadSampleBacklog(){ const input = $('#featureSetInput'); if(!input) return; @@ -69,6 +90,23 @@ function loadSampleBacklog(){ document.querySelector('#feature-sets')?.scrollIntoView({ behavior:'smooth', block:'start' }); toast('Sample backlog loaded. Import it or replace it with your own chaos.'); } +async function copyAiPrompt(){ + const status = $('#aiPromptStatus'); + try { + await navigator.clipboard.writeText(aiReadyPrompt); + if(status) status.textContent = 'Copied. Paste it into any AI, then paste the returned JSON back here.'; + toast('AI-ready prompt copied'); + } catch { + const input = $('#featureSetInput'); + if(input){ + input.value = aiReadyPrompt; + input.focus(); + input.select(); + } + if(status) status.textContent = 'Clipboard blocked — the prompt is selected in the text area for manual copy.'; + toast('Clipboard blocked. Prompt selected for manual copy.'); + } +} const $ = (sel, root=document) => root.querySelector(sel); const $$ = (sel, root=document) => Array.from(root.querySelectorAll(sel)); @@ -188,6 +226,7 @@ function openDetail(id){ const idea=state.ideas.find(i=>i.id===id); if(!idea) re function closeDetail(){ detail.classList.remove('open'); detail.setAttribute('aria-hidden','true'); state.selected=null; } async function archiveIdea(id=state.selected){ if(!id) return; const previous=state.ideas.find(i=>i.id===id); try{ await api(`/api/ideas/${id}`,{method:'PATCH',body:{archived:true,status:'remove'}}); state.ideas = state.ideas.filter(i=>i.id!==id); closeDetail(); render(); toast('Removed', previous ? () => undoIdea({...previous, archived:false}) : null); } catch(error){ toast(error.message); } } $('#sampleBacklog')?.addEventListener('click', loadSampleBacklog); +$('#copyAiPrompt')?.addEventListener('click', copyAiPrompt); $('#featureSetFile')?.addEventListener('change', async e => { const file = e.currentTarget.files?.[0]; if(!file) return; diff --git a/public/index.html b/public/index.html index 1e9d3a9..9fba48c 100644 --- a/public/index.html +++ b/public/index.html @@ -6,7 +6,7 @@
Copies a prompt that makes another AI return import-ready Rank JSON.