From 4293098fd9cf94bb8daaf401c14f83ca9cc7c1cb Mon Sep 17 00:00:00 2001 From: AT <93994194+VWSCoronaDashboard21@users.noreply.github.com> Date: Mon, 28 Nov 2022 09:09:05 +0100 Subject: [PATCH 01/16] Feature/COR-1088-archive-button-styling (#4508) * feat: changed styling of archive button * feat: added focus state * feat: refactored code * feat: renamed to StyledButton, removed redundant props and sorted * feat: changed focus color to theme color * feat: added interface and focus on hover * feat: removed transition Co-authored-by: VWSCoronaDashboard21 --- .../page-information-block.tsx | 78 ++++++++----------- 1 file changed, 34 insertions(+), 44 deletions(-) diff --git a/packages/app/src/components/page-information-block/page-information-block.tsx b/packages/app/src/components/page-information-block/page-information-block.tsx index c5537d7142..7e76b12706 100644 --- a/packages/app/src/components/page-information-block/page-information-block.tsx +++ b/packages/app/src/components/page-information-block/page-information-block.tsx @@ -16,6 +16,8 @@ import { PageLinks } from './components/page-links'; import { WarningTile } from '~/components/warning-tile'; import { useScopedWarning } from '~/utils/use-scoped-warning'; import { useIntl } from '~/intl'; +import { colors } from '@corona-dashboard/common'; +import { space } from '~/style/theme'; interface InformationBlockProps { title?: string; @@ -57,18 +59,12 @@ export function PageInformationBlock({ onToggleArchived, }: InformationBlockProps) { const scopedWarning = useScopedWarning(vrNameOrGmName || '', warning || ''); - const showArchivedToggleButton = - typeof isArchivedHidden !== 'undefined' && - typeof onToggleArchived !== 'undefined'; + const showArchivedToggleButton = typeof isArchivedHidden !== 'undefined' && typeof onToggleArchived !== 'undefined'; const { commonTexts } = useIntl(); const MetaDataBlock = metadata ? ( - + ) : null; @@ -86,22 +82,8 @@ export function PageInformationBlock({ return ( - {title && ( -
- )} - {scopedWarning && ( - - )} + {title &&
} + {scopedWarning && } {description && ( @@ -139,15 +121,9 @@ export function PageInformationBlock({ {showArchivedToggleButton && ( - + + {!isArchivedHidden ? commonTexts.common.show_archived : commonTexts.common.hide_archived} + )} @@ -172,14 +148,28 @@ const MetadataBox = styled.div( }) ); -const Button = styled.button<{ isActive?: boolean }>(({ isActive }) => - css({ - bg: !isActive ? 'blue8' : 'transparent', - border: 'none', - borderRadius: '5px', - color: !isActive ? 'white' : 'blue8', - px: !isActive ? 3 : 0, - py: !isActive ? 12 : 0, - cursor: 'pointer', - }) -); +interface StyledArchiveButtonProps { + isActive?: boolean; +} + +const StyledArchiveButton = styled.button` + background: ${({ isActive }) => (isActive ? colors.blue1 : colors.white)}; + border: ${({ isActive }) => (isActive ? colors.transparent : colors.gray3)}; + border-radius: 5px; + border-style: solid; + border-width: 1px; + color: ${({ isActive }) => (isActive ? colors.blue8 : colors.blue8)}; + cursor: pointer; + min-height: 36px; + padding: 12px ${space[3]}; + + &:hover { + background: ${colors.blue8}; + color: ${colors.white}; + border-color: ${colors.transparent}; + } + + &:hover:focus-visible { + outline: 2px dotted ${colors.magenta3}; + } +`; From 4d38aa1417bcf613bbe0a02bc3896d4ebb062f6e Mon Sep 17 00:00:00 2001 From: AT <93994194+VWSCoronaDashboard21@users.noreply.github.com> Date: Mon, 28 Nov 2022 09:09:28 +0100 Subject: [PATCH 02/16] Feature/COR-1068-change-border-color-measure-tile (#4509) * feat: changed borderColor of measure tile * feat: refactored code based on code conventions Co-authored-by: VWSCoronaDashboard21 --- .../domain/topical/components/topical-measure-tile.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/app/src/domain/topical/components/topical-measure-tile.tsx b/packages/app/src/domain/topical/components/topical-measure-tile.tsx index 2e6ec5dabe..487884cd82 100644 --- a/packages/app/src/domain/topical/components/topical-measure-tile.tsx +++ b/packages/app/src/domain/topical/components/topical-measure-tile.tsx @@ -14,11 +14,11 @@ interface TopicalMeasureTileProps { export const TopicalMeasureTile = ({ icon, title }: TopicalMeasureTileProps) => { return ( - + - + + @@ -28,7 +28,7 @@ export const TopicalMeasureTile = ({ icon, title }: TopicalMeasureTileProps) => ); }; -const KpiIcon = styled.div` +const StyledKpiIcon = styled.div` color: ${colors.blue8}; display: flex; width: 40px; From af34b2f31f60bf82d948a7abd34e7f0e685de1a0 Mon Sep 17 00:00:00 2001 From: HO <93981322+VWSCoronaDashboard19@users.noreply.github.com> Date: Mon, 28 Nov 2022 13:47:37 +0100 Subject: [PATCH 03/16] chore: update and cleanup keys and data structure (#4515) --- packages/cms/src/data/data-structure.ts | 90 +++++++++++---------- packages/cms/src/lokalize/key-mutations.csv | 16 ---- 2 files changed, 48 insertions(+), 58 deletions(-) diff --git a/packages/cms/src/data/data-structure.ts b/packages/cms/src/data/data-structure.ts index 3e2f06c0b8..4998060e71 100644 --- a/packages/cms/src/data/data-structure.ts +++ b/packages/cms/src/data/data-structure.ts @@ -12,16 +12,18 @@ export const dataStructure = { 'admissions_on_date_of_reporting', ], tested_overall: ['infected', 'infected_moving_average', 'infected_moving_average_rounded', 'infected_per_100k', 'infected_per_100k_moving_average'], - sewer: ['average', 'total_number_of_samples', 'sampled_installation_count', 'total_installation_count'], + sewer: ['average', 'total_number_of_samples', 'sampled_installation_count', 'total_installation_count', 'data_is_outdated'], vaccine_coverage_per_age_group: [ - 'age_group_range', - 'autumn_2022_vaccinated_percentage', - 'fully_vaccinated_percentage', - 'booster_shot_percentage', - 'birthyear_range', - 'autumn_2022_vaccinated_percentage_label', - 'fully_vaccinated_percentage_label', - 'booster_shot_percentage_label', + 'vaccination_type', + 'birthyear_range_12_plus', + 'birthyear_range_18_plus', + 'birthyear_range_60_plus', + 'vaccinated_percentage_12_plus', + 'vaccinated_percentage_12_plus_label', + 'vaccinated_percentage_18_plus', + 'vaccinated_percentage_18_plus_label', + 'vaccinated_percentage_60_plus', + 'vaccinated_percentage_60_plus_label', ], vaccine_coverage_per_age_group_archived: [ 'age_group_range', @@ -41,28 +43,30 @@ export const dataStructure = { 'booster_shot_percentage_label', 'has_one_shot_percentage_label', ], - booster_coverage: ['age_group', 'percentage', 'percentage_label'], + booster_coverage_archived_20220904: ['age_group', 'percentage', 'percentage_label'], }, gm_collection: { hospital_nice: ['admissions_on_date_of_admission', 'admissions_on_date_of_admission_per_100000', 'admissions_on_date_of_reporting'], hospital_nice_choropleth: ['admissions_on_date_of_admission', 'admissions_on_date_of_admission_per_100000', 'admissions_on_date_of_reporting'], tested_overall: ['infected_per_100k', 'infected'], - sewer: ['average', 'total_installation_count'], + sewer: ['average', 'total_installation_count', 'data_is_outdated'], vaccine_coverage_per_age_group: [ - 'age_group_range', - 'autumn_2022_vaccinated_percentage', - 'fully_vaccinated_percentage', - 'booster_shot_percentage', - 'birthyear_range', - 'autumn_2022_vaccinated_percentage_label', - 'fully_vaccinated_percentage_label', - 'booster_shot_percentage_label', + 'vaccination_type', + 'birthyear_range_12_plus', + 'birthyear_range_18_plus', + 'birthyear_range_60_plus', + 'vaccinated_percentage_12_plus', + 'vaccinated_percentage_12_plus_label', + 'vaccinated_percentage_18_plus', + 'vaccinated_percentage_18_plus_label', + 'vaccinated_percentage_60_plus', + 'vaccinated_percentage_60_plus_label', ], }, nl: { - booster_shot_administered: ['administered_total', 'ggd_administered_total', 'others_administered_total'], + booster_shot_administered_archived_20220904: ['administered_total', 'ggd_administered_total', 'others_administered_total'], repeating_shot_administered: ['ggd_administered_total'], - booster_coverage: ['age_group', 'percentage'], + booster_coverage_archived_20220904: ['age_group', 'percentage'], doctor: ['covid_symptoms_per_100k', 'covid_symptoms'], g_number: ['g_number'], infectious_people: ['margin_low', 'estimate', 'margin_high'], @@ -232,10 +236,8 @@ export const dataStructure = { 'age_group_total', 'autumn_2022_vaccinated', 'fully_vaccinated', - 'booster_shot', 'autumn_2022_vaccinated_percentage', 'fully_vaccinated_percentage', - 'booster_shot_percentage', 'date_of_report_unix', 'birthyear_range', ], @@ -294,7 +296,7 @@ export const dataStructure = { topical: {}, vr: { g_number: ['g_number'], - sewer: ['average'], + sewer: ['average', 'data_is_outdated'], tested_overall: ['infected', 'infected_moving_average', 'infected_moving_average_rounded', 'infected_per_100k', 'infected_per_100k_moving_average'], hospital_nice: [ 'admissions_on_date_of_admission', @@ -393,14 +395,16 @@ export const dataStructure = { 'other', ], vaccine_coverage_per_age_group: [ - 'age_group_range', - 'autumn_2022_vaccinated_percentage', - 'fully_vaccinated_percentage', - 'booster_shot_percentage', - 'birthyear_range', - 'autumn_2022_vaccinated_percentage_label', - 'fully_vaccinated_percentage_label', - 'booster_shot_percentage_label', + 'vaccination_type', + 'birthyear_range_12_plus', + 'birthyear_range_18_plus', + 'birthyear_range_60_plus', + 'vaccinated_percentage_12_plus', + 'vaccinated_percentage_12_plus_label', + 'vaccinated_percentage_18_plus', + 'vaccinated_percentage_18_plus_label', + 'vaccinated_percentage_60_plus', + 'vaccinated_percentage_60_plus_label', ], vaccine_coverage_per_age_group_archived: [ 'age_group_range', @@ -420,14 +424,14 @@ export const dataStructure = { 'booster_shot_percentage_label', 'has_one_shot_percentage_label', ], - booster_coverage: ['age_group', 'percentage', 'percentage_label'], + booster_coverage_archived_20220904: ['age_group', 'percentage', 'percentage_label'], }, vr_collection: { hospital_nice: ['admissions_on_date_of_admission', 'admissions_on_date_of_admission_per_100000', 'admissions_on_date_of_reporting'], hospital_nice_choropleth: ['admissions_on_date_of_admission', 'admissions_on_date_of_admission_per_100000', 'admissions_on_date_of_reporting'], tested_overall: ['infected_per_100k', 'infected'], nursing_home: ['newly_infected_people', 'newly_infected_locations', 'infected_locations_total', 'infected_locations_percentage', 'deceased_daily'], - sewer: ['average'], + sewer: ['average', 'data_is_outdated'], behavior_archived_20221019: [ 'number_of_participants', 'curfew_compliance', @@ -471,14 +475,16 @@ export const dataStructure = { elderly_at_home: ['positive_tested_daily', 'positive_tested_daily_per_100k', 'deceased_daily'], situations: ['has_sufficient_data', 'home_and_visits', 'work', 'school_and_day_care', 'health_care', 'gathering', 'travel', 'hospitality', 'other'], vaccine_coverage_per_age_group: [ - 'age_group_range', - 'autumn_2022_vaccinated_percentage', - 'fully_vaccinated_percentage', - 'booster_shot_percentage', - 'birthyear_range', - 'autumn_2022_vaccinated_percentage_label', - 'fully_vaccinated_percentage_label', - 'booster_shot_percentage_label', + 'vaccination_type', + 'birthyear_range_12_plus', + 'birthyear_range_18_plus', + 'birthyear_range_60_plus', + 'vaccinated_percentage_12_plus', + 'vaccinated_percentage_12_plus_label', + 'vaccinated_percentage_18_plus', + 'vaccinated_percentage_18_plus_label', + 'vaccinated_percentage_60_plus', + 'vaccinated_percentage_60_plus_label', ], }, }; diff --git a/packages/cms/src/lokalize/key-mutations.csv b/packages/cms/src/lokalize/key-mutations.csv index 29d273cf79..a7c6419a8a 100644 --- a/packages/cms/src/lokalize/key-mutations.csv +++ b/packages/cms/src/lokalize/key-mutations.csv @@ -1,17 +1 @@ timestamp,action,key,document_id,move_to -2022-11-07T15:09:11.939Z,add,common.choropleth_tooltip.gm.outdated_data_notification,TrUIlGMFRR6fBR627mmYKT,__ -2022-11-07T15:41:35.054Z,delete,common.choropleth_tooltip.gm.outdated_data_notification,TrUIlGMFRR6fBR627mmYKT,__ -2022-11-07T15:57:14.611Z,add,common.choropleth_tooltip.outdated_data_notification,Fgb5SAAswLDPRQ9KRzHRc8,__ -2022-11-07T16:00:34.118Z,delete,common.choropleth_tooltip.outdated_data_notification,Fgb5SAAswLDPRQ9KRzHRc8,__ -2022-11-07T16:01:10.105Z,add,common.choropleth_tooltip.gm.average.outdated_data_notification,Fgb5SAAswLDPRQ9KRzIAnG,__ -2022-11-07T16:01:11.103Z,add,common.choropleth_tooltip.vr.average.outdated_data_notification,BBCOmHCrMQzaQKV1wWKvZ9,__ -2022-11-11T08:49:48.826Z,add,pages.sewer_page.nl.choropleth_legend_outdated_data_label,TrUIlGMFRR6fBR628D5VMd,__ -2022-11-21T09:11:46.413Z,add,common.common.age_groups.12,UE7TbOA80ovT85nyy1gcYy,__ -2022-11-21T09:11:47.332Z,add,common.common.age_groups.18,UE7TbOA80ovT85nyy1gcqO,__ -2022-11-21T09:11:48.400Z,add,common.common.age_groups.60,Tg1qSQfR7l8JBUWv7hoA0J,__ -2022-11-21T09:11:49.412Z,add,common.vaccinations.coverage_kinds.autumn_2022,cMBWaVHxQUmXKxLgJyJ8LF,__ -2022-11-21T09:11:50.358Z,add,common.vaccinations.coverage_kinds.fully_basisserie,cMBWaVHxQUmXKxLgJyJ8aT,__ -2022-11-21T09:11:50.359Z,delete,common.vaccinations.coverage_kinds.autumn_2022_vaccinated_percentage,NGAoa2ArqEakZsIxnSDBhz,__ -2022-11-21T09:11:50.360Z,delete,common.vaccinations.coverage_kinds.fully_vaccinated_percentage,jDbv30Y7XYH5kl8ZaoSZwv,__ -2022-11-23T09:37:10.394Z,add,common.vaccinations.coverage_kinds.primary_series,cMBWaVHxQUmXKxLgKD55A5,__ -2022-11-23T09:37:10.395Z,delete,common.vaccinations.coverage_kinds.fully_basisserie,cMBWaVHxQUmXKxLgJyJ8aT,__ From d6bfed6eba2312b9ba33835c0a9e9322feab0a82 Mon Sep 17 00:00:00 2001 From: AP <116002914+VWSCoronaDashboard28@users.noreply.github.com> Date: Tue, 29 Nov 2022 10:00:06 +0100 Subject: [PATCH 04/16] Bugfix/cor 1067 fullscreen modal close button is not aligned properly (#4510) * bugfix(COR-1067): Adjust icon button styled component to align with new conventions. * bugfix(COR-1067): Adjust the close button positioning, update code according to conventions. * bugfix(COR-1067): PR feedback * bugfix(COR-1067): PR feedback --- .../src/components/fullscreen-chart-tile.tsx | 78 ++++++++----------- packages/app/src/components/icon-button.tsx | 74 +++++++----------- 2 files changed, 60 insertions(+), 92 deletions(-) diff --git a/packages/app/src/components/fullscreen-chart-tile.tsx b/packages/app/src/components/fullscreen-chart-tile.tsx index 62c668eb97..4c670e1359 100644 --- a/packages/app/src/components/fullscreen-chart-tile.tsx +++ b/packages/app/src/components/fullscreen-chart-tile.tsx @@ -1,8 +1,10 @@ +import { colors } from '@corona-dashboard/common'; import { Close, Expand } from '@corona-dashboard/icons'; -import css from '@styled-system/css'; import { useEffect, useRef, useState } from 'react'; +import styled from 'styled-components'; import { Tile } from '~/components/tile'; import { useIntl } from '~/intl'; +import { space } from '~/style/theme'; import { replaceVariablesInText } from '~/utils/replace-variables-in-text'; import { useBreakpoints } from '~/utils/use-breakpoints'; import { usePrevious } from '~/utils/use-previous'; @@ -12,15 +14,13 @@ import { IconButton } from './icon-button'; import { Metadata, MetadataProps } from './metadata'; import { Modal } from './modal'; -export function FullscreenChartTile({ - children, - metadata, - disabled, -}: { +interface FullscreenChartTileProps { children: React.ReactNode; metadata?: MetadataProps; disabled?: boolean; -}) { +} + +export function FullscreenChartTile({ children, metadata, disabled }: FullscreenChartTileProps) { const [isFullscreen, setIsFullscreen] = useState(false); const wasFullscreen = usePrevious(isFullscreen); const breakpoints = useBreakpoints(); @@ -33,18 +33,13 @@ export function FullscreenChartTile({ } }, [wasFullscreen, isFullscreen]); - const label = replaceVariablesInText( - isFullscreen - ? commonTexts.common.modal_close - : commonTexts.common.modal_open, - { subject: commonTexts.common.grafiek_singular } - ); + const label = replaceVariablesInText(isFullscreen ? commonTexts.common.modal_close : commonTexts.common.modal_open, { subject: commonTexts.common.grafiek_singular }); const tile = ( - + )} {!disabled && breakpoints.md && ( -
- setIsFullscreen((x) => !x)} - size={16} - > + + setIsFullscreen((previousValue) => !previousValue)} size={16}> {isFullscreen ? : } -
+ )}
@@ -91,11 +66,7 @@ export function FullscreenChartTile({ if (!disabled && breakpoints.md && isFullscreen) { return ( - setIsFullscreen(false)} - isFullheight - > + setIsFullscreen(false)} isFullheight> {tile} ); @@ -103,3 +74,22 @@ export function FullscreenChartTile({ return
{tile}
; } + +interface StyledModalCloseButtonWrapperProps { + isFullscreen: boolean; +} + +const StyledModalCloseButtonWrapper = styled.div` + color: ${colors.gray3}; + position: absolute; + right: ${({ isFullscreen }) => (isFullscreen ? '25px' : '0')}; + top: 25px; + + &:focus { + outline: 1px dashed ${colors.blue8}; + } + + &:hover { + color: ${colors.gray5}; + } +`; diff --git a/packages/app/src/components/icon-button.tsx b/packages/app/src/components/icon-button.tsx index ee0f37a241..57db91e0e9 100644 --- a/packages/app/src/components/icon-button.tsx +++ b/packages/app/src/components/icon-button.tsx @@ -1,4 +1,3 @@ -import css from '@styled-system/css'; import { cloneElement, forwardRef, ReactElement } from 'react'; import styled from 'styled-components'; import { VisuallyHidden } from './visually-hidden'; @@ -12,54 +11,33 @@ interface IconButtonProps { padding?: number | string; } -export const IconButton = forwardRef( - ( - { - children, - size, - title, - color = 'currentColor', - onClick, - padding, - ...ariaProps - }, - ref - ) => { - return ( - - {title} - {cloneElement(children, { 'aria-hidden': "true" })} - - ); - } -); +export const IconButton = forwardRef(({ children, size, title, color = 'currentColor', onClick, padding, ...ariaProps }, ref) => { + return ( + + {title} + {cloneElement(children, { 'aria-hidden': 'true' })} + + ); +}); -const StyledIconButton = styled.button<{ +interface StyledIconButtonProps { color: string; size: number; padding?: number | string; -}>((x) => - css({ - p: x.padding ?? 0, - m: 0, - bg: 'transparent', - border: 'none', - display: 'block', - cursor: 'pointer', - color: x.color, - '& svg': { - display: 'block', - width: x.size, - height: x.size, - }, - }) -); +} + +const StyledIconButton = styled.button` + background: transparent; + border: none; + color: ${({ color }) => color}; + cursor: pointer; + display: block; + margin: 0; + padding: ${({ padding }) => (padding ? `${padding}px` : 0)}; + + & svg { + display: block; + height: ${({ size }) => size}px; + width: ${({ size }) => size}px; + } +`; From 09027041fd275d387686ef9ee5dc453f7708d738 Mon Sep 17 00:00:00 2001 From: LR <107395524+VWSCoronaDashboard26@users.noreply.github.com> Date: Tue, 29 Nov 2022 17:01:53 +0100 Subject: [PATCH 05/16] bugfix(general): updated CollapsibleSection component styles so that the ID anchor element is vertically centered relative to the title of the collapsible; rewrote the CollapsibleSection component to leverage updated conventions; (#4517) Co-authored-by: VWSCoronaDashboard26 --- .../collapsible/collapsible-section.tsx | 101 +++++++++--------- 1 file changed, 48 insertions(+), 53 deletions(-) diff --git a/packages/app/src/components/collapsible/collapsible-section.tsx b/packages/app/src/components/collapsible/collapsible-section.tsx index a6afe2285f..64855f16a9 100644 --- a/packages/app/src/components/collapsible/collapsible-section.tsx +++ b/packages/app/src/components/collapsible/collapsible-section.tsx @@ -1,4 +1,3 @@ -import { css } from '@styled-system/css'; import { ReactNode, useEffect, useRef } from 'react'; import styled from 'styled-components'; import { Box, BoxProps } from '~/components/base'; @@ -7,6 +6,7 @@ import { isElementAtTopOfViewport } from '~/utils/is-element-at-top-of-viewport' import { useCollapsible } from '~/utils/use-collapsible'; import { Anchor } from '../typography'; import { colors } from '@corona-dashboard/common'; +import { fontSizes, fontWeights, space } from '~/style/theme'; interface CollapsibleSectionProps extends BoxProps { summary: string; @@ -51,9 +51,9 @@ export const CollapsibleSection = ({ summary, children, id, hideBorder, textColo }, [toggle, id]); return ( - - collapsible.toggle()}> - + + collapsible.toggle()}> + {summary} {id && ( {collapsible.button()} - - {collapsible.content({children})} + + {collapsible.content({children})} ); }; -const StyledAnchor = styled(Anchor)( - css({ - color: colors.gray2, - px: 3, - py: 1, - width: 0, - textDecoration: 'none', - position: 'absolute', - right: '100%', - '&:hover, &:focus': { - color: colors.blue1, - }, - }) -); +const StyledAnchor = styled(Anchor)` + color: ${colors.gray2}; + left: -48px; + padding: 0 ${space[3]}; + position: absolute; + text-decoration: none; + top: 50%; + transform: translateY(-50%); + width: 0; + + &:hover, + &:focus { + color: ${colors.blue1}; + } +`; interface SummaryProps { textColor: string; } -const Summary = styled.div((summaryProps: SummaryProps) => - css({ - display: 'flex', - alignItems: 'center', - justifyContent: 'space-between', - overflow: 'visible', - width: '100%', - margin: 0, - padding: 3, - bg: 'transparent', - border: 'none', - color: summaryProps.textColor, - fontFamily: 'body', - fontWeight: 'bold', - fontSize: '1.25rem', - textAlign: 'left', - position: 'relative', - cursor: 'pointer', - userSelect: 'none', - - '&:focus': { - outlineWidth: '1px', - outlineStyle: 'dashed', - outlineColor: colors.blue8, - }, - - [StyledAnchor]: { opacity: 0 }, - - '&:focus, &:hover': { - [StyledAnchor]: { opacity: 1 }, - }, - }) -); + +const StyledSummary = styled(Box)` + align-items: center; + color: ${({ textColor }) => textColor}; + cursor: pointer; + display: flex; + font-size: ${fontSizes[5]}; + font-weight: ${fontWeights.bold}; + justify-content: space-between; + padding: ${space[3]}; + user-select: none; + + &:focus { + outline: 1px dashed ${colors.blue8}; + } + + ${StyledAnchor} { + opacity: 0; + } + + &:hover, + &:focus { + ${StyledAnchor} { + opacity: 1; + } + } +`; From 3d31bcbc9dd2cc1e86748acf166f3ed27f89b40a Mon Sep 17 00:00:00 2001 From: AT <93994194+VWSCoronaDashboard21@users.noreply.github.com> Date: Wed, 30 Nov 2022 09:23:07 +0100 Subject: [PATCH 06/16] fix: correct mobile icon size (#4518) Co-authored-by: VWSCoronaDashboard21 --- .../domain/topical/components/topical-theme-header.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/app/src/domain/topical/components/topical-theme-header.tsx b/packages/app/src/domain/topical/components/topical-theme-header.tsx index b26cd806d5..c5a1f01e33 100644 --- a/packages/app/src/domain/topical/components/topical-theme-header.tsx +++ b/packages/app/src/domain/topical/components/topical-theme-header.tsx @@ -18,9 +18,9 @@ export const TopicalThemeHeader = ({ title, subtitle, icon }: TopicalThemeHeader return ( - + + {title} {subtitle && ( @@ -32,11 +32,11 @@ export const TopicalThemeHeader = ({ title, subtitle, icon }: TopicalThemeHeader ); }; -const TopicalThemeHeaderIcon = styled.span` +const StyledTopicalThemeHeaderIcon = styled.span` display: block; height: 25px; margin-right: 10px; - width: 25px; + min-width: 25px; @media ${theme.mediaQueries.sm} { height: 30px; From 56cdee01ddb0f3bd9dbad45231a81456af5f7ec6 Mon Sep 17 00:00:00 2001 From: LR <107395524+VWSCoronaDashboard26@users.noreply.github.com> Date: Wed, 30 Nov 2022 12:30:22 +0100 Subject: [PATCH 07/16] bugfix(general): updated general typography styles to always make anchor elements underlined when associated props are supplied; rewrote (parts of) the styled component; (#4516) Co-authored-by: VWSCoronaDashboard26 --- packages/app/src/components/typography.tsx | 108 ++++++++++--------- packages/app/src/domain/layout/gm-layout.tsx | 33 ++---- 2 files changed, 67 insertions(+), 74 deletions(-) diff --git a/packages/app/src/components/typography.tsx b/packages/app/src/components/typography.tsx index bff978e848..300b21d227 100644 --- a/packages/app/src/components/typography.tsx +++ b/packages/app/src/components/typography.tsx @@ -1,4 +1,4 @@ -import { Color } from '@corona-dashboard/common'; +import { Color, colors } from '@corona-dashboard/common'; import css, { CSSProperties } from '@styled-system/css'; import styled, { DefaultTheme } from 'styled-components'; import { Preset, preset } from '~/style/preset'; @@ -13,20 +13,7 @@ export interface TextProps { ariaLabel?: string; } -export interface AnchorProps extends TextProps { - underline?: boolean | 'hover'; - hoverColor?: TextProps['color']; - display?: string; - width?: string | number; -} - -export interface HeadingProps extends TextProps { - level: HeadingLevel; -} - -export type HeadingLevel = 1 | 2 | 3 | 4 | 5; - -function textStyle(props: TextProps & { as?: string }) { +export const textStyle = (props: TextProps & { as?: string }) => { return css({ ...(props.as === 'button' ? { @@ -40,16 +27,13 @@ function textStyle(props: TextProps & { as?: string }) { : undefined), ...(props.variant ? preset.typography[props.variant] : undefined), - ...(props.fontWeight ? { fontWeight: props.fontWeight } : undefined), ...(props.color ? { color: props.color } : undefined), - ...(props.textTransform - ? { textTransform: props.textTransform } - : undefined), + ...(props.textTransform ? { textTransform: props.textTransform } : undefined), ...(props.textAlign ? { textAlign: props.textAlign } : undefined), ...(props.hyphens ? { hyphens: props.hyphens } : undefined), }); -} +}; export const Text = styled.p(textStyle); @@ -57,40 +41,62 @@ export const InlineText = styled.span(textStyle); export const BoldText = styled.strong(textStyle); -export const Anchor = styled.a( - textStyle, - (props) => - props.underline && - css({ - textDecoration: props.underline === 'hover' ? 'none' : 'underline', - '&:hover, &:focus': { - span: { - textDecoration: 'underline', - }, - }, - }), - (props) => - props.hoverColor && - css({ - '&:hover,&:focus': { color: 'blue8' }, - }), - (props) => - props.display && - css({ - display: props.display, - }) -); +export interface AnchorProps extends TextProps { + underline?: boolean | 'hover'; + hoverColor?: TextProps['color']; + display?: string; + width?: string | number; +} + +export const Anchor = styled.a` + ${textStyle} + ${({ underline }) => + underline + ? ` + cursor: pointer; + text-decoration: ${underline === 'hover' ? 'none' : 'underline'}; + + &:hover, + &:focus { + text-decoration: underline; -export const Heading = styled.h1.attrs( - (props: HeadingProps & { as?: string }) => ({ - as: props.as ?? (`h${props.level}` as const), - variant: props.variant ?? (`h${props.level}` as const), - }) -)(textStyle); + span { + text-decoration: underline; + } + } + ` + : undefined} + ${({ hoverColor }) => + hoverColor + ? ` + &:hover, + &:focus { + color: ${colors.blue8}; + } + ` + : undefined} + ${({ display }) => + display + ? ` + display: ${display}; + ` + : undefined} +`; -export function styledTextVariant(variant: string, as?: string) { +export interface HeadingProps extends TextProps { + level: HeadingLevel; +} + +export type HeadingLevel = 1 | 2 | 3 | 4 | 5; + +export const Heading = styled.h1.attrs((props: HeadingProps & { as?: string }) => ({ + as: props.as ?? (`h${props.level}` as const), + variant: props.variant ?? (`h${props.level}` as const), +}))(textStyle); + +export const styledTextVariant = (variant: string, as?: string) => { return styled.p.attrs(() => ({ as: as ?? 'p', variant, })); -} +}; diff --git a/packages/app/src/domain/layout/gm-layout.tsx b/packages/app/src/domain/layout/gm-layout.tsx index 22c976673a..b36b42da99 100644 --- a/packages/app/src/domain/layout/gm-layout.tsx +++ b/packages/app/src/domain/layout/gm-layout.tsx @@ -4,9 +4,10 @@ import { Menu, MenuRenderer } from '~/components/aside/menu'; import { Box } from '~/components/base'; import { ErrorBoundary } from '~/components/error-boundary'; import { AppContent } from '~/components/layout/app-content'; -import { Heading, Text } from '~/components/typography'; +import { Anchor, Heading, Text } from '~/components/typography'; import { VisuallyHidden } from '~/components/visually-hidden'; import { useIntl } from '~/intl'; +import { space } from '~/style/theme'; import { getVrForMunicipalityCode } from '~/utils/get-vr-for-municipality-code'; import { Link } from '~/utils/link'; import { useReverseRouter } from '~/utils/use-reverse-router'; @@ -64,10 +65,7 @@ export function GmLayout(props: GmLayoutProps) { layout: 'gm', code: code, map: [ - [ - 'development_of_the_virus', - ['sewage_measurement', 'positive_tests', 'mortality'], - ], + ['development_of_the_virus', ['sewage_measurement', 'positive_tests', 'mortality']], ['consequences_for_healthcare', ['hospital_admissions']], ['actions_to_take', ['vaccinations']], ], @@ -76,23 +74,14 @@ export function GmLayout(props: GmLayoutProps) { return ( <> - - + + + } @@ -107,21 +96,19 @@ export function GmLayout(props: GmLayoutProps) { aria-labelledby="sidebar-title" role="navigation" maxWidth={{ _: '38rem', md: undefined }} - mx="auto" + marginX="auto" spacing={1} > - + - - {commonTexts.gemeente_layout.headings.sidebar} - + {commonTexts.gemeente_layout.headings.sidebar} {municipalityName} {vr && ( {commonTexts.common.veiligheidsregio_label}{' '} - {vr.name} + {vr.name} )} From 288cd30d730c5bbe7cf791f989110e89509fd7fe Mon Sep 17 00:00:00 2001 From: HO <93981322+VWSCoronaDashboard19@users.noreply.github.com> Date: Wed, 30 Nov 2022 14:39:47 +0100 Subject: [PATCH 08/16] feat: Add new Sanity field for collection title (#4521) --- packages/app/src/pages/landelijk/geldende-adviezen.tsx | 5 +++-- packages/app/src/types/cms.d.ts | 1 + packages/cms/src/schemas/measures/measures.ts | 6 ++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/app/src/pages/landelijk/geldende-adviezen.tsx b/packages/app/src/pages/landelijk/geldende-adviezen.tsx index bcb3947eaf..af9688265e 100644 --- a/packages/app/src/pages/landelijk/geldende-adviezen.tsx +++ b/packages/app/src/pages/landelijk/geldende-adviezen.tsx @@ -41,7 +41,8 @@ export const getStaticProps = createGetStaticProps( } }, 'title':title.${locale}, - 'description': description.${locale} + 'description': description.${locale}, + 'collectionTitle': collectionTitle.${locale} }, }`; }) @@ -70,7 +71,7 @@ const NationalRestrictions = (props: StaticProps) => { )} - {measures.title} + {measures.collectionTitle} diff --git a/packages/app/src/types/cms.d.ts b/packages/app/src/types/cms.d.ts index 5f4fd430b0..ad8392e166 100644 --- a/packages/app/src/types/cms.d.ts +++ b/packages/app/src/types/cms.d.ts @@ -174,6 +174,7 @@ export type Measures = { icon: string; title: string; description: RichContentBlock[] | null; + collectionTitle: string; measuresCollection: MeasuresCollection[]; }; declare module 'picosanity' { diff --git a/packages/cms/src/schemas/measures/measures.ts b/packages/cms/src/schemas/measures/measures.ts index aa6f7fe5f8..5f61c45788 100644 --- a/packages/cms/src/schemas/measures/measures.ts +++ b/packages/cms/src/schemas/measures/measures.ts @@ -24,6 +24,12 @@ export const measures = { name: 'description', type: 'localeRichContentBlock', }, + { + title: 'Titel van de groepen', + name: 'collectionTitle', + type: 'localeString', + validation: REQUIRED, + }, { title: 'Groepen', description: 'De maatregelen zijn onderverdeeld in groepen', From dfb6511e56e1e4eff902921cc0afa0f394d3f181 Mon Sep 17 00:00:00 2001 From: HO <93981322+VWSCoronaDashboard19@users.noreply.github.com> Date: Wed, 30 Nov 2022 14:40:05 +0100 Subject: [PATCH 09/16] feat(README) update and reorder docs (#4520) - Update documentation for new code conventions - Reorder the Code Conventions part of the document, because of it growth --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 201cb17690..6f548f841c 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,8 @@ documentation of the [app](/packages/app/README.md) and (optionally the) Without describing in detail all the rules we tend to follow here are some worth noting: +#### General + - All filenames are written in kebab-case. - We use named exports where possible. They improve typing and help refactoring. - We aim to stop using barrel files (using an index file in a folder to bundle exports for the consuming code). @@ -91,12 +93,21 @@ noting: - We avoid using `boolean && doSomething();` inside the component's JavaScript logic, but do use it inside the component's JSX (`{boolean && ( ... )}`) to conditionally render (parts of) the component. - We avoid unnecessary short-hand variable names like `arr` for array or `i` for index or `acc` for a `reduce` accumulator. + +- Completely separate Javascript logic from HTML/JSX. This means also remove maps from the JSX. Additionally, if you have nested maps extract them into components passing the required data to map to the component. +- We prefer early returns. If statements should be on multiple lines, so no single line if statements. + +#### Styling - We write Styled Components using its OOTB tagged template literal functions instead of using an additional layer of the Styled System's `css()` method. This method improves readability, makes code easier to understand and sticks to the fundamentals of CSS. This method still allows for usage of Styled System's theme definitions, yet removes a dependency on the actual package. - We included a `Styled`-prefix when creating Styled Components. This makes them easily distinguishable from other components. Examples would be `StyledInput` or `StyledTile`. - We avoid using magic numbers in code, be it logic, JSX or styles. Magic numbers are often derived from the theme defined by Styled System and resolve to properties such as spacing and font-sizes, but are unclear on its own. Instead, we import the desired property and refer to the index in that properties array. An example would be `padding: 3` (undesired) vs `padding: space[3]` (desired). + +#### GIT + - We do not have a hard preference or requirement for using `git rebase` or `git merge`. Developers should follow what works best for them, but it should be noted that both methods are allowed and actively used in this project. - We do not have a hard preference or requirement for squashing a multitude of git commits, but it can be useful to apply this when creating a pull request. This action should be used on an 'as-needed basis': if a pull request grows large due to a large amount of commits, it might improve reviewability when multiple commits are squashed. It should be noted that pull requests are squashed when merged, aside from pull requests to `master`. This is to keep a clear view of features and fixes that were merged as part of a release. - Continuing on the above: we should write a comprehensive commit message when squash merging a pull request. This message should be a (filtered) summary of the commits on the branch. + - We use the following branch names: - `feature/COR-XXX-descriptive-name-of-ticket-branch` for features - `bugfix/COR-XXX-descriptive-name-of-ticket-branch` for bug fixes From 16d9c5cd0811fbb3ae371d1d54e60f0a213d5d12 Mon Sep 17 00:00:00 2001 From: LR <107395524+VWSCoronaDashboard26@users.noreply.github.com> Date: Thu, 1 Dec 2022 10:09:33 +0100 Subject: [PATCH 10/16] feature/COR-694-choropleth-clickable-tooltip (#4519) * updated TooltipContent component so that the entire tooltip becomes a clickable anchor element if a link is supplied, but remains a div element when no link is present; * rewrote the TooltipContent component to leverage/satisfy updated conventions; Co-authored-by: VWSCoronaDashboard26 --- .../choropleth/tooltips/tooltip-content.tsx | 132 +++++++----------- 1 file changed, 52 insertions(+), 80 deletions(-) diff --git a/packages/app/src/components/choropleth/tooltips/tooltip-content.tsx b/packages/app/src/components/choropleth/tooltips/tooltip-content.tsx index 048307e4c3..3005e20e95 100644 --- a/packages/app/src/components/choropleth/tooltips/tooltip-content.tsx +++ b/packages/app/src/components/choropleth/tooltips/tooltip-content.tsx @@ -1,107 +1,79 @@ -import { Location } from '@corona-dashboard/icons'; -import css from '@styled-system/css'; -import { ReactNode } from 'react'; +import { colors } from '@corona-dashboard/common'; +import { ChevronRight, Location } from '@corona-dashboard/icons'; +import { MouseEventHandler, ReactNode } from 'react'; import styled from 'styled-components'; -import { Text } from '~/components/typography'; +import { Box } from '~/components/base'; +import { InlineText, Text } from '~/components/typography'; import { space } from '~/style/theme'; import { useIsTouchDevice } from '~/utils/use-is-touch-device'; -interface IProps { +interface TooltipContentProps { title: string; - onSelect?: (event: React.MouseEvent) => void; link?: string; children?: ReactNode; } -export function TooltipContent(props: IProps) { - const { title, onSelect, link, children } = props; +export const TooltipContent = ({ title, link, children }: TooltipContentProps) => { const isTouch = useIsTouchDevice(); return ( - - + + {title} - {(onSelect || link) && } - - {children && {children}} + {link && } + + + {children && {children}} ); -} +}; -const StyledTooltipContent = styled.div<{ isInteractive: boolean }>((x) => - css({ - color: 'black', - width: '100%', - minWidth: 250, - borderRadius: 1, - cursor: x.onClick ? 'pointer' : 'default', - pointerEvents: x.isInteractive ? undefined : 'none', - }) -); - -function TooltipHeader({ href, children }: { href?: string; children: ReactNode }) { - if (href) { - return ( - - {children} - - ); - } - - return {children}; +interface StyledTooltipContentProps { + isInteractive: boolean; + onClick?: MouseEventHandler; } -const StyledTooltipHeader = styled.div( - css({ - whiteSpace: 'nowrap', - color: 'black', - py: 2, - px: 3, - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - textDecoration: 'none!important', - }) -); +const StyledTooltipContent = styled(Box)` + color: ${colors.black}; + display: flex; + flex-direction: column; + min-width: 250px; + pointer-events: ${({ isInteractive }) => (isInteractive ? undefined : 'none')}; + width: 100%; +`; -const Chevron = styled.div( - css({ - ml: 3, - backgroundImage: 'url("/icons/chevron-black.svg")', - backgroundSize: '0.5em 0.9em', - backgroundPosition: '0 50%', - backgroundRepeat: 'no-repeat', - width: '0.5em', - height: '1em', - display: 'block', - }) -); +const StyledTooltipHeader = styled(Box)` + align-items: center; + display: flex; + justify-content: space-between; + padding: ${space[2]} ${space[3]}; + white-space: nowrap; +`; -const TooltipInfo = styled.div( - css({ - cursor: 'pointer', - borderTop: '1px solid', - borderTopColor: 'gray3', - padding: `${space[2]} ${space[3]}`, - }) -); +const StyledChevronRight = styled(ChevronRight)` + color: ${colors.black}; + height: ${space[3]}; +`; -const StyledLocationIcon = styled.span( - css({ - whiteSpace: 'nowrap', - display: 'inline-block', - mr: 2, +const StyledTooltipInfo = styled(Box)` + border-top: 1px solid ${colors.gray3}; + cursor: pointer; + padding: ${space[2]} ${space[3]}; +`; - svg: { - pt: '3px', - color: 'black', - width: 16, - height: 17, - }, - }) -); +const StyledLocationIcon = styled(InlineText)` + color: ${colors.black}; + margin-right: ${space[2]}; + white-space: nowrap; + + svg { + height: 18px; + padding-top: 3px; + width: 18px; + } +`; From 88f5b49d9cd5d296f442e63e14854fd3bfc4bf51 Mon Sep 17 00:00:00 2001 From: VWSCoronaDashboard27 <111750729+VWSCoronaDashboard27@users.noreply.github.com> Date: Thu, 1 Dec 2022 10:11:43 +0100 Subject: [PATCH 11/16] feat: COR-1087: Applied a new button design (#4511) * feat: applied a new button design * fix: resolved conversation * fix: resolved conversation * fix: fixing styling of the button outline * fix: fixing styling of the button outline Co-authored-by: VWSCoronaDashboard27 --- .../app/src/components/article-detail.tsx | 75 +++++++------------ 1 file changed, 29 insertions(+), 46 deletions(-) diff --git a/packages/app/src/components/article-detail.tsx b/packages/app/src/components/article-detail.tsx index 06f13790e3..9ceda5a756 100644 --- a/packages/app/src/components/article-detail.tsx +++ b/packages/app/src/components/article-detail.tsx @@ -3,7 +3,7 @@ import styled from 'styled-components'; import { ArrowIconLeft } from '~/components/arrow-icon'; import { Box } from '~/components/base'; import { ContentBlock } from '~/components/cms/content-block'; -import { Heading, InlineText } from '~/components/typography'; +import { Heading, InlineText, Anchor } from '~/components/typography'; import { ArticleCategoryType } from '~/domain/topical/common/categories'; import { useIntl } from '~/intl'; import { SiteText } from '~/locale'; @@ -15,6 +15,8 @@ import { RichContent } from './cms/rich-content'; import { LinkWithIcon } from './link-with-icon'; import { PublicationDate } from './publication-date'; import { useBreakpoints } from '~/utils/use-breakpoints'; +import { colors } from '@corona-dashboard/common'; +import { space } from '~/style/theme'; interface ArticleDetailProps { article: Article; text: SiteText['pages']['topical_page']['shared']; @@ -50,29 +52,17 @@ export function ArticleDetail({ article, text }: ArticleDetailProps) { - + {!breakpoints.xs ? article.imageMobile && ( - + ) : article.imageDesktop && ( - + )} {!!article.content?.length && ( @@ -93,9 +83,7 @@ export function ArticleDetail({ article, text }: ArticleDetailProps) { {article.categories && ( - - {text.secties.artikelen.tags} - + {text.secties.artikelen.tags} - - { - text.secties.artikelen.categorie_filters[ - item as ArticleCategoryType - ] - } - + {text.secties.artikelen.categorie_filters[item as ArticleCategoryType]} ))} @@ -134,25 +116,26 @@ export function ArticleDetail({ article, text }: ArticleDetailProps) { ); } -const TagAnchor = styled.a( - css({ - display: 'block', - border: '2px solid transparent', - mb: 3, - px: 3, - py: 2, - backgroundColor: 'blue3', - color: 'blue8', - textDecoration: 'none', - transition: '0.1s border-color', +const StyledTagAnchor = styled(Anchor)` + border-radius: 5px; + border: 2px solid ${colors.gray4}; + color: ${colors.black}; + display: block; + margin-bottom: ${space[3]}; + padding: ${space[2]} ${space[3]}; - '&:hover': { - borderColor: 'blue8', - }, + &:focus:focus-visible { + outline: 2px dotted ${colors.blue8}; + } - '&:focus': { - outline: '2px dotted', - outlineColor: 'blue8', - }, - }) -); + &:hover { + background: ${colors.blue8}; + border: 2px solid ${colors.blue8}; + color: ${colors.white}; + text-shadow: 0.5px 0px 0px ${colors.white}, -0.5px 0px 0px ${colors.white}; + + &:focus-visible { + outline: 2px dotted ${colors.magenta3}; + } + } +`; From 5f8fa6f6f81c62afdaa01a7417f375264e942cf9 Mon Sep 17 00:00:00 2001 From: J <93984341+VWSCoronaDashboard18@users.noreply.github.com> Date: Mon, 5 Dec 2022 14:37:54 +0100 Subject: [PATCH 12/16] Added middelOfDay integration (#4524) --- packages/app/src/pages/landelijk/gedrag.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/app/src/pages/landelijk/gedrag.tsx b/packages/app/src/pages/landelijk/gedrag.tsx index caf669b4c2..bfc58de97c 100644 --- a/packages/app/src/pages/landelijk/gedrag.tsx +++ b/packages/app/src/pages/landelijk/gedrag.tsx @@ -1,5 +1,6 @@ import { Bevolking } from '@corona-dashboard/icons'; import { GetStaticPropsContext } from 'next'; +import { middleOfDayInSeconds } from '@corona-dashboard/common'; import { useMemo, useRef, useState } from 'react'; import { Box } from '~/components/base'; import { Markdown } from '~/components/markdown'; @@ -99,8 +100,8 @@ export default function BehaviorPage(props: StaticProps) .map((event) => ({ title: event[`message_title_${locale}`], description: event[`message_desc_${locale}`], - start: event.date_start_unix, - end: event.date_end_unix, + start: middleOfDayInSeconds(event.date_start_unix), + end: middleOfDayInSeconds(event.date_end_unix), })); return { currentTimelineEvents }; From 2d774929052ec82818a06c2304bd52ff925215d0 Mon Sep 17 00:00:00 2001 From: AT <93994194+VWSCoronaDashboard21@users.noreply.github.com> Date: Mon, 5 Dec 2022 15:02:13 +0100 Subject: [PATCH 13/16] bugfix/COR-1001-scaling-tooltip-width (#4523) * fix: tooltip max-width to 440px * fix: partly changed styled system to styled components * fix: wip styled components * fix: changed StyledTriangleWrapper styled component * fix: changed all styled system to styled components Co-authored-by: VWSCoronaDashboard21 --- .../components/tooltip/tooltip-wrapper.tsx | 198 +++++++++--------- packages/app/src/style/theme.ts | 2 +- 2 files changed, 100 insertions(+), 100 deletions(-) diff --git a/packages/app/src/components/time-series-chart/components/tooltip/tooltip-wrapper.tsx b/packages/app/src/components/time-series-chart/components/tooltip/tooltip-wrapper.tsx index a91e318a2e..9542ae5f08 100644 --- a/packages/app/src/components/time-series-chart/components/tooltip/tooltip-wrapper.tsx +++ b/packages/app/src/components/time-series-chart/components/tooltip/tooltip-wrapper.tsx @@ -1,7 +1,7 @@ import { colors } from '@corona-dashboard/common'; -import css from '@styled-system/css'; import { ReactNode } from 'react'; import styled from 'styled-components'; +import { space, fontSizes, shadows } from '~/style/theme'; import { isDefined } from 'ts-is-present'; import { BoldText } from '~/components/typography'; import { useBoundingBox } from '~/utils/use-bounding-box'; @@ -28,14 +28,7 @@ const VIEWPORT_PADDING = 10; * * @TODO clean up calculations in Tooltip component */ -export function TooltipWrapper({ - title, - children, - left, - top: _top, - bounds, - padding, -}: TooltipWrapperProps) { +export function TooltipWrapper({ title, children, left, top: _top, bounds, padding }: TooltipWrapperProps) { const viewportSize = useViewport(); const isMounted = useIsMounted({ delayMs: 10 }); const [ref, { width = 0, height = 0 }] = useResizeObserver(); @@ -44,10 +37,7 @@ export function TooltipWrapper({ const targetY = -height; const targetX = left + padding.left; - const maxWidth = Math.min( - bounds.width + padding.left + padding.right, - viewportSize.width - VIEWPORT_PADDING * 2 - ); + const maxWidth = Math.min(bounds.width + padding.left + padding.right, viewportSize.width - VIEWPORT_PADDING * 2); const relativeLeft = boundingBox?.left ?? 0; @@ -66,10 +56,10 @@ export function TooltipWrapper({ return ( <>
- {children} - +
); } +interface StyledTooltipContainerProps { + isMounted: boolean; +} + +const StyledTooltipContainer = styled.div` + background: ${colors.white}; + border-radius: 1px; + box-shadow: ${shadows.tooltip}; + opacity: ${(props) => (props.isMounted ? 1 : 0)}; + pointer-events: none; + position: absolute; + top: 0; + will-change: transform; + z-index: 1000; +`; + interface TriangleProps { + isMounted: boolean; left: number; top: number; - isMounted: boolean; } function Triangle({ left, top, isMounted }: TriangleProps) { return ( -
-
+ ); } -const StyledTriangle = styled.div<{ width: number }>((x) => { - /** - * 🙏 pythagoras - */ - const borderWidth = Math.sqrt(Math.pow(x.width, 2) / 2) / 2; - - return css({ - position: 'relative', - width: 0, - height: 0, - marginLeft: -borderWidth, - boxSizing: 'border-box', - borderWidth, - borderStyle: 'solid', - borderColor: 'transparent transparent white white', - transformOrigin: '0 0', - transform: 'rotate(-45deg)', - boxShadow: `-3px 3px 3px 0 ${colors.blackOpacity}`, - }); -}); - -const TooltipContainer = styled.div( - css({ - position: 'absolute', - bg: 'white', - boxShadow: 'tooltip', - pointerEvents: 'none', - zIndex: 1000, - borderRadius: 1, - top: 0, - willChange: 'transform', - }) -); +interface StyledTriangleWrapperProps { + isMounted: boolean; +} + +const StyledTriangleWrapper = styled.div` + left: 0; + opacity: ${(props) => (props.isMounted ? 1 : 0)}; + pointer-events: none; + position: absolute; + top: 0; + z-index: 1010; +`; + +interface StyledTriangleProps { + width: number; +} + +const calcPythagoras = (width: number) => Math.sqrt(Math.pow(width, 2) / 2) / 2; + +const StyledTriangle = styled.div` + border-color: ${colors.transparent} ${colors.transparent} ${colors.white} ${colors.white}; + border-style: solid; + border-width: ${(props) => calcPythagoras(props.width)}px; + box-shadow: -3px 3px 3px 0 ${colors.blackOpacity}; + box-sizing: border-box; + height: 0; + margin-left: -${(props) => calcPythagoras(props.width)}px; + position: relative; + transform-origin: 0 0; + transform: rotate(-45deg); + width: 0; +`; interface TooltipContentProps { - title?: string; - onSelect?: (event: React.MouseEvent) => void; children?: ReactNode; + onSelect?: (event: React.MouseEvent) => void; + title?: string; } function TooltipContent(props: TooltipContentProps) { @@ -159,50 +157,52 @@ function TooltipContent(props: TooltipContentProps) { return ( {title && } - {children && ( - - {children} - - )} + {children && {children}} ); } function TooltipHeading({ title }: { title: string }) { return ( -
+ {title} -
+ ); } -const TooltipChildren = styled.div<{ hasTitle?: boolean }>(({ hasTitle }) => - css({ - borderTop: hasTitle ? '1px solid' : '', - borderTopColor: hasTitle ? 'gray3' : '', - py: 2, - px: 3, - }) -); - -const StyledTooltipContent = styled.div((x) => - css({ - color: 'black', - maxWidth: 425, - borderRadius: 1, - cursor: x.onClick ? 'pointer' : 'default', - fontSize: 1, - }) -); +interface StyledTooltipContentProps { + onClick?: (event: React.MouseEvent) => void; +} + +const StyledTooltipContent = styled.div` + border-radius: 1px; + color: ${colors.black}; + cursor: ${(props) => (props.onClick ? 'pointer' : 'default')}; + font-size: ${fontSizes[1]}; + max-width: 440px; +`; + +interface StyledTooltipHeadingWrapperProps { + title?: string; +} + +const StyledTooltipHeadingWrapper = styled.div` + align-items: center; + color: ${colors.black}; + display: flex; + justify-content: space-between; + overflow: hidden; + padding: ${space[2]} ${space[3]}; + text-overflow: ellipsis; + white-space: nowrap; +`; + +interface StyledTooltipChildrenProps { + hasTitle?: boolean; +} + +const StyledTooltipChildren = styled.div` + border-top: ${(props) => (props.hasTitle ? '1px solid' : '')}; + border-top-color: ${(props) => (props.hasTitle ? colors.gray3 : '')}; + padding: ${space[2]} ${space[3]}; +`; diff --git a/packages/app/src/style/theme.ts b/packages/app/src/style/theme.ts index 6a8738915b..99811ab972 100644 --- a/packages/app/src/style/theme.ts +++ b/packages/app/src/style/theme.ts @@ -89,7 +89,7 @@ const mediaQueries = { const radii = [0, 5, 10]; -const shadows = { +export const shadows = { tile: '0px 4px 8px rgba(0, 0, 0, 0.1)', tooltip: '0px 2px 12px rgba(0, 0, 0, 0.1)', } as const; From 855e52c8803996eed9ccb3d1370029ff52cb1660 Mon Sep 17 00:00:00 2001 From: AP <116002914+VWSCoronaDashboard28@users.noreply.github.com> Date: Tue, 6 Dec 2022 13:26:52 +0100 Subject: [PATCH 14/16] Feature/COR-1149 adjust hoverstate styling of choropleth (#4522) * feat(COR-1149): Added border logic for outside borders and applied drop-shadow * feat(COR-1149): Implements same design for tabstate as hover. Attempts to fix bug related to waterbodies in Zeeland. * feat(COR-1149): Added a comment. * Update packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx * feat(choropleth): PR feedback adjustments Co-authored-by: VWSCoronaDashboard18 <93984341+VWSCoronaDashboard18@users.noreply.github.com> --- .../components/canvas-choropleth-map.tsx | 75 +++++++++++++------ .../choropleth/logic/use-feature-props.ts | 63 ++++------------ 2 files changed, 65 insertions(+), 73 deletions(-) diff --git a/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx b/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx index b6f29e0142..c33d90d710 100644 --- a/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx +++ b/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx @@ -16,7 +16,7 @@ import type { AnchorEventHandler } from './choropleth-map'; Konva.pixelRatio = typeof window !== 'undefined' ? Math.min(window.devicePixelRatio, 2) : 1; -export type CanvasChoroplethMapProps = { +export interface CanvasChoroplethMapProps { anchorEventHandlers: AnchorEventHandler; annotations: AccessibilityAnnotations; choroplethFeatures: ChoroplethFeatures; @@ -33,7 +33,7 @@ export type CanvasChoroplethMapProps = { mapProjection: () => GeoProjection; tooltipTrigger: ChoroplethTooltipHandlers[2]; width: number; -}; +} /** * This is one transparent pixel encoded in a dataUrl. This is used for the image overlay on top of the canvas that @@ -181,12 +181,12 @@ export const CanvasChoroplethMap = (props: CanvasChoroplethMapProps) => { ); }; -type HighlightedFeatureProps = { +interface HighlightedFeatureProps { feature: [number, number][][] | undefined; featureProps: FeatureProps; code: string | undefined; hoverCode: string | undefined; -}; +} const HighlightedFeature = memo((props: HighlightedFeatureProps) => { const { feature, featureProps, code, hoverCode } = props; @@ -212,13 +212,13 @@ const HighlightedFeature = memo((props: HighlightedFeatureProps) => { ); }); -type HoveredFeatureProps = { +interface HoveredFeatureProps { hoveredRef: RefObject; hover: [number, number][][] | undefined; hoverCode: string | undefined; featureProps: FeatureProps; isKeyboardActive?: boolean; -}; +} const HoveredFeature = memo((props: HoveredFeatureProps) => { const { hoveredRef, hover, hoverCode, featureProps, isKeyboardActive } = props; @@ -227,30 +227,58 @@ const HoveredFeature = memo((props: HoveredFeatureProps) => { return null; } + /** + * The code in the condition below is a workaround. + * + * This is required as for some reason, the water bodies also get rendered as a Feature (you can see another fix for this in the + * Features component below). As a consequence, when making the fix introduced in COR-1149 which required adding an additional + * line to the HoveredFeature, the water bodies ended up receiving the same fill colour as the land around them and thereby masking + * the white water body. + * + * To fix this, there are now two maps iterating over two arrays for Zeeland. One represents land and the other, water. + */ + let landCoords: [number, number][][] = [...hover]; + let waterCoords: [number, number][][] | undefined; + if (hoverCode === 'VR19') { + landCoords = hover.filter((_, index) => index === 0 || index === 5); + waterCoords = hover.filter((_, index) => !(index === 0 || index === 5)); + } + return ( - {hover.map((x, i) => ( - + {landCoords.map((coordinates, index) => ( + <> + + {/* The additional line is used as an overlay on the original to make it seem like the stroke on the original line is on the outside */} + + + ))} + {waterCoords?.map((coordinates, index) => ( + ))} ); }); -type OutlinesProps = { +interface OutlinesProps { geoInfo: ProjectedGeoInfo[]; featureProps: FeatureProps; -}; +} const Outlines = memo((props: OutlinesProps) => { const { geoInfo, featureProps } = props; @@ -276,11 +304,11 @@ const Outlines = memo((props: OutlinesProps) => { ); }); -type FeaturesProps = { +interface FeaturesProps { geoInfo: ProjectedGeoInfo[]; featureProps: FeatureProps; children: React.ReactNode; -}; +} const Features = memo((props: FeaturesProps) => { const { geoInfo, featureProps, children } = props; @@ -336,7 +364,7 @@ const Features = memo((props: FeaturesProps) => { ); }); -type AreaMapProps = { +interface AreaMapProps { isTabInteractive: boolean; geoInfo: ProjectedGeoInfo[]; getLink?: (code: string) => string; @@ -347,7 +375,7 @@ type AreaMapProps = { handleMouseOver: (event: MouseEvent) => void; height: number; width: number; -}; +} type GeoInfoGroup = { code: string; @@ -383,6 +411,7 @@ function AreaMap(props: AreaMapProps) { = (code: string) => T; -type GetHoverFeatureProp = ( - code: string, - isActivated?: boolean, - isKeyboardActive?: boolean -) => T; +type GetHoverFeatureProp = (code: string, isActivated?: boolean, isKeyboardActive?: boolean) => T; export type FeatureProps = { /** @@ -39,7 +35,7 @@ type FeaturePropFunctions = { export const DEFAULT_STROKE_WIDTH = 0.5; -export const DEFAULT_HOVER_STROKE_WIDTH = 3; +export const DEFAULT_HOVER_STROKE_WIDTH = 6; /** * This hook returns the visual props for the map features based on the specified map type. @@ -60,10 +56,7 @@ export function useFeatureProps( dataOptions: DataOptions, dataConfig: DataConfig ): FeatureProps { - return useMemo( - () => getFeatureProps(map, getFillColor, dataOptions, dataConfig), - [map, getFillColor, dataOptions, dataConfig] - ); + return useMemo(() => getFeatureProps(map, getFillColor, dataOptions, dataConfig), [map, getFillColor, dataOptions, dataConfig]); } export function getFeatureProps( @@ -83,38 +76,17 @@ export function getFeatureProps( strokeWidth: () => dataConfig.areaStrokeWidth, }, hover: { - fill: (_code: string, isHover?: boolean) => - isHover ? dataConfig.hoverFill : 'none', + fill: (_code: string) => getFillColor(_code), stroke: !dataOptions.highlightSelection || !dataOptions.selectedCode - ? ( - _code: string, - isActivated?: boolean, - isKeyboardActive?: boolean - ) => - isActivated - ? isKeyboardActive - ? dataConfig.highlightStroke - : dataConfig.hoverStroke - : 'none' + ? (_code: string, isActivated?: boolean, isKeyboardActive?: boolean) => + isActivated ? (isKeyboardActive ? dataConfig.highlightStroke : dataConfig.hoverStroke) : 'none' : (code: string, isActivated?: boolean) => - code === dataOptions.selectedCode - ? isActivated - ? dataConfig.hoverStroke - : dataConfig.highlightStroke - : isActivated - ? dataConfig.hoverStroke - : 'none', + code === dataOptions.selectedCode ? (isActivated ? dataConfig.hoverStroke : dataConfig.highlightStroke) : isActivated ? dataConfig.hoverStroke : 'none', strokeWidth: !dataOptions.highlightSelection || !dataOptions.selectedCode - ? (_code: string, isActivated?: boolean) => - isActivated ? dataConfig.hoverStrokeWidth : 0 - : (code: string, isActivated?: boolean) => - code === dataOptions.selectedCode - ? dataConfig.highlightStrokeWidth - : isActivated - ? dataConfig.hoverStrokeWidth - : 0, + ? (_code: string, isActivated?: boolean) => (isActivated ? dataConfig.hoverStrokeWidth : 0) + : (code: string, isActivated?: boolean) => (code === dataOptions.selectedCode ? dataConfig.highlightStrokeWidth : isActivated ? dataConfig.hoverStrokeWidth : 0), }, outline: { fill: () => 'transparent', @@ -133,19 +105,10 @@ export function getFeatureProps( strokeWidth: () => dataConfig.areaStrokeWidth, }, hover: { - fill: () => 'none', - stroke: ( - _code: string, - isActivated?: boolean, - isKeyboardActive?: boolean - ) => - isActivated - ? isKeyboardActive - ? dataConfig.highlightStroke - : dataConfig.hoverStroke - : 'none', - strokeWidth: (_code: string, isActivated?: boolean) => - isActivated ? dataConfig.hoverStrokeWidth : 0, + fill: (_code: string) => getFillColor(_code), + stroke: (_code: string, isActivated?: boolean, isKeyboardActive?: boolean) => + isActivated ? (isKeyboardActive ? dataConfig.highlightStroke : dataConfig.hoverStroke) : 'none', + strokeWidth: (_code: string, isActivated?: boolean) => (isActivated ? dataConfig.hoverStrokeWidth : 0), }, outline: { fill: () => 'none', From ba45ba255c0fc146a4801e334bdef16c6f52ee64 Mon Sep 17 00:00:00 2001 From: AP <116002914+VWSCoronaDashboard28@users.noreply.github.com> Date: Wed, 7 Dec 2022 10:09:25 +0100 Subject: [PATCH 15/16] Feature/COR-1178: Change trend icons kpi tile (#4527) * feat(theme-tiles): Adds a new field to select the intensity for the trend icon. * feat(theme-tiles): Adds a new field to the topical structure query and changes double quotes to single quotes. * feat(KPI-tiles): Adjusts the trend icon component to render out a new icon for the homepage which takes intensity level into consideration. Co-authored-by: VWSCoronaDashboard26 VWSCoronaDashboard26@users.noreply.github.com * feat(KPI-tiles): Updates component name, adjusts styling, adds a comment. * feat(KPI-tiles): PR feedback: Added a comment, refactored styling, changed sanity labels. * feat(KPI-tiles): Remove no stroke comment and remove stroke property from intensity level 3. --- packages/app/schema/topical/icon.json | 1 + packages/app/src/components/trend-icon.tsx | 65 ++++++++++++++++--- .../topical/components/topical-tile.tsx | 15 +---- packages/app/src/domain/topical/types.ts | 1 + .../queries/get-topical-structure-query.ts | 27 ++++---- .../cms/src/schemas/topical/trend-icon.ts | 15 +++++ packages/icons/icons.md | 1 + packages/icons/src/icon-name2filename.ts | 2 + .../icons/src/svg/arrow_with_intensity.svg | 27 ++++++++ 9 files changed, 120 insertions(+), 34 deletions(-) create mode 100644 packages/icons/src/svg/arrow_with_intensity.svg diff --git a/packages/app/schema/topical/icon.json b/packages/app/schema/topical/icon.json index 9af0334a15..36b96d0c0e 100644 --- a/packages/app/schema/topical/icon.json +++ b/packages/app/schema/topical/icon.json @@ -7,6 +7,7 @@ "AlcoholVerkoop", "Archive", "Arrow", + "ArrowWithIntensity", "Arts", "Avondklok", "BarChart", diff --git a/packages/app/src/components/trend-icon.tsx b/packages/app/src/components/trend-icon.tsx index 27d430de4b..fb51f19d53 100644 --- a/packages/app/src/components/trend-icon.tsx +++ b/packages/app/src/components/trend-icon.tsx @@ -1,33 +1,82 @@ +import { colors } from '@corona-dashboard/common'; +import { Down, Dot, Up, ArrowWithIntensity } from '@corona-dashboard/icons'; +import styled from 'styled-components'; import { useIntl } from '~/intl'; -import { Down, Dot, Up } from '@corona-dashboard/icons'; +import { space } from '~/style/theme'; export enum TrendDirection { UP, DOWN, NEUTRAL, } + interface TrendIconProps { trendDirection: TrendDirection; + intensity?: number | null; + color?: string | null; ariaLabel?: string; } -export const TrendIcon = ({ trendDirection, ariaLabel }: TrendIconProps) => { +export const TrendIcon = ({ trendDirection, ariaLabel, intensity = null, color = null }: TrendIconProps) => { const { commonTexts } = useIntl(); - const TrendLabelUp = ariaLabel || commonTexts.accessibility.visual_context_labels.up_trend_label; - const TrendLabelDown = ariaLabel || commonTexts.accessibility.visual_context_labels.down_trend_label; - const TrendLabelNeutral = ariaLabel || commonTexts.accessibility.visual_context_labels.neutral_trend_label; + const trendLabels: { [key: string]: string } = { + up: ariaLabel || commonTexts.accessibility.visual_context_labels.up_trend_label, + down: ariaLabel || commonTexts.accessibility.visual_context_labels.down_trend_label, + neutral: ariaLabel || commonTexts.accessibility.visual_context_labels.neutral_trend_label, + }; + + const ariaLabelText = trendLabels[TrendDirection[trendDirection].toLowerCase()]; + + // Icon with intensity is used only on the homepage at the moment, for all other trend icons the default (below) are used. + if (intensity && color && TrendDirection[trendDirection]) { + return ; + } switch (trendDirection) { case TrendDirection.UP: - return ; + return ; case TrendDirection.DOWN: - return ; + return ; case TrendDirection.NEUTRAL: - return ; + return ; default: { const exhaustiveCheck: never = trendDirection; throw new Error(`Unhandled TrendDirection case: ${exhaustiveCheck}`); } } }; + +const intensitySelectors: { [key: number]: { fill: string; stroke?: string } } = { + 1: { + fill: '.one-arrow', + stroke: '.two-stroke, .three-stroke', + }, + 2: { + fill: '.one-arrow, .two-arrows', + stroke: '.three-stroke', + }, + 3: { + fill: '.one-arrow, .two-arrows, .three-arrows', + }, +}; + +interface TrendIconWithIntensityProps { + color: string; + direction: TrendDirection; + intensity: number; +} + +const TrendIconWithIntensity = styled(ArrowWithIntensity)` + flex-shrink: 0; + margin-left: ${space[2]}; + transform: ${({ direction }) => (direction === TrendDirection.DOWN ? 'scaleY(-1)' : undefined)}; + + ${({ intensity, color }): string => + `${intensitySelectors[intensity].fill} { + fill: ${color}; + } + ${intensitySelectors[intensity].stroke} { + stroke: ${colors.gray7}; + }`} +`; diff --git a/packages/app/src/domain/topical/components/topical-tile.tsx b/packages/app/src/domain/topical/components/topical-tile.tsx index 8a1859a384..8dce26d17f 100644 --- a/packages/app/src/domain/topical/components/topical-tile.tsx +++ b/packages/app/src/domain/topical/components/topical-tile.tsx @@ -84,18 +84,14 @@ export function TopicalTile({ title, tileIcon, trendIcon, description, kpiValue, > {title} {!formattedKpiValue && trendIcon.direction && trendIcon.color && ( - - - + )} {formattedKpiValue && ( {trendIcon.direction && trendIcon.color && ( - - - + )} )} @@ -135,13 +131,6 @@ export function TopicalTile({ title, tileIcon, trendIcon, description, kpiValue, ); } -const TrendIconWrapper = styled.span` - color: ${({ color }) => color}; - flex-shrink: 0; - margin-left: ${space[2]}; - width: 20px; -`; - const TileIcon = styled.span` background-color: ${colors.blue8}; border-bottom-left-radius: ${space[1]}; diff --git a/packages/app/src/domain/topical/types.ts b/packages/app/src/domain/topical/types.ts index 2d8dbf2d6e..ca1f7cbd62 100644 --- a/packages/app/src/domain/topical/types.ts +++ b/packages/app/src/domain/topical/types.ts @@ -6,4 +6,5 @@ export type TrendIconDirection = typeof ICON_DIRECTION_UP | typeof ICON_DIRECTIO export type TrendIcon = { direction: TrendIconDirection | null; color: TrendIconColor | null; + intensity: 1 | 2 | 3 | null; }; diff --git a/packages/app/src/queries/get-topical-structure-query.ts b/packages/app/src/queries/get-topical-structure-query.ts index 0249248a93..4667bd0d37 100644 --- a/packages/app/src/queries/get-topical-structure-query.ts +++ b/packages/app/src/queries/get-topical-structure-query.ts @@ -5,13 +5,13 @@ export function getTopicalStructureQuery(locale: string) { const query = `// groq { 'topicalConfig': *[ - _type == 'topicalPageConfig' && !(_id in path("drafts.**")) + _type == 'topicalPageConfig' && !(_id in path('drafts.**')) ][0]{ 'title': title.${locale}, 'description': description.${locale} }, 'weeklySummary': *[ - _type == 'weeklySummary' && !(_id in path("drafts.**")) + _type == 'weeklySummary' && !(_id in path('drafts.**')) ][0]{ 'title': title.${locale}, 'items': items[]->{ @@ -21,30 +21,31 @@ export function getTopicalStructureQuery(locale: string) { }, }, 'kpiThemes': *[ - _type == 'themeCollection' && !(_id in path("drafts.**")) + _type == 'themeCollection' && !(_id in path('drafts.**')) ][0]{ 'themes': themes[]->{ - "title":title.${locale}, - "subTitle":subTitle.${locale}, + 'title':title.${locale}, + 'subTitle':subTitle.${locale}, themeIcon, 'linksLabelMobile': labelMobile.${locale}, 'linksLabelDesktop': labelDesktop.${locale}, - "links":links[]->{ + 'links':links[]->{ 'cta': { 'title': cta.title.${locale}, 'href': cta.href }, }, - "tiles":tiles[]->{ - "description":description.${locale}, + 'tiles':tiles[]->{ + 'description':description.${locale}, tileIcon, - "title":title.${locale}, - "sourceLabel":sourceLabel.${locale}, + 'title':title.${locale}, + 'sourceLabel':sourceLabel.${locale}, 'kpiValue': kpiValue.${locale}, 'trendIcon': { 'color': trendIcon.color, 'direction': trendIcon.direction, + 'intensity': trendIcon.intensity, }, 'cta': { 'title': cta.title.${locale}, @@ -54,7 +55,7 @@ export function getTopicalStructureQuery(locale: string) { }, }, 'measureTheme': *[ - _type == 'measureTheme' && !(_id in path("drafts.**")) + _type == 'measureTheme' && !(_id in path('drafts.**')) ][0]{ 'title': title.${locale}, themeIcon, @@ -65,12 +66,12 @@ export function getTopicalStructureQuery(locale: string) { }, }, 'thermometer': *[ - _type == 'thermometer' && !(_id in path("drafts.**")) + _type == 'thermometer' && !(_id in path('drafts.**')) ][0]{ icon, 'title': title.${locale}, 'subTitle': subTitle.${locale}, - "tileTitle":tileTitle.${locale}, + 'tileTitle':tileTitle.${locale}, currentLevel, 'thermometerLevels': thermometerLevels[]->{ 'level': level, diff --git a/packages/cms/src/schemas/topical/trend-icon.ts b/packages/cms/src/schemas/topical/trend-icon.ts index 645ef52946..170e75659f 100644 --- a/packages/cms/src/schemas/topical/trend-icon.ts +++ b/packages/cms/src/schemas/topical/trend-icon.ts @@ -31,5 +31,20 @@ export const trendIcon = { }, validation: REQUIRED, }, + { + title: 'Intensiteit', + name: 'intensity', + description: 'Beschrijft de intensiteit van relatieve verandering ten opzichte van de vorige meeting.', + type: 'number', + options: { + list: [ + { value: 1, title: '1 pijltje gekleurd' }, + { value: 2, title: '2 pijltjes gekleurd' }, + { value: 3, title: '3 pijltjes gekleurd' }, + ], + layout: 'dropdown', + }, + validation: REQUIRED, + }, ], }; diff --git a/packages/icons/icons.md b/packages/icons/icons.md index ede4332b51..2d10992f0c 100644 --- a/packages/icons/icons.md +++ b/packages/icons/icons.md @@ -8,6 +8,7 @@ See below an overview of all the available icons in this package. This file is g | AlcoholVerkoop |
AlcoholVerkoop
| | Archive |
Archive
| | Arrow |
Arrow
| +| ArrowWithIntensity |
ArrowWithIntensity
| | Arts |
Arts
| | Avondklok |
Avondklok
| | BarChart |
BarChart
| diff --git a/packages/icons/src/icon-name2filename.ts b/packages/icons/src/icon-name2filename.ts index 37d0b3dc65..b772ce9ff4 100644 --- a/packages/icons/src/icon-name2filename.ts +++ b/packages/icons/src/icon-name2filename.ts @@ -3,6 +3,7 @@ export type IconName = | 'AlcoholVerkoop' | 'Archive' | 'Arrow' + | 'ArrowWithIntensity' | 'Arts' | 'Avondklok' | 'BarChart' @@ -135,6 +136,7 @@ export const iconName2filename: Record = { AlcoholVerkoop: 'alcohol_verkoop.svg', Archive: 'archive.svg', Arrow: 'arrow.svg', + ArrowWithIntensity: 'arrow_with_intensity.svg', Arts: 'arts.svg', Avondklok: 'avondklok.svg', BarChart: 'bar_chart.svg', diff --git a/packages/icons/src/svg/arrow_with_intensity.svg b/packages/icons/src/svg/arrow_with_intensity.svg new file mode 100644 index 0000000000..956a73bc49 --- /dev/null +++ b/packages/icons/src/svg/arrow_with_intensity.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + \ No newline at end of file From dc6331b009bc418ffdf7ef208b761e21eb43cf26 Mon Sep 17 00:00:00 2001 From: VWSCoronaDashboard26 Date: Thu, 8 Dec 2022 11:36:31 +0100 Subject: [PATCH 16/16] feat(release): updated TrendIconWithIntensity to have an aria-label; --- packages/app/src/components/trend-icon.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/src/components/trend-icon.tsx b/packages/app/src/components/trend-icon.tsx index fb51f19d53..6cb7051455 100644 --- a/packages/app/src/components/trend-icon.tsx +++ b/packages/app/src/components/trend-icon.tsx @@ -30,7 +30,7 @@ export const TrendIcon = ({ trendDirection, ariaLabel, intensity = null, color = // Icon with intensity is used only on the homepage at the moment, for all other trend icons the default (below) are used. if (intensity && color && TrendDirection[trendDirection]) { - return ; + return ; } switch (trendDirection) {