Skip to content

Commit

Permalink
Add language switch menu + restyle top bar + breakpoint pagination (#33)
Browse files Browse the repository at this point in the history
* Add language switch menu + restyle top bar

* Limit pagination buttons to 6 for mobile devices

* Create custom RoutedPagination with maxButtons breakpoint definition
  • Loading branch information
elboletaire authored Jul 2, 2024
1 parent 519e274 commit f894758
Show file tree
Hide file tree
Showing 20 changed files with 166 additions and 87 deletions.
4 changes: 2 additions & 2 deletions src/components/Blocks/BlockCard.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Box, Card, CardBody, Flex, Link, Text } from '@chakra-ui/react'
import { Trans } from 'react-i18next'
import { ReducedTextAndCopy } from '~components/CopyButton'
import { useDateFns } from '~i18n/use-date-fns'
import { generatePath, Link as RouterLink } from 'react-router-dom'
import { ReducedTextAndCopy } from '~components/Layout/CopyButton'
import { RoutePath } from '~constants'
import { useDateFns } from '~i18n/use-date-fns'

export const BlockCard = ({ height, time, proposer }: { height: number; time: string; proposer: string }) => {
const date = new Date(time)
Expand Down
14 changes: 7 additions & 7 deletions src/components/Blocks/BlocksList.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { keepPreviousData } from '@tanstack/react-query'
import { useTranslation } from 'react-i18next'
import { generatePath, useNavigate, useParams } from 'react-router-dom'
import { RoutedPagination } from '~components/Pagination/Pagination'
import { RoutedPaginationProvider } from '~components/Pagination/PaginationProvider'
import { PaginationItemsPerPage, RefreshIntervalBlocks, RoutePath } from '~constants'
import { BlockCard } from '~components/Blocks/BlockCard'
import { InputSearch } from '~components/Layout/Inputs'
import { LoadingCards } from '~components/Layout/Loading'
import LoadingError from '~components/Layout/LoadingError'
import { RoutedPaginationProvider } from '~components/Pagination/PaginationProvider'
import { RoutedPagination } from '~components/Pagination/RoutedPagination'
import { PaginationItemsPerPage, RefreshIntervalBlocks, RoutePath } from '~constants'
import { useBlockList } from '~queries/blocks'
import { useChainInfo } from '~queries/stats'
import { BlockCard } from '~components/Blocks/BlockCard'
import { useTranslation } from 'react-i18next'
import { InputSearch } from '~components/Layout/Inputs'
import { keepPreviousData } from '@tanstack/react-query'

export const BlocksFilter = () => {
const { t } = useTranslation()
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
57 changes: 57 additions & 0 deletions src/components/Layout/Languages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Button, Menu, MenuButton, MenuItem, MenuList, MenuProps } from '@chakra-ui/react'
import { useTranslation } from 'react-i18next'
import { FaChevronDown, FaChevronUp, FaGlobeAmericas } from 'react-icons/fa'
import languages from '~i18n/languages.mjs'

export const LanguagesList = () => {
const { i18n } = useTranslation()

const isAnyLanguageSelected =
Object.keys(languages).some((l) => l === i18n.language) && languages.includes(i18n.language)

return (
<>
{languages.map((k: string) => (
<MenuItem
key={k}
onClick={() => {
i18n.changeLanguage(k)
}}
display='flex'
justifyContent='center'
fontWeight={k === i18n.language ? 'bold' : ''}
borderRadius='none'
>
{k.toUpperCase()}
</MenuItem>
))}
</>
)
}

export const LanguagesMenu = (props: Omit<MenuProps, 'children'>) => {
const { t } = useTranslation()

return (
<Menu>
{({ isOpen }) => (
<>
<MenuButton
as={Button}
aria-label={t('menu.burger_aria_label')}
variant='rounded-ghost'
sx={{ span: { margin: 'px' } }}
rightIcon={isOpen ? <FaChevronUp /> : <FaChevronDown />}
minW='none'
size='sm'
>
<FaGlobeAmericas />
</MenuButton>
<MenuList minW={16} mt={2}>
<LanguagesList />
</MenuList>
</>
)}
</Menu>
)
}
2 changes: 1 addition & 1 deletion src/components/Layout/ShowRawButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Box, BoxProps, Button, ButtonProps, useDisclosure } from '@chakra-ui/react'
import { Trans } from 'react-i18next'
import { CopyButtonIcon } from '~components/CopyButton'
import { CopyButtonIcon } from '~components/Layout/CopyButton'
import { JsonViewer } from '~components/Layout/JsonViewer'

