From b62334c429c995d99e1101ffee60209ebee9ab5f Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Wed, 10 Dec 2025 14:38:07 -0500 Subject: [PATCH] Draft redesign of the App --- app/src/components/Footer.tsx | 108 +++++++-- app/src/components/FooterSubscribe.tsx | 41 +++- app/src/components/Sidebar.tsx | 17 +- app/src/components/blog/BlogPostCard.tsx | 27 ++- app/src/components/common/EmptyState.tsx | 23 +- .../components/flowView/CardListVariant.tsx | 47 +++- app/src/components/home/ActionCards.tsx | 81 +++++-- app/src/components/home/MainSection.tsx | 79 ++++--- app/src/components/home/OrgLogos.tsx | 36 ++- app/src/components/homeHeader/NavItem.tsx | 68 +++++- app/src/components/shared/HomeHeader.tsx | 13 +- .../components/shared/static/HeroSection.tsx | 62 ++++-- app/src/components/sidebar/SidebarDivider.tsx | 3 +- app/src/components/sidebar/SidebarNavItem.tsx | 38 ++-- app/src/components/sidebar/SidebarSection.tsx | 6 +- app/src/designTokens/typography.ts | 3 +- app/src/main.tsx | 1 + app/src/pages/Home.page.tsx | 86 ++++++- app/src/styles/components.ts | 6 +- app/src/styles/globalStyles.css | 209 ++++++++++++++++++ 20 files changed, 791 insertions(+), 163 deletions(-) create mode 100644 app/src/styles/globalStyles.css diff --git a/app/src/components/Footer.tsx b/app/src/components/Footer.tsx index ee0976d79..b2ad953bc 100644 --- a/app/src/components/Footer.tsx +++ b/app/src/components/Footer.tsx @@ -10,7 +10,7 @@ import { import { Anchor, Box, Container, Group, SimpleGrid, Stack, Text } from '@mantine/core'; import type { CountryId } from '@/api/report'; import FooterSubscribe from '@/components/FooterSubscribe'; -import { colors, spacing, typography } from '@/designTokens'; +import { spacing, typography } from '@/designTokens'; import { useCurrentCountry } from '@/hooks/useCurrentCountry'; const PolicyEngineLogo = '/assets/logos/policyengine/white.svg'; @@ -20,8 +20,6 @@ const getContactLinks = (countryId: CountryId) => ({ donate: `/${countryId}/donate`, privacy: `/${countryId}/privacy`, terms: `/${countryId}/terms`, - // TODO: Add developer-tools page once it's built out - // developerTools: `/${countryId}/developer-tools`, }); const SOCIAL_LINKS = [ @@ -37,13 +35,34 @@ const SOCIAL_LINKS = [ export default function Footer() { const countryId = useCurrentCountry(); const CONTACT_LINKS = getContactLinks(countryId); + return ( - + {/* Decorative gradient orb */} + + + PolicyEngine { + e.currentTarget.style.color = '#4FD1C5'; + }} + onMouseLeave={(e) => { + e.currentTarget.style.color = 'rgba(255, 255, 255, 0.8)'; + }} > About us { + e.currentTarget.style.color = '#4FD1C5'; + }} + onMouseLeave={(e) => { + e.currentTarget.style.color = 'rgba(255, 255, 255, 0.8)'; + }} > Donate { + e.currentTarget.style.color = '#4FD1C5'; + }} + onMouseLeave={(e) => { + e.currentTarget.style.color = 'rgba(255, 255, 255, 0.8)'; + }} > Privacy policy { + e.currentTarget.style.color = '#4FD1C5'; + }} + onMouseLeave={(e) => { + e.currentTarget.style.color = 'rgba(255, 255, 255, 0.8)'; + }} > Terms and conditions - {/* TODO: Uncomment when developer-tools page is built - - Developer tools - - */} {SOCIAL_LINKS.map(({ icon: Icon, href }, index) => ( - - + { + e.currentTarget.style.color = '#4FD1C5'; + }} + onMouseLeave={(e) => { + e.currentTarget.style.color = 'rgba(255, 255, 255, 0.6)'; + }} + > + ))} - + © {new Date().getFullYear()} PolicyEngine. All rights reserved. diff --git a/app/src/components/FooterSubscribe.tsx b/app/src/components/FooterSubscribe.tsx index ac8a8615f..ac83dc276 100644 --- a/app/src/components/FooterSubscribe.tsx +++ b/app/src/components/FooterSubscribe.tsx @@ -40,10 +40,19 @@ export default function FooterSubscribe() { return ( - + Subscribe to PolicyEngine - + Get the latest posts delivered right to your inbox. @@ -54,17 +63,41 @@ export default function FooterSubscribe() { value={email} onChange={(event) => setEmail(event.currentTarget.value)} styles={{ - input: { backgroundColor: colors.white, flex: 1 }, + input: { + backgroundColor: 'rgba(255, 255, 255, 0.1)', + border: '1px solid rgba(79, 209, 197, 0.3)', + color: '#ffffff', + '&::placeholder': { + color: 'rgba(255, 255, 255, 0.5)', + }, + '&:focus': { + borderColor: '#4FD1C5', + }, + }, }} disabled={status === 'loading'} /> diff --git a/app/src/components/Sidebar.tsx b/app/src/components/Sidebar.tsx index df3914b4c..8e27fed0d 100644 --- a/app/src/components/Sidebar.tsx +++ b/app/src/components/Sidebar.tsx @@ -13,7 +13,7 @@ import { import { useLocation, useNavigate } from 'react-router-dom'; import { Box, Button, Stack } from '@mantine/core'; import { useCurrentCountry } from '@/hooks/useCurrentCountry'; -import { colors, spacing, typography } from '../designTokens'; +import { spacing, typography } from '../designTokens'; import SidebarDivider from './sidebar/SidebarDivider'; import SidebarNavItem from './sidebar/SidebarNavItem'; import SidebarSection from './sidebar/SidebarSection'; @@ -81,9 +81,9 @@ export default function Sidebar({ isOpen = true }: SidebarProps) { return ( navigate(`/${countryId}/reports/create`)} diff --git a/app/src/components/blog/BlogPostCard.tsx b/app/src/components/blog/BlogPostCard.tsx index de428ae9b..d83219959 100644 --- a/app/src/components/blog/BlogPostCard.tsx +++ b/app/src/components/blog/BlogPostCard.tsx @@ -51,20 +51,24 @@ export function BlogPostCard({ item, countryId }: BlogPostCardProps) { const cardContent = ( { - e.currentTarget.style.boxShadow = `0 4px 12px ${colors.gray[300]}`; + e.currentTarget.style.boxShadow = '0 8px 30px rgba(79, 209, 197, 0.15)'; + e.currentTarget.style.transform = 'translateY(-4px)'; + e.currentTarget.style.borderColor = 'rgba(79, 209, 197, 0.4)'; }} onMouseLeave={(e) => { e.currentTarget.style.boxShadow = 'none'; + e.currentTarget.style.transform = 'translateY(0)'; + e.currentTarget.style.borderColor = 'rgba(79, 209, 197, 0.2)'; }} > {/* Image */} @@ -83,6 +87,7 @@ export function BlogPostCard({ item, countryId }: BlogPostCardProps) { width: '100%', height: '100%', objectFit: 'cover', + transition: 'transform 0.3s ease', }} onError={(e) => { // Hide broken images @@ -105,7 +110,18 @@ export function BlogPostCard({ item, countryId }: BlogPostCardProps) { {displayTags.map((tag) => ( - + {tag} ))} @@ -130,8 +146,9 @@ export function BlogPostCard({ item, countryId }: BlogPostCardProps) { size="sm" mt="sm" style={{ - color: colors.primary[600], + color: '#0d9488', textAlign: 'right', + fontWeight: 500, }} > {item.isApp ? 'Open →' : 'Read →'} diff --git a/app/src/components/common/EmptyState.tsx b/app/src/components/common/EmptyState.tsx index 6562cc0eb..5be421d31 100644 --- a/app/src/components/common/EmptyState.tsx +++ b/app/src/components/common/EmptyState.tsx @@ -1,4 +1,4 @@ -import { Stack, Text } from '@mantine/core'; +import { Box, Stack, Text } from '@mantine/core'; interface EmptyStateProps { ingredient: string; // e.g., "Policy" @@ -8,11 +8,26 @@ interface EmptyStateProps { export default function EmptyState({ ingredient }: EmptyStateProps) { return ( - + + + ? + + + No {ingredient.toLowerCase()} found. - {/*
Please create {ingredient} to get started. */}
- {/* */}
); } diff --git a/app/src/components/flowView/CardListVariant.tsx b/app/src/components/flowView/CardListVariant.tsx index f81f98467..e15a9a039 100644 --- a/app/src/components/flowView/CardListVariant.tsx +++ b/app/src/components/flowView/CardListVariant.tsx @@ -32,25 +32,50 @@ export default function CardListVariant({ return ( {paginatedItems.map((item: CardListItem, index: number) => { - // Determine variant based on disabled state first, then selection - let variant = 'cardList--inactive'; - if (item.isDisabled) { - variant = 'cardList--disabled'; - } else if (item.isSelected) { - variant = 'cardList--active'; - } + const isSelected = item.isSelected; + const isDisabled = item.isDisabled; return ( { + if (!isDisabled) { + e.currentTarget.style.borderColor = '#4FD1C5'; + e.currentTarget.style.boxShadow = '0 4px 12px rgba(79, 209, 197, 0.15)'; + } + }} + onMouseLeave={(e) => { + if (!isDisabled) { + e.currentTarget.style.borderColor = isSelected + ? '#4FD1C5' + : 'rgba(79, 209, 197, 0.2)'; + e.currentTarget.style.boxShadow = 'none'; + } + }} > - {item.title} + + {item.title} + {item.subtitle && ( {item.subtitle} diff --git a/app/src/components/home/ActionCards.tsx b/app/src/components/home/ActionCards.tsx index a97c434ca..bc9c26f0c 100644 --- a/app/src/components/home/ActionCards.tsx +++ b/app/src/components/home/ActionCards.tsx @@ -1,6 +1,6 @@ import { useNavigate } from 'react-router-dom'; -import { Card, Center, Container, Text } from '@mantine/core'; -import { colors, spacing, typography } from '@/designTokens'; +import { Box, Center, Container, Group } from '@mantine/core'; +import { spacing, typography } from '@/designTokens'; import { useCurrentCountry } from '@/hooks/useCurrentCountry'; export default function ActionCards() { @@ -10,24 +10,71 @@ export default function ActionCards() { return (
- navigate(`/${countryId}/reports`)} + - - Enter PolicyEngine - - + + {/* Primary CTA */} + + + {/* Secondary CTA */} + + +
); diff --git a/app/src/components/home/MainSection.tsx b/app/src/components/home/MainSection.tsx index 24d0d3ad2..dbf49f497 100644 --- a/app/src/components/home/MainSection.tsx +++ b/app/src/components/home/MainSection.tsx @@ -1,5 +1,5 @@ -import { Container, Stack, Text, Title } from '@mantine/core'; -import { colors, spacing, typography } from '@/designTokens'; +import { Box, Container, Stack, Text } from '@mantine/core'; +import { spacing, typography } from '@/designTokens'; import { useCurrentCountry } from '@/hooks/useCurrentCountry'; export default function MainSection() { @@ -15,37 +15,64 @@ export default function MainSection() { maxWidth: spacing.layout.container, }} > - - Start simulating - +

+ Simulate the +
+ + future of policy + +

+
- - Free, open-source tax and benefit analysis. -
- {countryId === 'uk' - ? 'Model policy reforms across the UK.' - : 'Model policy reforms across all 50 states.'} -
- Power benefit access tools with accurate rules. -
+ + Free, open-source tax and benefit analysis. +
+ {countryId === 'uk' + ? 'Model policy reforms across the UK.' + : 'Model policy reforms across all 50 states.'} +
+ Power benefit access tools with accurate rules. +
+
); diff --git a/app/src/components/home/OrgLogos.tsx b/app/src/components/home/OrgLogos.tsx index f70e13b9e..b4ea5ea99 100644 --- a/app/src/components/home/OrgLogos.tsx +++ b/app/src/components/home/OrgLogos.tsx @@ -1,7 +1,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { Box, Flex, Text } from '@mantine/core'; import { CountryId, getOrgsForCountry, Organization } from '@/data/organizations'; -import { colors, spacing, typography } from '@/designTokens'; +import { spacing, typography } from '@/designTokens'; import { useCurrentCountry } from '@/hooks/useCurrentCountry'; const NUM_VISIBLE = 7; @@ -104,14 +104,30 @@ export default function OrgLogos() { const visibleOrgs = slotIndices.map((idx) => shuffledOrgs[idx]).filter(Boolean) as Organization[]; return ( - + {countryId === 'us' ? 'Trusted by researchers, policy organizations, and benefit platforms' @@ -144,9 +160,19 @@ export default function OrgLogos() { cursor: 'pointer', width: '120px', height: '100px', - opacity: transitioningSlot === i ? 0 : 1, + opacity: transitioningSlot === i ? 0 : 0.6, transition: 'opacity 0.3s ease-in-out', }} + onMouseEnter={(e) => { + if (transitioningSlot !== i) { + e.currentTarget.style.opacity = '1'; + } + }} + onMouseLeave={(e) => { + if (transitioningSlot !== i) { + e.currentTarget.style.opacity = '0.6'; + } + }} >