open-navigator / web_app /src /data /homeQuickNavFlyouts.tsx
jcbowyer's picture
Clean HuggingFace deployment without binary files
e59d91d
Raw
History Blame Contribute Delete
10.3 kB
import type { ReactNode } from 'react'
import type { HomeQuickNavGroupId } from './exploreActionPhases'
import { CAUSES } from './causes'
const S = '#2d6b65'
function Ico({ children, stroke = S }: { children: ReactNode; stroke?: string }) {
return (
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={stroke} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
{children}
</svg>
)
}
export const flyoutIcons = {
roads: (stroke = S) => (
<Ico stroke={stroke}>
<path d="M3 17l6-12 6 12" />
<path d="M9 17l6-12 6 12" />
</Ico>
),
schools: (stroke = S) => (
<Ico stroke={stroke}>
<path d="M22 10v6M2 10l10-5 10 5-10 5z" />
<path d="M6 12v5c3 3 9 3 12 0v-5" />
</Ico>
),
safety: (stroke = S) => (
<Ico stroke={stroke}>
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
</Ico>
),
family: (stroke = S) => (
<Ico stroke={stroke}>
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" />
<circle cx="9" cy="7" r="4" />
<path d="M23 21v-2a4 4 0 0 0-3-3.87" />
<path d="M16 3.13a4 4 0 0 1 0 7.75" />
</Ico>
),
health: (stroke = S) => (
<Ico stroke={stroke}>
<path d="M22 12h-4l-3 9L9 3l-3 9H2" />
</Ico>
),
other: (stroke = S) => (
<Ico stroke={stroke}>
<circle cx="12" cy="12" r="10" />
<line x1="12" y1="16" x2="12" y2="12" />
<line x1="12" y1="8" x2="12.01" y2="8" />
</Ico>
),
person: (stroke = S) => (
<Ico stroke={stroke}>
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
<circle cx="12" cy="7" r="4" />
</Ico>
),
globe: (stroke = S) => (
<Ico stroke={stroke}>
<circle cx="12" cy="12" r="10" />
<line x1="2" y1="12" x2="22" y2="12" />
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
</Ico>
),
people: (stroke = S) => (
<Ico stroke={stroke}>
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" />
<circle cx="9" cy="7" r="4" />
<path d="M23 21v-2a4 4 0 0 0-3-3.87" />
<path d="M16 3.13a4 4 0 0 1 0 7.75" />
</Ico>
),
target: (stroke = S) => (
<Ico stroke={stroke}>
<circle cx="12" cy="12" r="10" />
<circle cx="12" cy="12" r="6" />
<circle cx="12" cy="12" r="2" />
</Ico>
),
building: (stroke = S) => (
<Ico stroke={stroke}>
<rect x="4" y="2" width="16" height="20" rx="2" ry="2" />
<path d="M9 22v-4h6v4" />
<path d="M8 6h.01M12 6h.01M16 6h.01M8 10h.01M12 10h.01M16 10h.01M8 14h.01M12 14h.01M16 14h.01" />
</Ico>
),
capitol: (stroke = S) => (
<Ico stroke={stroke}>
<path d="M3 21h18M5 21V7l7-4 7 4v14M9 21v-4h6v4" />
<path d="M9 10h6M9 14h6" />
</Ico>
),
dollar: (stroke = S) => (
<Ico stroke={stroke}>
<line x1="12" y1="1" x2="12" y2="23" />
<path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" />
</Ico>
),
phone: (stroke = S) => (
<Ico stroke={stroke}>
<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.69 13a19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 3.6 2.18h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L7.91 9.91a16 16 0 0 0 6.06 6.06l.9-.9a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 21.73 17z" />
</Ico>
),
vote: (stroke = S) => (
<Ico stroke={stroke}>
<path d="M9 11l3 3L22 4" />
<path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11" />
</Ico>
),
monitor: (stroke = S) => (
<Ico stroke={stroke}>
<rect x="2" y="3" width="20" height="14" rx="2" ry="2" />
<line x1="8" y1="21" x2="16" y2="21" />
<line x1="12" y1="17" x2="12" y2="21" />
</Ico>
),
calendar: (stroke = S) => (
<Ico stroke={stroke}>
<rect x="3" y="4" width="18" height="18" rx="2" ry="2" />
<line x1="16" y1="2" x2="16" y2="6" />
<line x1="8" y1="2" x2="8" y2="6" />
<line x1="3" y1="10" x2="21" y2="10" />
</Ico>
),
bell: (stroke = S) => (
<Ico stroke={stroke}>
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" />
<path d="M13.73 21a2 2 0 0 1-3.46 0" />
</Ico>
),
database: (stroke = S) => (
<Ico stroke={stroke}>
<ellipse cx="12" cy="5" rx="9" ry="3" />
<path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3" />
<path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5" />
</Ico>
),
lightning: (stroke = S) => (
<Ico stroke={stroke}>
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" />
</Ico>
),
code: (stroke = S) => (
<Ico stroke={stroke}>
<polyline points="16 18 22 12 16 6" />
<polyline points="8 6 2 12 8 18" />
</Ico>
),
globeAlt: (stroke = S) => (
<Ico stroke={stroke}>
<circle cx="12" cy="12" r="10" />
<line x1="2" y1="12" x2="22" y2="12" />
<path d="M12 2a14.5 14.5 0 0 1 0 20 14.5 14.5 0 0 1 0-20" />
</Ico>
),
} as const
export type FlyoutIconKey = keyof typeof flyoutIcons
export type HomeFlyoutItem = {
id: string
label: string
description: string
tag: string
hot?: boolean
to: string
external?: boolean
iconKey: FlyoutIconKey
}
function apiDocsUrl(): string {
return import.meta.env.PROD ? 'https://www.communityone.com/api/docs' : 'http://localhost:8001/docs'
}
function causesToReportFlyoutItems(): HomeFlyoutItem[] {
return CAUSES.map((c) => ({
id: c.id,
iconKey: c.iconKey,
label: c.label,
description: c.desc,
tag: c.tag,
hot: c.hot,
to: c.to,
external: c.to.startsWith('http'),
}))
}
export const HOME_QUICK_NAV_FLYOUTS: Record<HomeQuickNavGroupId, HomeFlyoutItem[]> = {
cause: causesToReportFlyoutItems(),
plan: [
{
id: 'personal',
iconKey: 'person',
label: 'Personal Path',
description: 'I need help — find services and information for me',
tag: 'For me',
to: '/services',
},
{
id: 'macro',
iconKey: 'globe',
label: 'Macro Path',
description: 'I want to create change in my community',
tag: 'For my community',
hot: true,
to: '/explore',
},
{
id: 'professional',
iconKey: 'capitol',
label: 'Professional Path',
description: 'State legislators, county administrators, and nonprofit champions',
tag: 'For my role',
to: '/explore#explore-plan-path',
},
{
id: 'allies',
iconKey: 'people',
label: 'Identify Allies',
description: 'Find officials, nonprofits, and neighbors fighting for your cause',
tag: 'Strategy',
to: '/people',
},
{
id: 'success',
iconKey: 'target',
label: 'Define Success',
description: 'Set measurable goals and track your progress',
tag: 'Outcomes',
to: '/analytics',
},
],
find: [
{
id: 'np',
iconKey: 'building',
label: 'Nonprofits Near Me',
description: '1.8M organizations mapped across 5 states',
tag: 'Free',
to: '/nonprofits',
},
{
id: 'officials',
iconKey: 'capitol',
label: 'Elected Officials',
description: 'Voting records, contact info, decision patterns',
tag: '75K+ leaders',
to: '/people',
},
{
id: 'grants',
iconKey: 'dollar',
label: 'Grants & Funding',
description: 'Federal, state, and foundation opportunities',
tag: '1,000s available',
// Grants search: historical 990 grantmaking + open Grants.gov funding.
// (The bare /opportunities route is the unrelated advocacy-opportunities page.)
to: '/search?types=grants,grant_opportunities',
},
{
id: 'svc',
iconKey: 'phone',
label: 'Community Services',
description: 'Government services, hotlines, local resources',
tag: 'Services',
to: '/services',
},
],
track: [
{
id: 'vote',
iconKey: 'vote',
label: 'Vote Tracker',
description: 'How officials voted on issues that matter to you',
tag: 'Real-time',
hot: true,
to: '/documents',
},
{
id: 'budget',
iconKey: 'monitor',
label: 'Budget Watch',
description: 'Flag when line items shift year over year',
tag: 'Analysis',
to: '/analytics',
},
{
id: 'meetings',
iconKey: 'calendar',
label: 'Upcoming Meetings',
description: 'Agendas, dates, how to attend or comment',
tag: '90K+ jurisdictions',
to: '/events',
},
{
id: 'alerts',
iconKey: 'bell',
label: 'Set Alerts',
description: 'Get notified when your keywords hit an agenda',
tag: 'Free',
to: '/search',
},
],
build: [
{
id: 'data-explorer',
iconKey: 'globeAlt',
label: 'Explore data',
description: 'ACS map and scorecard — national, state, and place trends',
tag: 'Interactive',
hot: true,
to: '/data-explorer',
},
{
id: 'hf',
iconKey: 'database',
label: 'HuggingFace Datasets',
description: 'Meeting transcripts, legislation — MIT license',
tag: 'Open source',
hot: true,
to: 'https://huggingface.co/datasets/CommunityOne/open-navigator-data',
external: true,
},
{
id: 'playbooks',
iconKey: 'lightning',
label: 'Strategy Playbooks',
description: 'Fork civic tools: vote tracker, meeting monitor',
tag: 'GitHub',
to: '/opensource',
},
{
id: 'api',
iconKey: 'code',
label: 'API Reference',
description: 'Query jurisdictions, decisions, and nonprofits',
tag: 'Developers',
to: '__API_DOCS__',
external: true,
},
{
id: 'ecosystem',
iconKey: 'globeAlt',
label: 'Civic Tech Ecosystem',
description: 'Code for America, OpenStates, MySociety',
tag: 'Community',
to: 'https://www.openstates.org/',
external: true,
},
],
}
/** Resolve special `to` tokens after import.meta is available */
export function resolveHomeFlyoutHref(to: string): string {
if (to === '__API_DOCS__') return apiDocsUrl()
return to
}
export function homeQuickNavFlyoutItems(id: HomeQuickNavGroupId): HomeFlyoutItem[] {
return HOME_QUICK_NAV_FLYOUTS[id]
}