const ShowRawButton = ({ obj, ...props }: { obj: object } & Omit<ButtonProps, 'onClick'>) => {
Expand Down
74 changes: 44 additions & 30 deletions src/components/TopBar.tsx β†’ src/components/Layout/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import {
} from '@chakra-ui/react'
import { useTranslation } from 'react-i18next'
import { RxHamburgerMenu } from 'react-icons/rx'
import { generatePath, Link as RouterLink } from 'react-router-dom'
import { generatePath, Link as RouterLink, useLocation } from 'react-router-dom'
import { RoutePath, VocdoniEnvironment } from '~constants'

import { LanguagesMenu } from './Languages'
import logoDevUrl from '/images/logo-header-dev.png'
import logoStgUrl from '/images/logo-header-stg.png'
import logoUrl from '/images/logo-header.png'
Expand All @@ -29,6 +30,7 @@ interface HeaderLink {
export const TopBar = () => {
const isSmallScreen = useBreakpointValue({ base: true, lg: false })
const { t } = useTranslation()
const location = useLocation()
const env = VocdoniEnvironment

let headerUrl
Expand All @@ -46,83 +48,95 @@ export const TopBar = () => {

const links: HeaderLink[] = [
{
name: t('links.organizations'),
name: t('links.organizations', { defaultValue: 'Organizations' }),
url: generatePath(RoutePath.OrganizationsList, { page: null, query: null }),
},
{
name: t('links.processes'),
name: t('links.processes', { defaultValue: 'Processes' }),
url: generatePath(RoutePath.ProcessesList, { page: null }),
},
{
name: t('links.blocks'),
name: t('links.blocks', { defaultValue: 'Blocks' }),
url: generatePath(RoutePath.BlocksList, { page: null }),
},
{
name: t('links.transactions'),
name: t('links.transactions', { defaultValue: 'Transactions' }),
url: generatePath(RoutePath.TransactionsList, { page: null }),
},
{
name: t('links.validators'),
name: t('links.validators', { defaultValue: 'Validators' }),
url: generatePath(RoutePath.Validators),
},
]

const rightLinks: HeaderLink[] = [
{
name: t('links.verify_vote'),
name: t('links.verify_vote', { defaultValue: 'Verify vote' }),
url: generatePath(RoutePath.Verify, { verifier: null }),
},
]

const isActive = (link: HeaderLink) => location.pathname === link.url

return (
<Box
as='header'
width='100%'
w='full'
zIndex='100'
minHeight='50px'
top='0'
padding='10px 0'
backdropFilter='blur(10px)'
bg='white'
px={{ base: 4, md: 8 }}
>
<Flex justifyContent='space-between' alignItems='start' flexWrap='wrap' px={{ base: 4, md: 8 }}>
<Flex alignItems='center'>
<Link as={RouterLink} to={'/'}>
<Image src={headerUrl} alt='Vocdoni' marginTop='6px' maxHeight='45px' maxWidth='200px' />
</Link>
<Flex w='full' gap={5}>
<Link as={RouterLink} to={'/'}>
<Image src={headerUrl} alt='Vocdoni' maxW='200px' />
</Link>

<Flex display={isSmallScreen ? 'none' : 'flex'} gap={4} marginLeft='20px' wrap={'wrap'}>
<Flex gap={4} w='full' display={isSmallScreen ? 'none' : 'flex'}>
<Flex gap={4} alignItems='center'>
{links.map((link, i) => (
<Link key={i} as={RouterLink} to={link.url}>
<Button variant='link' key={i} as={RouterLink} to={link.url} isActive={isActive(link)}>
{link.name}
</Link>
</Button>
))}
</Flex>
<Box ml='auto' display='flex'>
<LanguagesMenu />
<Flex alignItems='center'>
{rightLinks.map((link, i) => (
<Button as={RouterLink} size='sm' key={i} to={link.url}>
{link.name}
</Button>
))}
</Flex>
</Box>
</Flex>

{isSmallScreen ? (
<Box pr={2}>
{isSmallScreen && (
<Box pr={2} ml='auto'>
<LanguagesMenu />
<Menu>
<MenuButton as={IconButton} aria-label='Options' icon={<RxHamburgerMenu />} variant='outline' />
<MenuButton as={IconButton} aria-label='Menu' icon={<RxHamburgerMenu />} variant='outline' />
<MenuList>
{[...links, ...rightLinks].map((link) => (
<MenuItem key={link.name}>
<Link as={RouterLink} to={link.url}>
<Button
variant='link'
justifyContent='start'
as={RouterLink}
w='full'
to={link.url}
isActive={isActive(link)}
>
{link.name}
</Link>
</Button>
</MenuItem>
))}
</MenuList>
</Menu>
</Box>
) : (
<Flex alignItems='center'>
{rightLinks.map((link, i) => (
<Button as={RouterLink} key={i} to={link.url}>
{link.name}
</Button>
))}
</Flex>
)}
</Flex>
</Box>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Organizations/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { Box, Card, CardBody, CardProps, Link, Text } from '@chakra-ui/react'
import { OrganizationImage as Avatar, OrganizationName } from '@vocdoni/chakra-components'
import { OrganizationProvider, useOrganization } from '@vocdoni/react-providers'
import { Trans, useTranslation } from 'react-i18next'
import { generatePath, Link as RouterLink } from 'react-router-dom'
import { ReducedTextAndCopy } from '~components/CopyButton'
import { Link as RouterLink, generatePath } from 'react-router-dom'
import { ReducedTextAndCopy } from '~components/Layout/CopyButton'
import { FallbackAccountImg, RoutePath } from '~constants'

type IOrganizationCardProps = {
Expand Down
10 changes: 5 additions & 5 deletions src/components/Organizations/Detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ import { OrganizationDescription, OrganizationHeader, OrganizationName } from '@
import { useOrganization } from '@vocdoni/react-providers'
import { AccountData, ensure0x, PublishedElection } from '@vocdoni/sdk'
import { Trans } from 'react-i18next'
import { AppBaseURL, FallbackHeaderImg, PaginationItemsPerPage } from '~constants'
import { FaUserAlt } from 'react-icons/fa'
import { CopyButton, ReducedTextAndCopy } from '~components/CopyButton'
import { CopyButton, ReducedTextAndCopy } from '~components/Layout/CopyButton'
import { HeroHeaderLayout } from '~components/Layout/HeroHeaderLayout'
import { LoadingCards } from '~components/Layout/Loading'
import ShowRawButton from '~components/Layout/ShowRawButton'
import { Pagination } from '~components/Pagination/Pagination'
import { PaginationProvider, usePagination } from '~components/Pagination/PaginationProvider'
import { ElectionCard } from '~components/Process/Card'
import { AppBaseURL, FallbackHeaderImg, PaginationItemsPerPage } from '~constants'
import { useOrganizationElections } from '~queries/organizations'
import { LoadingCards } from '~components/Layout/Loading'
import ShowRawButton from '~components/Layout/ShowRawButton'
import { HeroHeaderLayout } from '~components/Layout/HeroHeaderLayout'

const OrganizationDetail = () => {
const { organization: org } = useOrganization()
Expand Down
10 changes: 5 additions & 5 deletions src/components/Organizations/List.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { keepPreviousData } from '@tanstack/react-query'
import { useTranslation } from 'react-i18next'
import { generatePath, useNavigate, useParams } from 'react-router-dom'
import { InputSearch } from '~components/Layout/Inputs'
import { LoadingCards } from '~components/Layout/Loading'
import LoadingError from '~components/Layout/LoadingError'
import { OrganizationCard } from '~components/Organizations/Card'
import { RoutedPagination } from '~components/Pagination/Pagination'
import { RoutedPaginationProvider } from '~components/Pagination/PaginationProvider'
import { RoutedPagination } from '~components/Pagination/RoutedPagination'
import { PaginationItemsPerPage, RoutePath } from '~constants'
import { useOrganizationCount, useOrganizationList } from '~queries/organizations'
import { InputSearch } from '~components/Layout/Inputs'
import { LoadingCards } from '~components/Layout/Loading'
import LoadingError from '~components/Layout/LoadingError'
import { keepPreviousData } from '@tanstack/react-query'

export const OrganizationsFilter = () => {
const { t } = useTranslation()
Expand Down
9 changes: 9 additions & 0 deletions src/components/Pagination/RoutedPagination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { useBreakpointValue } from '@chakra-ui/react'
import { RoutedPagination as Pagination, PaginationProps } from './Pagination'

// Note this component is a custom definition of the pagination component that will end in chakra-components
export const RoutedPagination = (props: PaginationProps) => {
const maxButtons = useBreakpointValue({ base: 6, lg: 10 })

return <Pagination {...props} maxButtons={maxButtons} />
}
4 changes: 2 additions & 2 deletions src/components/Process/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { OrganizationImage as Avatar, ElectionSchedule, ElectionTitle } from '@v
import { ElectionProvider, OrganizationProvider, useElection, useOrganization } from '@vocdoni/react-providers'
import { InvalidElection as InvalidElectionType, PublishedElection } from '@vocdoni/sdk'
import { useTranslation } from 'react-i18next'
import { generatePath, Link as RouterLink } from 'react-router-dom'
import { ReducedTextAndCopy } from '~components/CopyButton'
import { Link as RouterLink, generatePath } from 'react-router-dom'
import { ReducedTextAndCopy } from '~components/Layout/CopyButton'
import { ElectionStatusBadge } from '~components/Organizations/StatusBadge'
import InvalidElection from '~components/Process/InvalidElection'
import { RoutePath } from '~constants'
Expand Down
22 changes: 11 additions & 11 deletions src/components/Process/Detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,21 @@ import {
InvalidElection as InvalidElectionType,
PublishedElection,
} from '@vocdoni/sdk'
import { FallbackHeaderImg, RoutePath } from '~constants'
import { HeroHeaderLayout } from '~components/Layout/HeroHeaderLayout'
import { CopyButton, ReducedTextAndCopy } from '~components/CopyButton'
import { Trans, useTranslation } from 'react-i18next'
import { ElectionStatusBadge } from '~components/Organizations/StatusBadge'
import { OrganizationCard } from '~components/Organizations/Card'
import { RawContentBox } from '~components/Layout/ShowRawButton'
import { useElectionKeys, useElectionVotesList } from '~queries/processes'
import { PaginationProvider, usePagination } from '~components/Pagination/PaginationProvider'
import { BiEnvelope } from 'react-icons/bi'
import { generatePath, Link as RouterLink } from 'react-router-dom'
import { CopyButton, ReducedTextAndCopy } from '~components/Layout/CopyButton'
import { HeroHeaderLayout } from '~components/Layout/HeroHeaderLayout'
import { LoadingCards } from '~components/Layout/Loading'
import { RawContentBox } from '~components/Layout/ShowRawButton'
import { OrganizationCard } from '~components/Organizations/Card'
import { ElectionStatusBadge } from '~components/Organizations/StatusBadge'
import { Pagination } from '~components/Pagination/Pagination'
import { BiEnvelope } from 'react-icons/bi'
import { ucfirst } from '~utils/strings'
import { PaginationProvider, usePagination } from '~components/Pagination/PaginationProvider'
import InvalidElection from '~components/Process/InvalidElection'
import { generatePath, Link as RouterLink } from 'react-router-dom'
import { FallbackHeaderImg, RoutePath } from '~constants'
import { useElectionKeys, useElectionVotesList } from '~queries/processes'
import { ucfirst } from '~utils/strings'

const Detail = () => {
const { election } = useElection()
Expand Down
10 changes: 5 additions & 5 deletions src/components/Process/ProcessList.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { Button, Checkbox, Flex } from '@chakra-ui/react'
import { keepPreviousData } from '@tanstack/react-query'
import { IElectionListFilter } from '@vocdoni/sdk'
import { Trans, useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
import { RoutedPagination } from '~components/Pagination/Pagination'
import { RoutedPaginationProvider } from '~components/Pagination/PaginationProvider'
import { PaginationItemsPerPage, RoutePath } from '~constants'
import { useProcessesCount, useProcessList } from '~queries/processes'
import { InputSearch } from '~components/Layout/Inputs'
import { LoadingCards } from '~components/Layout/Loading'
import LoadingError from '~components/Layout/LoadingError'
import { RoutedPaginationProvider } from '~components/Pagination/PaginationProvider'
import { RoutedPagination } from '~components/Pagination/RoutedPagination'
import { PaginationItemsPerPage, RoutePath } from '~constants'
import { useProcessesCount, useProcessList } from '~queries/processes'
import useQueryParams from '~src/router/use-query-params'
import { isEmpty } from '~utils/objects'
import { ElectionCard } from './Card'
import { keepPreviousData } from '@tanstack/react-query'

type FilterQueryParams = {
[K in keyof Omit<IElectionListFilter, 'organizationId'>]: string
Expand Down
7 changes: 3 additions & 4 deletions src/components/Transactions/TransactionCard.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Box, Card, CardBody, Flex, Link, Tag, Text } from '@chakra-ui/react'
import { Trans } from 'react-i18next'
import { ReducedTextAndCopy } from '~components/CopyButton'
import { IChainTxReference, TransactionType } from '@vocdoni/sdk'
import React from 'react'
import { generatePath, Link as RouterLink } from 'react-router-dom'
import { Trans } from 'react-i18next'
import { Link as RouterLink, generatePath } from 'react-router-dom'
import { ReducedTextAndCopy } from '~components/Layout/CopyButton'
import { RoutePath } from '~constants'

export const TransactionTypeBadge = ({ transactionType }: { transactionType: TransactionType }) => {
Expand Down
Loading

2 comments on commit f894758

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.