Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ca40ba7
Download framer-motion and lucid-react for icons
arianabuilds Nov 3, 2025
ee464ce
Add placeholder code skeleton for new HomePage 2025: /admin/homepage2025
arianabuilds Nov 3, 2025
d56d0d9
Add high-level components
arianabuilds Nov 3, 2025
72f4e0b
Switch font to san serif
arianabuilds Nov 3, 2025
642c1de
Header: remove underline
arianabuilds Nov 3, 2025
c7b7774
Header: pull Header into its own component
arianabuilds Nov 3, 2025
f5eeca8
Hero: pulled Hero code into its own component
arianabuilds Nov 3, 2025
d52ecc1
Hero: Update features text & icons
arianabuilds Nov 3, 2025
41cf3be
Hero: Tweak tagline
arianabuilds Nov 3, 2025
e16b196
Hero: add line breaker in the tagline
arianabuilds Nov 3, 2025
37dd575
Extract Button code into its own component
arianabuilds Nov 3, 2025
2121f4a
Buttons: Tweak styling
arianabuilds Nov 3, 2025
cb14073
Hero: Update button text
arianabuilds Nov 3, 2025
2158ab4
Hero: update tagline color to SIV's blue #060067
arianabuilds Nov 3, 2025
ad1bd74
Buttons: update BlackButton color to SIV's dark blue
arianabuilds Nov 3, 2025
8edc3a0
Hero: update background style
arianabuilds Nov 3, 2025
ab63a48
Hero: Fix g in voting getting cut
arianabuilds Nov 3, 2025
1372f73
Buttons & Header: Added ability to override button styling
arianabuilds Nov 3, 2025
10463d6
Header: upade login button w/ icon and BlackButton styling
arianabuilds Nov 3, 2025
d96da3b
Header: add ability for custom styling for WhiteButton component & up…
arianabuilds Nov 3, 2025
7faed04
Header: updated login link
arianabuilds Nov 3, 2025
026b612
Hero: Moved Properties Cards from right of the title to underneath fo…
arianabuilds Nov 3, 2025
1d54ebf
Hero: Comment out # of votes cast for now
arianabuilds Nov 3, 2025
9083e7d
Fix build error: Switch homepage2025 from /pages to /src
arianabuilds Nov 8, 2025
ce251e3
Update export path to match /src
arianabuilds Nov 8, 2025
7bdc01c
Hero: Added numbers to Cards
arianabuilds Nov 8, 2025
189bde0
Hero: add card Voter Verifiable Results
arianabuilds Nov 8, 2025
300e0d8
Hero: easier code structure for Features
arianabuilds Nov 8, 2025
af760ea
Hero: add desc & styling to Verifiable Results
arianabuilds Nov 8, 2025
485c37e
Increase margin above cards
arianabuilds Nov 8, 2025
cafa189
Hero: add line break
arianabuilds Nov 8, 2025
8b30d11
Hero: tweak Results desc
arianabuilds Nov 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,11 @@
"cypress-mailslurp": "^1.3.0",
"email-validator": "^2.0.4",
"firebase-admin": "^9.0.0",
"framer-motion": "^12.23.24",
"isomorphic-dompurify": "^2.29.0",
"jsonwebtoken": "^8.5.1",
"lodash-es": "^4.17.15",
"lucide-react": "^0.552.0",
"mailgun-js": "^0.22.0",
"marked": "^16.4.0",
"moment": "^2.29.1",
Expand Down
1 change: 1 addition & 0 deletions pages/admin/homepage2025.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { HomePage2025 as default } from '../../src/homepage2025/HomePage2025'
Binary file added public/homepage2025/checkmark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/homepage2025/devices.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/homepage2025/privacy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions src/homepage2025/Buttons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react'

export const BlackButton = ({
children,
className,
href,
icon: Icon,
id,
}: {
children: React.ReactNode
className?: string
href: string
icon: React.ComponentType<{ className?: string }>
id?: string
}) => (
<a
className={`inline-flex gap-2 items-center px-6 py-4 font-medium text-white no-underline rounded-xl bg-[#060067] dark:bg-white dark:text-zinc-900 hover:opacity-90 ${
className || ''
}`}
href={href}
id={id}
>
<Icon className="w-5 h-5" /> {children}
</a>
)

