From 6e4eed8c27b2b44ba0dc0ad58ce60eda14992173 Mon Sep 17 00:00:00 2001 From: v0 Date: Wed, 11 Mar 2026 08:47:27 +0000 Subject: [PATCH] refactor: simplify landing page with ops features Remove marketing elements and add animated ops preview. Co-authored-by: Moheeb Zara <1184415+virgilvox@users.noreply.github.com> --- app/(landing)/page.tsx | 345 +++++++++++++++++++++-------------------- 1 file changed, 178 insertions(+), 167 deletions(-) diff --git a/app/(landing)/page.tsx b/app/(landing)/page.tsx index d3b4bac..c9610ef 100644 --- a/app/(landing)/page.tsx +++ b/app/(landing)/page.tsx @@ -16,11 +16,11 @@ function IcoFolder({ className }: { className?: string }) { function IcoCreditCard({ className }: { className?: string }) { return } -function IcoKey({ className }: { className?: string }) { - return +function IcoLock({ className }: { className?: string }) { + return } -function IcoChart({ className }: { className?: string }) { - return +function IcoDoc({ className }: { className?: string }) { + return } function IcoArrow({ className }: { className?: string }) { return @@ -28,8 +28,15 @@ function IcoArrow({ className }: { className?: string }) { function IcoTerminal({ className }: { className?: string }) { return } +function IcoEye({ className }: { className?: string }) { + return +} +function IcoPin({ className }: { className?: string }) { + return +} + +// ─── Mini UI Previews ────────────────────────────────────────────────────────── -// Mini UI Components with animations function MiniMemberTable() { const [activeRow, setActiveRow] = useState(0) const members = [ @@ -38,14 +45,10 @@ function MiniMemberTable() { { name: 'Sam Rivera', tier: 'PLUS', status: 'late' }, { name: 'Casey Wong', tier: 'BASIC', status: 'current' }, ] - useEffect(() => { - const interval = setInterval(() => { - setActiveRow((prev) => (prev + 1) % members.length) - }, 2000) - return () => clearInterval(interval) + const t = setInterval(() => setActiveRow(p => (p + 1) % members.length), 2000) + return () => clearInterval(t) }, [members.length]) - return (
@@ -54,17 +57,12 @@ function MiniMemberTable() {
{members.map((m, i) => ( -
-
+
+
{m.name.split(' ').map(n => n[0]).join('')}
{m.name} - {m.tier} + {m.tier}
))} @@ -77,20 +75,15 @@ function MiniTaskList() { const [checkedIndex, setCheckedIndex] = useState(-1) const tasks = [ { title: 'Clean laser cutter lens', area: 'Laser' }, - { title: 'Restock filament', area: '3D Printing' }, + { title: 'Restock filament', area: '3D Print' }, { title: 'Update wiki docs', area: 'Admin' }, ] - useEffect(() => { - const interval = setInterval(() => { - setCheckedIndex((prev) => { - if (prev >= tasks.length - 1) return -1 - return prev + 1 - }) + const t = setInterval(() => { + setCheckedIndex(p => (p >= tasks.length - 1 ? -1 : p + 1)) }, 1500) - return () => clearInterval(interval) + return () => clearInterval(t) }, [tasks.length]) - return (
@@ -100,18 +93,14 @@ function MiniTaskList() {
{tasks.map((t, i) => (
-
+
{i <= checkedIndex && ( )}
- - {t.title} - + {t.title} {t.area}
))} @@ -122,16 +111,11 @@ function MiniTaskList() { function MiniProjectBoard() { const [movingCard, setMovingCard] = useState(0) - useEffect(() => { - const interval = setInterval(() => { - setMovingCard((prev) => (prev + 1) % 3) - }, 2500) - return () => clearInterval(interval) + const t = setInterval(() => setMovingCard(p => (p + 1) % 3), 2500) + return () => clearInterval(t) }, []) - const columns = ['BACKLOG', 'IN PROGRESS', 'DONE'] - return (
@@ -141,10 +125,8 @@ function MiniProjectBoard() { {columns.map((col, colIndex) => (
- - {col} + + {col}
{colIndex === movingCard && (
@@ -154,9 +136,9 @@ function MiniProjectBoard() {
)} - {colIndex !== movingCard && colIndex === 1 && ( -
-

Placeholder

+ {colIndex === 1 && colIndex !== movingCard && ( +
+

Network rack

)}
@@ -168,14 +150,10 @@ function MiniProjectBoard() { function MiniPayments() { const [linking, setLinking] = useState(false) - useEffect(() => { - const interval = setInterval(() => { - setLinking((prev) => !prev) - }, 2000) - return () => clearInterval(interval) + const t = setInterval(() => setLinking(p => !p), 2000) + return () => clearInterval(t) }, []) - return (
@@ -186,9 +164,7 @@ function MiniPayments() {
PAYPAL $50.00 - + {linking ? 'LINKED' : '+ LINK'}
@@ -202,36 +178,132 @@ function MiniPayments() { ) } -function MiniStats() { - const [count, setCount] = useState(47) - +function MiniOps() { + const [revealedIndex, setRevealedIndex] = useState(-1) + const [tab, setTab] = useState<'secrets' | 'kb'>('secrets') + + const secrets = [ + { label: 'WiFi Password', area: 'Network' }, + { label: 'Alarm Code', area: 'Security' }, + { label: 'PayPal API Key', area: 'Finance' }, + ] + const kb = [ + { title: 'Open / Close Procedure', area: 'Ops', pinned: true }, + { title: 'Laser Cutter Safety', area: 'Laser', pinned: false }, + { title: 'Board Meeting Runbook', area: 'Admin', pinned: true }, + ] + useEffect(() => { - const interval = setInterval(() => { - setCount((prev) => prev + Math.floor(Math.random() * 3) - 1) - }, 3000) - return () => clearInterval(interval) + if (tab !== 'secrets') return + const t = setInterval(() => { + setRevealedIndex(p => (p >= secrets.length - 1 ? -1 : p + 1)) + }, 1800) + return () => clearInterval(t) + }, [tab, secrets.length]) + + useEffect(() => { + const t = setInterval(() => { + setTab(p => (p === 'secrets' ? 'kb' : 'secrets')) + setRevealedIndex(-1) + }, 5000) + return () => clearInterval(t) }, []) - + + return ( +
+
+ Ops +
+
+ {(['secrets', 'kb'] as const).map(t => ( + + ))} +
+
+ {tab === 'secrets' && secrets.map((s, i) => ( +
+
+ +
+ {s.label} + {s.area} +
+ + {i === revealedIndex ? ( + ••••1234 + ) : ( + reveal + )} +
+
+ ))} + {tab === 'kb' && kb.map((k) => ( +
+
+ +
+ {k.title} + {k.pinned && } + {k.area} +
+ ))} +
+
+ ) +} + +function MiniDashboard() { + const [tick, setTick] = useState(0) + useEffect(() => { + const t = setInterval(() => setTick(p => p + 1), 3000) + return () => clearInterval(t) + }, []) + const members = 47 + (tick % 3) return (
- MEMBERS + Members
-

{count}

+

{members}

- TASKS + Tasks

12

+
+
+ Due this week + 3 late +
+
+ {Array.from({ length: 12 }).map((_, i) => ( +
+ ))} +
+
) } +// ─── Main Landing Page ───────────────────────────────────────────────────────── + export default function LandingPage() { return (
@@ -259,21 +331,21 @@ export default function LandingPage() {

- Operational Software for Makerspaces + Operational software for makerspaces

Run your hackerspace like the infrastructure it is

- Member management, dues tracking, task coordination, and project visibility. Built by people who have actually run these spaces. + Member management, dues tracking, task coordination, project visibility, and a shared ops brain for the things that keep the space running.

- Start Free + Get Started - - See Features + + Log in
@@ -281,7 +353,7 @@ export default function LandingPage() {
- +
@@ -293,35 +365,16 @@ export default function LandingPage() {
- {/* Stats bar */} -
-
-
- {[ - { label: 'Spaces running', value: '40+' }, - { label: 'Members managed', value: '2,800+' }, - { label: 'Tasks completed', value: '15k+' }, - { label: 'Payments tracked', value: '$380k+' }, - ].map((stat) => ( -
-

{stat.value}

-

{stat.label}

-
- ))} -
-
-
- {/* Features */}
-
+

Features

Everything your space needs, nothing it does not

-

- No bloated enterprise features. No learning curve. Just tools that match how hackerspaces actually operate. +

+ No bloated enterprise features. No learning curve. Tools that match how hackerspaces actually operate.

@@ -330,7 +383,7 @@ export default function LandingPage() { { Icon: IcoUsers, title: 'Member Directory', - description: 'Track membership tiers, payment status, access credentials, and contact info. Bulk actions for common operations.', + description: 'Track membership tiers, payment status, and contact info. Bulk actions for common operations. Know who is current and who is not.', preview: , }, { @@ -342,46 +395,26 @@ export default function LandingPage() { { Icon: IcoFolder, title: 'Project Tracking', - description: 'Kanban board for space projects. Track progress, assign areas, and keep the community informed about ongoing work.', + description: 'Kanban board for space projects. Track progress, assign areas, and keep the community informed about what is in motion.', preview: , }, { Icon: IcoCreditCard, title: 'Payment Reconciliation', - description: 'Import from PayPal, Venmo, and Zeffy. Link transactions to members. Know exactly who owes what without spreadsheet hell.', + description: 'Import from PayPal, Venmo, and Zeffy. Link transactions to members. Know exactly who owes what without the spreadsheet.', preview: , }, { - Icon: IcoKey, - title: 'Access Control', - description: 'Track key cards, door codes, and 24/7 access privileges. Integrated with member status so access stays current.', - preview: ( -
-
- Access Logs -
-
- {[ - { name: 'A. Chen', time: '2:34 PM', door: 'Main' }, - { name: 'J. Mills', time: '1:12 PM', door: 'Shop' }, - { name: 'S. Rivera', time: '11:45 AM', door: 'Main' }, - ].map((log) => ( -
- - {log.name} - {log.door} - {log.time} -
- ))} -
-
- ), + Icon: IcoLock, + title: 'Ops: Secrets and KB', + description: 'Store WiFi passwords, alarm codes, API keys, and procedures in one place. Role-based visibility. Reveal on demand.', + preview: , }, { - Icon: IcoChart, + Icon: IcoDoc, title: 'Dashboard', - description: 'At a glance status on membership, open tasks, payment issues, and recent activity. Know what needs attention.', - preview: , + description: 'At a glance status on membership, open tasks, payment issues, and recent activity. Know what needs attention when you log in.', + preview: , }, ].map((feature) => (
@@ -406,32 +439,31 @@ export default function LandingPage() { {/* How it works */}
-
-

How it works

+
+

Setup

- From chaos to clarity in under an hour + From nothing to running in under an hour

-
{[ { step: '01', title: 'Import your members', - description: 'Paste from a spreadsheet or add them one by one. We handle the messy data.', + description: 'Paste from a spreadsheet or add them one by one. Set tiers, statuses, and contact info.', }, { step: '02', title: 'Connect payments', - description: 'Link your PayPal or Zeffy account. Transactions import automatically.', + description: 'Link your PayPal or Zeffy account. Transactions import and sit waiting to be matched to members.', }, { step: '03', - title: 'Invite your board', - description: 'Add admins and treasurers. Everyone sees what they need to see.', + title: 'Seed your ops docs', + description: 'Drop in your SOPs, credentials, and area leads. The whole board has one place to look things up.', }, ].map((item) => ( -
+

{item.step}

{item.title}

{item.description}

@@ -441,36 +473,23 @@ export default function LandingPage() {
- {/* Testimonial */} -
-
-
- "We went from a shared Google Sheet that nobody updated to actually knowing who was current on dues. Game changer for our monthly board meetings." -
-
-

Marcus Webb

-

Treasurer, FreeGeek Chicago

-
-
-
- {/* CTA */}
-
+

Your space deserves better than spreadsheets

-

- Free for spaces under 25 members. No credit card required. Set up in minutes. +

+ A tool built specifically for volunteer-run makerspaces and hackerspaces. Not adapted from something else.

-
- - Start Free +
+ + Get Started - - Contact Us - + + Log in +
@@ -478,22 +497,14 @@ export default function LandingPage() { {/* Footer */}