diff --git a/src/components/Dashboard/ProcessView.tsx b/src/components/Dashboard/ProcessView.tsx index 27cff0d09..bfc0de7cb 100644 --- a/src/components/Dashboard/ProcessView.tsx +++ b/src/components/Dashboard/ProcessView.tsx @@ -47,7 +47,7 @@ import { Routes } from '~src/router/routes' export const ProcessView = () => { const { setTitle, setBack } = useOutletContext() const { id, election, participation, turnout } = useElection() - const { ReadMoreMarkdownWrapper } = useReadMoreMarkdown('rgba(242, 242, 242, 0)', 'rgba(242, 242, 242, 1)', 600, 20) + const { ReadMoreMarkdownWrapper, ReadMoreMarkdownButton } = useReadMoreMarkdown(600, 20) const votingLink = `${document.location.origin}${generatePath(Routes.processes.view, { id })}` const { hasCopied, onCopy } = useClipboard(votingLink) @@ -66,9 +66,16 @@ export const ProcessView = () => { {election instanceof PublishedElection && election.description && ( - - - + <> + + + + + )} {/* Calendar */} diff --git a/src/components/Layout/use-read-more.tsx b/src/components/Layout/use-read-more.tsx index 2934bb0b9..dc93072b1 100644 --- a/src/components/Layout/use-read-more.tsx +++ b/src/components/Layout/use-read-more.tsx @@ -1,18 +1,19 @@ import { Box, Button } from '@chakra-ui/react' -import { useEffect, useRef, useState } from 'react' +import { ReactNode, useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -export const useReadMoreMarkdown = ( - colorFrom: string, - colorTo: string, - containerMaxHeightPx: number, - tantPerCentGradient?: number -) => { +interface ReadMoreMarkdownWrapperProps { + children: ReactNode + from?: string + toLight?: string + toDark?: string +} + +export const useReadMoreMarkdown = (containerMaxHeightPx: number, tantPerCentGradient?: number) => { const { t } = useTranslation() const containerRef = useRef(null) const [isTruncated, setIsTruncated] = useState(false) const [readMore, setReadMore] = useState(false) - const handleReadMore = () => setReadMore((prev) => !prev) useEffect(() => { @@ -26,32 +27,40 @@ export const useReadMoreMarkdown = ( } }, []) - const ReadMoreMarkdownWrapper = ({ children, from, to, ...props }: any) => ( - - {children} - - ) + const ReadMoreMarkdownWrapper = ({ + children, + from = 'var(--chakra-colors-read_more-from)', + toLight = 'var(--chakra-colors-read_more-to-light)', + toDark = 'var(--chakra-colors-read_more-to-dark)', + ...props + }: ReadMoreMarkdownWrapperProps) => { + return ( + + + {children} + + ) + } const ReadMoreMarkdownButton = ({ ...props }: any) => isTruncated ? ( + } + /> )} {election?.header && ( )} - - - + + + - + - - + + {t('process.state')} - + - + - - + + {t('process.schedule')} - + @@ -104,34 +92,33 @@ const ProcessHeader = () => { {!election?.description?.default.length && ( - + {t('process.no_description')} )} - + - + - + {election?.status !== ElectionStatus.CANCELED ? ( ) : ( @@ -149,7 +136,7 @@ const ProcessHeader = () => { )} - {t('process.census')} {showTotalCensusSize && } + {t('process.census')} {showTotalCensusSize && } {showTotalCensusSize ? ( { )} {showOrgInformation && ( - + {t('process.created_by')} @@ -200,10 +187,9 @@ const ProcessHeader = () => { flexWrap: 'wrap', }, '& p strong': { - maxW: { base: '100%', md: '220px', md2: '250px' }, + maxW: { base: '100%', md: '220px', xl2: '120px' }, isTruncated: true, mr: 1, - color: 'process.created_by', }, }} /> diff --git a/src/components/Process/View.tsx b/src/components/Process/View.tsx index 9a8b426a9..2395179d4 100644 --- a/src/components/Process/View.tsx +++ b/src/components/Process/View.tsx @@ -106,8 +106,19 @@ export const ProcessView = () => { }, [formErrors]) return ( - - + +
{election instanceof PublishedElection && election?.streamUri && ( @@ -115,7 +126,7 @@ export const ProcessView = () => { maxW={{ base: '800px', lg: videoTop ? '400px' : '800px' }} ml={videoTop ? 'auto' : 'none'} position={{ base: 'unset', lg: 'sticky' }} - top={{ base: 0, lg2: 20 }} + top={{ base: 0, xl2: 20 }} zIndex={100} > @@ -124,26 +135,23 @@ export const ProcessView = () => { )} - + - {t('process.questions')} + {t('process.questions')} {election instanceof PublishedElection && election?.status !== ElectionStatus.CANCELED && ( - {t('process.results')} + {t('process.results')} )} - + { setFormErrors(args) @@ -151,40 +159,33 @@ export const ProcessView = () => { confirmContents={(election, answers) => } /> - + - + - + @@ -281,7 +282,7 @@ const ConfirmVoteModal = ({ election, answers }: { election: PublishedElection; overflowY='scroll' boxShadow='rgba(128, 128, 128, 0.42) 1px 1px 1px 1px' px={2} - borderRadius='lg2' + borderRadius='xl2' > {election.questions.map((q, i) => ( diff --git a/src/elements/Layout.tsx b/src/elements/Layout.tsx index 939a12849..b0dcfa73a 100644 --- a/src/elements/Layout.tsx +++ b/src/elements/Layout.tsx @@ -7,7 +7,16 @@ const Layout = () => { const location = useLocation() return ( - + diff --git a/src/theme/colors.ts b/src/theme/colors.ts index f99d57e37..8c153d0e4 100644 --- a/src/theme/colors.ts +++ b/src/theme/colors.ts @@ -5,6 +5,7 @@ export const colorsBase = { grayish: '#2B2A33', dark: '#1A202C', }, + gradient: 'linear-gradient(to right, #546E39, #2E441A)', gray: { light: '#E2E8F0', normal: '#718096', @@ -15,6 +16,7 @@ export const colorsBase = { pure: '#ffffff', dark: '#F5F5F7', alpha: 'whiteAlpha.300', + from_read_more: 'rgba(245, 245, 247, 0)', }, yellow: '#FFB116', } @@ -51,6 +53,13 @@ export const colors = { bg_checked_light: colorsBase.white.pure, bg_checked_dark: colorsBase.blue.dark, }, + read_more: { + from: colorsBase.white.from_read_more, + to: { + light: colorsBase.white.pure, + dark: colorsBase.blue.grayish, + }, + }, sidebar: { bg: { light: colorsBase.white.pure, @@ -153,6 +162,58 @@ export const colors = { }, }, org_text_secondary: colorsBase.gray.normal, + + process: { + aside: { + bg: colorsBase.gradient, + color: colorsBase.white.pure, + vote_btn_color: colorsBase.black, + vote_btn_bg: colorsBase.primary, + verify_link: colorsBase.white.pure, + }, + canceled: colorsBase.primary, + info_title: colorsBase.primary, + label: colorsBase.gray.normal, + questions: { + alert: { + bg: colorsBase.primary, + color: colorsBase.white.pure, + link_color: colorsBase.black, + link_bg: colorsBase.white.pure, + }, + question_selected: { + bg: colorsBase.primary, + color: colorsBase.white.pure, + }, + hover: { + light: colorsBase.white.pure, + dark: colorsBase.blue.grayish, + }, + disabled: { + light: colorsBase.white.pure, + dark: colorsBase.blue.grayish, + }, + title: { + ligth: colorsBase.primary, + dark: colorsBase.white.pure, + }, + }, + paused: colorsBase.primary, + results: { + alert_bg: colorsBase.primary, + alert_color: colorsBase.white.pure, + bg: colorsBase.gray.light, + description: colorsBase.gray.normal, + progressbar_bg: colorsBase.gray.light, + title: colorsBase.primary, + }, + tabs: { + active_bg: colorsBase.gray.light, + hover_bg: colorsBase.gray.light, + border_bottom_list: colorsBase.gray.light, + }, + }, + process_create: { bg: { dark: colorsBase.blue.dark, @@ -174,7 +235,17 @@ export const colors = { text_secondary: colorsBase.gray.normal, question_index: colorsBase.primary, }, - + process_view: { + bg_light: colorsBase.white.dark, + bg_dark: colorsBase.blue.dark, + }, + read_more: { + from: colorsBase.white.from_read_more, + to: { + light: colorsBase.white.dark, + dark: colorsBase.blue.dark, + }, + }, tab: { variant: { card: { diff --git a/src/theme/components/Questions.ts b/src/theme/components/Questions.ts new file mode 100644 index 000000000..66b1f3455 --- /dev/null +++ b/src/theme/components/Questions.ts @@ -0,0 +1,210 @@ +import { createMultiStyleConfigHelpers } from '@chakra-ui/react' +import { questionsAnatomy } from '@vocdoni/chakra-components' +import checkIcon from '/assets/check-icon.png' + +const { defineMultiStyleConfig, definePartsStyle } = createMultiStyleConfigHelpers(questionsAnatomy) + +const baseStyle = definePartsStyle({ + alert: { + px: { base: 3, sm: 5 }, + py: 7, + mb: '30px', + borderRadius: '8px', + color: 'process.questions.alert.color', + bgColor: 'process.questions.alert.bg', + display: 'grid', + columnGap: 4, + justifyContent: 'center', + alignItems: 'center', + gridTemplateColumns: 'auto 1fr', + gridTemplateRows: 'auto auto', + boxShadow: 'var(--box-shadow-darker)', + border: 'none', + + '& span': { + color: 'white', + ml: { base: 2, lg: 10, xl: 2 }, + gridRow: '1/3', + gridColumn: '1/2', + }, + }, + + alertTitle: { + fontSize: 'lg', + mb: 3, + }, + + alertDescription: { + display: 'flex', + gap: 2, + flexDirection: { base: 'column', lg2: 'row' }, + justifyContent: 'center', + alignItems: { md: 'center' }, + whiteSpace: { base: 'pre-wrap', lg2: 'nowrap' }, + }, + + alertLink: { + display: 'block', + w: '100%', + px: 2, + py: 1, + textOverflow: 'ellipsis', + overflow: 'hidden', + whiteSpace: 'nowrap', + color: 'process.questions.alert.link_color', + backgroundColor: 'process.questions.alert.link_bg', + borderRadius: 'md', + fontSize: 'sm', + + _hover: { + textDecoration: 'none', + }, + }, + + wrapper: { + '& > form': { + display: 'flex', + flexDirection: 'column', + gap: 10, + }, + }, + + question: { + width: { base: 'full', xl: '80%' }, + m: 0, + mx: 'auto', + + '& > div': { + display: 'flex', + flexDirection: 'column', + overflow: 'hidden', + }, + }, + + title: { + display: 'block', + textAlign: 'start', + lineHeight: 1.3, + fontSize: 'xl !important', + color: 'process.questions.title.light', + + _dark: { + color: 'process.questions.title.dark', + }, + }, + + description: { + px: 1, + color: 'process.questions.description', + textAlign: 'start', + fontSize: 'md !important', + + '& a': { + textDecoration: 'underline', + }, + + _dark: { + color: 'process.questions.title.dark', + }, + }, + + stack: { + '& label': { + borderRadius: 'lg', + overflow: 'hidden', + display: 'flex', + alignItems: 'center', + gap: 2, + w: { lg2: '99%' }, + _hover: { + bgColor: 'process.questions.hover.light', + + _dark: { + bgColor: 'process.questions.hover.dark', + }, + }, + + '& span:nth-of-type(1)': { + display: { base: 'none', md: 'block' }, + position: 'absolute', + width: '30px', + height: '30px', + background: 'transparent', + ml: '10px', + borderRadius: 'none', + + '&[data-checked=""]': { + '&:before': { + display: 'none', + bgColor: 'transparent', + }, + + background: 'process.questions.question_selected.bg', + borderColor: 'white', + borderWidth: '1px', + bgSize: '15px', + bgRepeat: 'no-repeat', + bgPosition: 'center', + bgImage: checkIcon, + + _hover: { + border: 'none', + background: 'process.questions.question_selected.bg', + borderColor: 'process.questions.question_selected.bg', + bgSize: '15px', + bgRepeat: 'no-repeat', + bgPosition: 'center', + bgImage: checkIcon, + }, + }, + + '&[data-disabled=""]': { + bgColor: 'process.questions.disabled.light', + border: 'none', + + _dark: { + bgColor: 'process.questions.disabled.dark', + }, + }, + }, + '& span:nth-of-type(2)': { + p: 2, + pl: { md: 12 }, + m: 0, + border: '1px solid lightgray', + w: '100%', + borderRadius: 'lg', + }, + + '& input:checked ~ span:nth-of-type(2)': { + color: 'process.questions.question_selected.color', + bgColor: 'process.questions.question_selected.bg', + w: '100%', + }, + }, + }, + + radio: { + borderRadius: 'full !important', + }, + + checkbox: { + // Checkbox label style + '& span:nth-of-type(2)': { + display: 'flex', + flexDir: 'row', + justifyContent: 'space-between', + justifyItems: 'center', + alignItems: 'center', + }, + }, + + error: { + display: 'flex', + justifyContent: 'center', + }, +}) + +export const ElectionQuestions = defineMultiStyleConfig({ + baseStyle, +}) diff --git a/src/theme/components/Tabs.ts b/src/theme/components/Tabs.ts index 46114c17f..5b688e193 100644 --- a/src/theme/components/Tabs.ts +++ b/src/theme/components/Tabs.ts @@ -109,9 +109,43 @@ const card = definePartsStyle({ p: 0, }, }) +const process = definePartsStyle({ + root: {}, + tabpanel: { + px: { base: 0, sm: 4 }, + mb: 0, + }, + tab: { + position: 'relative', + whiteSpace: 'nowrap', + color: 'process.tabs.color', + fontWeight: 'normal', + borderTopRadius: 'md', + fontSize: 'lg', + + _hover: { + bgColor: 'process.tabs.hover', + }, + _active: { + bgColor: 'process.tabs.active_bg', + }, + _selected: { + fontWeight: 'bold', + borderBottom: '1px solid', + }, + }, + tablist: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + borderBottom: '1px solid', + borderColor: 'process.tabs.border_bottom_list', + }, +}) const variants = { card, + process, } export const Tabs = defineMultiStyleConfig({ variants }) diff --git a/src/theme/components/card.ts b/src/theme/components/card.ts index 771ed6cc7..3c06ed9a1 100644 --- a/src/theme/components/card.ts +++ b/src/theme/components/card.ts @@ -485,5 +485,23 @@ export const Card = defineMultiStyleConfig({ }, }, }, + aside: { + container: { + direction: 'column', + justifyContent: 'center', + alignItems: 'center', + px: { base: 6, xl2: 8 }, + py: { base: 6, xl2: 8 }, + w: 'full', + gap: 4, + mt: { md: 7 }, + mb: { base: 7, xl2: 0 }, + color: 'process.aside.color', + background: 'process.aside.bg', + boxShadow: 'var(--box-shadow-banner)', + borderRadius: 'lg', + fontSize: 'text', + }, + }, }, }) diff --git a/src/theme/components/results.ts b/src/theme/components/results.ts new file mode 100644 index 000000000..a5632b094 --- /dev/null +++ b/src/theme/components/results.ts @@ -0,0 +1,92 @@ +import { createMultiStyleConfigHelpers } from '@chakra-ui/react' +import { resultsAnatomy } from '@vocdoni/chakra-components' + +const { defineMultiStyleConfig, definePartsStyle } = createMultiStyleConfigHelpers(resultsAnatomy) + +const baseStyle = definePartsStyle({ + question: { + p: 4, + width: { base: 'full', xl: '80%' }, + m: 0, + mx: 'auto', + + '& > div:nth-of-type(1)': { + '& > p': { + fontSize: 'xl2', + mb: 5, + lineHeight: 1.3, + textAlign: 'start', + }, + }, + '& > div:nth-of-type(2) > div': { + display: 'flex', + flexDirection: { base: 'column', md: 'row' }, + alignItems: { base: 'center', md: 'start' }, + gap: 3, + mb: 5, + + '& p:nth-of-type(1)': { + maxW: '100%', + flexBasis: '33%', + flexGrow: 1, + color: 'process.results.description', + }, + '& p:nth-of-type(2)': { + mx: 4, + }, + '& div': { + w: 'full', + flexBasis: '33%', + flexGrow: 0, + flexShrink: 0, + h: 6, + borderRadius: 'md', + bgColor: 'results.progressbar_bg', + overflow: 'hidden', + position: 'relative', + + '& div': { + h: 6, + background: { + base: `linear-gradient(to right, #789D53 0%, #546E39 50%, #2E441A 100%) left/var(--p,100%) fixed;`, + md: `linear-gradient(to right, #789D53 65%, #546E39 79.5%, #2E441A 94%) left/var(--p,100%) fixed;`, + xl: `linear-gradient(to right, #789D53 46%, #546E39 56%, #2E441A 66%) left/var(--p,100%) fixed;`, + }, + }, + }, + + '& > div:nth-of-type(2) > div:last-of-type': { + mb: 0, + }, + }, + }, + + secret: { + px: 8, + py: 8, + my: 4, + color: 'process.results.alert_color', + bgColor: 'process.results.alert_bg', + borderRadius: 'lg', + whiteSpace: 'wrap', + }, + + title: { + fontWeight: 700, + fontSize: 'xl', + lineHeight: 7, + color: 'process.results.title', + textAlign: { base: 'center', md: 'start' }, + mb: 3, + }, + + wrapper: { + display: 'flex', + flexDirection: 'column', + gap: 10, + }, +}) + +export const ElectionResults = defineMultiStyleConfig({ + baseStyle, +}) diff --git a/src/theme/index.ts b/src/theme/index.ts index 02836fa9e..04b508658 100644 --- a/src/theme/index.ts +++ b/src/theme/index.ts @@ -1,4 +1,4 @@ -import { ColorMode, extendTheme } from '@chakra-ui/react' +import { ColorMode, extendTheme, textDecoration } from '@chakra-ui/react' import { darkTheme, lightTheme } from '@rainbow-me/rainbowkit' import { theme as vtheme } from '@vocdoni/chakra-components' import { breakpoints } from './breakpoints' @@ -21,6 +21,8 @@ import { Text } from './components/text' import { Textarea } from './components/textarea' import { editor } from './editor' import { spacing } from './space' +import { ElectionQuestions } from './components/Questions' +import { ElectionResults } from './components/results' export const theme = extendTheme(vtheme, { config: { @@ -37,6 +39,42 @@ export const theme = extendTheme(vtheme, { '.brand-gradient': { bgGradient: 'linear-gradient(to bottom, #B5F492, #338B93)', }, + '.md-sizes': { + '& :first-of-type': { + mt: 0, + }, + 'h2[level="1"]': { + fontSize: '26px', + }, + 'h2[level="2"]': { + fontSize: '23px', + }, + 'h3[level="3"]': { + fontSize: '20px', + }, + p: { + fontSize: '18px', + }, + li: { + fontSize: '18px', + }, + 'li:last-of-type': { + mb: '20px', + }, + ul: { + fontSize: '18px', + }, + ol: { + fontSize: '18px', + }, + a: { + fontSize: '18px', + textDecoration: 'underline', + }, + pre: { + 'white-space': 'pre-wrap', + }, + }, }, }, components: { @@ -46,6 +84,8 @@ export const theme = extendTheme(vtheme, { Card, Checkbox, ElectionTitle, + ElectionQuestions, + ElectionResults, Form, Heading, Input,