export const WhiteButton = ({
children,
className,
href,
icon: Icon,
}: {
children: React.ReactNode
className?: string
href: string
icon: React.ComponentType<{ className?: string }>
}) => (
<a
className={`inline-flex gap-2 items-center px-6 py-4 text-base font-medium text-black no-underline bg-white rounded-xl border border-solid border-zinc-300 hover:bg-zinc-50 ${
className || ''
}`}
href={href}
>
<Icon className="w-5 h-5 text-black" /> {children}
</a>
)
38 changes: 38 additions & 0 deletions src/homepage2025/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Code, LogIn } from 'lucide-react'
import React from 'react'

import { BlackButton, WhiteButton } from './Buttons'

export const HeaderBar = () => {
return (
<header className="sticky top-0 z-40 border-b backdrop-blur bg-white/70 dark:bg-zinc-900/60 border-zinc-200/60 dark:border-zinc-800">
<div className="container flex justify-between items-center px-4 mx-auto max-w-7xl h-16">
<div className="flex gap-3 items-center">
<span className="text-2xl font-bold tracking-tight text-zinc-900 dark:text-zinc-100">SIV</span>
</div>
<nav className="hidden gap-6 items-center text-sm md:flex">
<a className="no-underline text-zinc-900 dark:text-zinc-100 hover:opacity-80" href="#how">
How it works
</a>
<a className="no-underline text-zinc-900 dark:text-zinc-100 hover:opacity-80" href="#security">
Security
</a>
<a className="no-underline text-zinc-900 dark:text-zinc-100 hover:opacity-80" href="#compare">
Contributors
</a>
<a className="no-underline text-zinc-900 dark:text-zinc-100 hover:opacity-80" href="#demo">
Live Demo
</a>
</nav>
<div className="flex gap-3 items-center">
<WhiteButton className="!px-4 !py-2 text-sm !rounded-md" href="https://hack.siv.org" icon={Code}>
Hack SIV
</WhiteButton>
<BlackButton className="!px-4 !py-2 text-sm !rounded-md" href="https://siv.org/login" icon={LogIn}>
Log In
</BlackButton>
</div>
</div>
</header>
)
}
127 changes: 127 additions & 0 deletions src/homepage2025/Hero.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { motion } from 'framer-motion'
import { CircleUserRound, ListTodo, QrCode } from 'lucide-react'
import Image from 'next/image'
import React from 'react'

import { BlackButton, WhiteButton } from './Buttons'

// Simple container
const Section = ({ children, className = '', id }: { children: React.ReactNode; className?: string; id?: string }) => (
<section className={`relative py-16 md:py-24 ${className}`} id={id}>
<div className="container px-4 mx-auto max-w-7xl">{children}</div>
</section>
)

const Card = ({ children, className = '' }: { children: React.ReactNode; className?: string }) => (
<div
className={`rounded-2xl p-6 md:p-8 shadow-[0_10px_40px_-12px_rgba(0,0,0,0.15)] bg-gradient-to-br from-white/90 via-white/80 to-zinc-50/90 dark:from-zinc-900/80 dark:via-zinc-900/70 dark:to-zinc-950/90 backdrop-blur-md border border-white/50 dark:border-zinc-800/50 transition-all duration-300 hover:shadow-[0_15px_50px_-12px_rgba(0,0,0,0.2)] hover:scale-[1.02] ${className}`}
>
{children}
</div>
)

const features = [
{
desc: 'Only eligible registered voters can vote, and only once.',
icon: CircleUserRound,
title: 'One Person, One Vote',
},
{
desc: 'Vote from own device, without needing to install anything.',
image: '/homepage2025/devices.png',
title: 'Vote in Seconds',
},
{
desc: 'No one can see how you vote, incl. servers & election admins.',
image: '/homepage2025/privacy.png',
title: 'Cryptographic Privacy',
},
{
desc: 'Even if the system is compromised, voters can easily verify their own votes and auditors can gather active proofs that the election gives correct results.',
image: '/homepage2025/checkmark.png',
title: 'Voter Verifiable Results',
},
]

