Landing page for RunVoteWin, a modern canvassing and voter data system for Democratic Party campaigns.
Live site: https://runvotewin.com/
Prerequisites:
- Node.js 22 or newer
- npm
Install dependencies:
npm installStart the local development server:
npm run devRun type checking:
npm run lintBuild for production:
npm run buildThe landing page reads VITE_SIGNUP_ENDPOINT at build time. Set it to a Google Apps Script web app URL that accepts lead and pricing-estimate payloads.
{
"formType": "pricing",
"name": "Jane Organizer",
"email": "jane@campaign.org",
"role": "candidate",
"campaignSize": "congressional",
"estimateMonthly": 1250,
"source": "RunVoteWin landing page"
}Until that endpoint is configured, the forms render normally but display a connection-needed message on submit.
- Open the Google Sheet for leads.
- Go to Extensions > Apps Script.
- Paste the contents of
automation/google-apps-script/pricing-leads.gs. - Optional: set
TEAM_NOTIFY_EMAILin the script if the team should receive internal lead notifications. - Click Deploy > New deployment.
- Choose Web app.
- Set Execute as to Me.
- Set Who has access to Anyone.
- Deploy and copy the web app URL ending in
/exec. - In GitHub, add a repository secret named
VITE_SIGNUP_ENDPOINTwith that/execURL. - Re-run the GitHub Pages workflow or merge any change to rebuild the static site with the endpoint.
The front end sends text/plain JSON with mode: no-cors so Google Apps Script can receive submissions from GitHub Pages without a CORS preflight.
The NGP VAN comparison logo is sourced from Wikimedia Commons: https://commons.wikimedia.org/wiki/File:NGPVAN_Logo.svg
GitHub Pages is deployed by .github/workflows/deploy-pages.yml.
The Vite base option is set to ./ so the static build works from the custom domain root without hard-coded repository paths.
In GitHub Pages settings, the source should be GitHub Actions. Do not serve the repository root directly; that serves src/main.tsx instead of the static dist build and will fail in the browser.