feat: add sales-first Rank landing
This commit is contained in:
@@ -51,6 +51,25 @@ const profiles = {
|
||||
},
|
||||
};
|
||||
const state = { ideas: [], milestones: [], activity: [], activeId: null, selected: null, profileId: localStorage.getItem('rank-profile') || 'mvp', undo: null, recentPlacement: null };
|
||||
const sampleBacklog = {
|
||||
format: 'prioritix-feature-set-v1',
|
||||
name: 'Messy SaaS launch backlog',
|
||||
features: [
|
||||
{ title: 'Mobile sorting flow feels clumsy', description: 'Users can capture ideas, but the phone flow makes prioritizing feel like work instead of relief.', labels: ['Mobile', 'Activation'], impact: 9, effort: 4, confidence: 8, urgency: 8 },
|
||||
{ title: 'Team voting on every feature', description: 'Stakeholders want input, but voting may create politics before the product has a clear decision model.', labels: ['Collaboration'], impact: 7, effort: 7, confidence: 4, urgency: 5 },
|
||||
{ title: 'Export roadmap for sales calls', description: 'Turn sorted decisions into something founders can share with clients or internal buyers.', labels: ['Sales', 'Export'], impact: 8, effort: 5, confidence: 7, urgency: 7 },
|
||||
{ title: 'Dark mode polish', description: 'Nice for taste, but unlikely to decide whether anyone trusts the core prioritization.', labels: ['Polish'], impact: 4, effort: 3, confidence: 8, urgency: 2 },
|
||||
{ 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 }
|
||||
]
|
||||
};
|
||||
function loadSampleBacklog(){
|
||||
const input = $('#featureSetInput');
|
||||
if(!input) return;
|
||||
input.value = JSON.stringify(sampleBacklog, null, 2);
|
||||
document.querySelector('#feature-sets')?.scrollIntoView({ behavior:'smooth', block:'start' });
|
||||
toast('Sample backlog loaded. Import it or replace it with your own chaos.');
|
||||
}
|
||||
|
||||
const $ = (sel, root=document) => root.querySelector(sel);
|
||||
const $$ = (sel, root=document) => Array.from(root.querySelectorAll(sel));
|
||||
const featureDeck = $('#featureDeck'); const sortingGrid = $('#sortingGrid'); const timeline = $('#timeline');
|
||||
@@ -168,6 +187,7 @@ async function reorderOnTimeline(id,e){ const line=e.currentTarget; const idea=s
|
||||
function openDetail(id){ const idea=state.ideas.find(i=>i.id===id); if(!idea) return; state.selected=id; detailForm.title.value=idea.title||''; detailForm.description.value=idea.description||''; detailForm.labels.value=(idea.labels||[]).join(', '); detailForm.impact.value=idea.impact??5; detailForm.effort.value=idea.effort??5; detailForm.confidence.value=idea.confidence??5; detailForm.urgency.value=idea.urgency??5; detailForm.notes.value=idea.notes||''; $('#detailCategory').textContent=categoryOf(idea); $('.detail-head .chip').textContent=zoneFor(idea).label; detail.classList.add('open'); detail.setAttribute('aria-hidden','false'); }
|
||||
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);
|
||||
$('#featureSetFile')?.addEventListener('change', async e => {
|
||||
const file = e.currentTarget.files?.[0];
|
||||
if(!file) return;
|
||||
|
||||
Reference in New Issue
Block a user