export const Hero = () => {
return (
<Section className="overflow-hidden relative">
{/* Subtle gradient background overlay */}
<div className="absolute inset-0 bg-gradient-to-br to-transparent pointer-events-none from-indigo-50/40 via-violet-50/20 dark:from-indigo-950/20 dark:via-violet-950/10" />
<div className="absolute inset-0 bg-gradient-to-t via-transparent to-transparent pointer-events-none from-white/60 dark:from-zinc-950/60" />

{/* Subtle animated background elements */}
<div className="absolute top-20 -right-20 w-96 h-96 bg-gradient-to-br rounded-full blur-3xl pointer-events-none from-indigo-200/30 to-violet-200/20 dark:from-indigo-900/20 dark:to-violet-900/10" />
<div className="absolute bottom-20 -left-20 w-96 h-96 bg-gradient-to-tr rounded-full blur-3xl pointer-events-none from-blue-200/30 to-indigo-200/20 dark:from-blue-900/20 dark:to-indigo-900/10" />

<div className="relative">
<motion.div animate={{ opacity: 1, y: 0 }} initial={{ opacity: 0, y: 10 }} transition={{ duration: 0.5 }}>
<h1 className="text-4xl bg-gradient-to-r from-[#060067] via-[#1a0a8c] to-[#060067] bg-clip-text text-transparent tracking-tight leading-[1.15] pb-0.5 md:text-6xl md:leading-[1.15] dark:from-indigo-400 dark:via-violet-300 dark:to-indigo-400">
Zero‑trust digital voting
</h1>
<p className="mt-6 max-w-2xl text-lg leading-relaxed md:text-xl text-zinc-700 dark:text-zinc-300">
Everyone can verify whether an election was free & fair—
<br />
no advanced tech skills needed. Built to withstand nation‑state attacks.
</p>
<div className="flex flex-wrap gap-3 mt-10">
<BlackButton href="https://siv.org/login" icon={ListTodo} id="demo">
Create Election
</BlackButton>
<WhiteButton href="https://siv.org/login" icon={QrCode}>
Live Demo
</WhiteButton>
</div>
{/* <div className="flex gap-6 items-center mt-10">
<div className="text-3xl font-extrabold bg-gradient-to-r from-[#060067] to-indigo-700 bg-clip-text text-transparent md:text-4xl dark:from-indigo-400 dark:to-violet-300">
30,000+
</div>
<div className="text-zinc-700 dark:text-zinc-300">
votes cast in binding elections, including for a US Member of Congress
</div>
</div> */}
</motion.div>
<motion.div
animate={{ opacity: 1, y: 0 }}
className="mt-20 md:mt-28"
initial={{ opacity: 0, y: 10 }}
transition={{ duration: 0.6 }}
>
<div className="grid gap-4 sm:grid-cols-3">
{features.map((f, i) => (
<Card className={`relative text-center ${i === 3 ? 'col-span-full' : ''}`} key={i}>
{i < 3 && (
<div className="flex absolute -top-3 -left-3 z-10 justify-center items-center w-8 h-8 text-sm font-semibold text-white bg-[#060067] rounded-full shadow-lg dark:bg-zinc-100 dark:text-[#060067]">
{i + 1}
</div>
)}
<div className="flex justify-center items-center mx-auto w-12 h-12">
{f.icon ? (
<f.icon className="w-8 h-8" />
) : (
<Image alt="" className="object-contain w-12 h-12" height={48} src={f.image} width={48} />
)}
</div>
<h3 className="mt-3 font-semibold text-zinc-900 dark:text-zinc-100">{f.title}</h3>
{f.desc && (
<p
className={`mt-1 text-sm leading-relaxed text-zinc-600 dark:text-zinc-400 ${
i === 3 ? 'mx-auto max-w-3xl' : ''
}`}
>
{f.desc.split('\n').map((line, idx, arr) => (
<React.Fragment key={idx}>
{line}
{idx < arr.length - 1 && <br />}
</React.Fragment>
))}
</p>
)}
</Card>
))}
</div>
</motion.div>
</div>
</Section>
)
}
Loading