diff --git a/frontend/src/pages/proposals/[id].astro b/frontend/src/pages/proposals/[id].astro index 4e6fee4..8938967 100644 --- a/frontend/src/pages/proposals/[id].astro +++ b/frontend/src/pages/proposals/[id].astro @@ -63,6 +63,72 @@ const proposalId = id ?? ''; return hints[method] || hints['approval']; } + function getVotingExplainer(method) { + const m = normalizeMethod(method); + if (m === 'ranked_choice') { + return { + hint: 'Ranked-choice voting', + lede: 'You rank options in order of preference. If your top choice cannot win, your vote transfers to your next choice.', + bullets: [ + 'Click options in order: 1st choice, then 2nd, then 3rd.', + 'Click an already-ranked option to remove it and re-number the ranks.', + 'Add as many ranks as you like—more ranks can make your intent clearer.', + ], + note: 'Tip: if you only rank one option, your vote will not transfer.' + }; + } + + if (m === 'quadratic') { + return { + hint: 'Quadratic voting', + lede: 'You allocate credits across options. Extra support costs more (1 vote costs 1 credit, 2 votes cost 4, 3 votes cost 9, etc.).', + bullets: [ + 'Use + / − to allocate votes (credits) per option.', + 'Watch the total credits used so you do not exceed the limit.', + 'Spread credits to express nuance, or concentrate them to signal priority.' + ], + note: 'Tip: quadratic cost makes it expensive to “pile on” many votes for one option.' + }; + } + + if (m === 'star') { + return { + hint: 'Star voting', + lede: 'You rate each option from 0 to 5 stars. Higher ratings show stronger support across multiple options.', + bullets: [ + 'Click stars on each option to set your rating.', + 'You can rate multiple options highly if you like several outcomes.', + 'Use low ratings (or 0) to express opposition or disinterest.' + ], + note: 'Tip: star voting captures intensity without forcing a single pick.' + }; + } + + if (m === 'schulze') { + return { + hint: 'Schulze (Condorcet) method', + lede: 'This method compares options pairwise to find the strongest overall winner based on collective preferences.', + bullets: [ + 'Think in terms of which option you prefer over another, not just a single favorite.', + 'If you are asked to rank options, include as many as you can for clarity.', + 'Results aim to reflect broad preference strength across matchups.' + ], + note: 'Tip: ranking more options helps express your true preferences.' + }; + } + + return { + hint: 'Approval voting', + lede: 'You can approve multiple options. Each approved option gets one vote from you.', + bullets: [ + 'Click to select one or more options you can live with.', + 'Approving several options signals you are open to compromise.', + 'Submit when your selections match your intent.' + ], + note: 'Tip: approval voting is great when there are several acceptable outcomes.' + }; + } + async function loadProposal() { const container = document.getElementById('proposal-content'); if (!container) return; @@ -173,6 +239,25 @@ const proposalId = id ?? ''; +
+ + How voting works + ${escapeHtml(getVotingExplainer(methodKey).hint)} + +
+ ${(() => { + const explainer = getVotingExplainer(methodKey); + return ` +

${escapeHtml(explainer.lede)}

+ + ${explainer.note ? `

${escapeHtml(explainer.note)}

` : ''} + `; + })()} +
+
+ ${canStartDiscussion ? `
@@ -699,6 +784,27 @@ const proposalId = id ?? ''; margin-bottom: 1rem; } + .explainer-lede { + margin: 0; + color: var(--color-text); + line-height: 1.6; + } + + .explainer-list { + margin: 0.75rem 0 0; + padding-left: 1.1rem; + color: var(--color-text-muted); + line-height: 1.55; + display: grid; + gap: 0.35rem; + } + + .explainer-note { + margin: 0.75rem 0 0; + color: var(--color-text-muted); + font-size: 0.9rem; + } + .comment-actions { margin-top: 0.5rem; display: flex;