From ff3fac62360a84751d1fac482c6e14c6711ff64a Mon Sep 17 00:00:00 2001 From: sophiamersmann Date: Tue, 8 Oct 2024 10:47:05 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20(grapher)=20add=20short=20attributi?= =?UTF-8?q?on=20to=20tab=20labels?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../grapher/src/modal/SourcesModal.scss | 11 +++ .../grapher/src/modal/SourcesModal.tsx | 69 +++++++++++++------ .../grapher/src/tabs/ExpandableTabs.tsx | 6 +- .../@ourworldindata/grapher/src/tabs/Tabs.tsx | 4 +- 4 files changed, 64 insertions(+), 26 deletions(-) diff --git a/packages/@ourworldindata/grapher/src/modal/SourcesModal.scss b/packages/@ourworldindata/grapher/src/modal/SourcesModal.scss index be482435403..86f3482fb10 100644 --- a/packages/@ourworldindata/grapher/src/modal/SourcesModal.scss +++ b/packages/@ourworldindata/grapher/src/modal/SourcesModal.scss @@ -4,6 +4,7 @@ $tab-padding: 16px; $tab-font-size: 13px; $tab-gap: 8px; + $tab-secondary-margin: 8px; $border: $gray-20; @@ -64,6 +65,16 @@ font-size: $tab-font-size; padding: 8px $tab-padding; margin-right: $tab-gap; + + .attribution { + color: $gray-60; + display: inline-block; + margin-left: $tab-secondary-margin; + } + + &[aria-selected="true"] .attribution { + color: $blue-50; + } } .source { diff --git a/packages/@ourworldindata/grapher/src/modal/SourcesModal.tsx b/packages/@ourworldindata/grapher/src/modal/SourcesModal.tsx index 4210be78314..93edffb8aa1 100644 --- a/packages/@ourworldindata/grapher/src/modal/SourcesModal.tsx +++ b/packages/@ourworldindata/grapher/src/modal/SourcesModal.tsx @@ -25,7 +25,7 @@ import { CLOSE_BUTTON_WIDTH, CloseButton, } from "@ourworldindata/components" -import React from "react" +import React, { ReactElement } from "react" import cx from "classnames" import { action, computed } from "mobx" import { observer } from "mobx-react" @@ -46,6 +46,7 @@ const MAX_CONTENT_WIDTH = 640 const TAB_PADDING = 16 const TAB_FONT_SIZE = 13 const TAB_GAP = 8 +const TAB_SECONDARY_MARGIN = 8 export interface SourcesModalManager { isReady?: boolean @@ -112,10 +113,32 @@ export class SourcesModal extends React.Component< return this.manager.columnsWithSourcesExtensive } - @computed private get tabLabels(): string[] { - return this.columns.map( - (column) => column.titlePublicOrDisplayName.title - ) + @computed private get tabLabels(): ReactElement[] { + return this.columns.map((column) => { + const attribution = joinTitleFragments( + column.titlePublicOrDisplayName.attributionShort, + column.titlePublicOrDisplayName.titleVariant + ) + return ( + + {column.titlePublicOrDisplayName.title} + {attribution && ( + {attribution} + )} + + ) + }) + } + + @computed private get tabLabelWidths(): number[] { + return this.columns.map((column) => { + const title = `${column.titlePublicOrDisplayName.title}` + const fragments = joinTitleFragments( + column.titlePublicOrDisplayName.attributionShort, + column.titlePublicOrDisplayName.titleVariant + ) + return measureTabWidth(title, fragments) + TAB_GAP + }) } private renderSource( @@ -162,12 +185,8 @@ export class SourcesModal extends React.Component< this.modalBounds.width - 2 * this.modalPadding - 10 // wiggle room ) - const labelWidths = this.tabLabels.map( - (label) => measureTabWidth(label) + TAB_GAP - ) - // check if all tab labels fit into a single line - if (sum(labelWidths) <= maxWidth) { + if (sum(this.tabLabelWidths) <= maxWidth) { return ( Math.min(measureTabWidth(label), maxTabWidth) + TAB_GAP + const clippedLabelWidths = this.tabLabelWidths.map((labelWidth) => + Math.min(labelWidth, maxTabWidth + TAB_GAP) ) // check if all tab labels fit into a single line when they are clipped @@ -195,18 +214,20 @@ export class SourcesModal extends React.Component< } // compute the subset of tabs that fit into a single line - const getVisibleLabels = (labels: string[]) => { + const getVisibleLabels = ( + labels: React.ReactElement[] + ): React.ReactElement[] => { // take width of the "Show more" button into account let width = measureTabWidth("Show more") + 13 + // icon width 6 // icon padding - const visibleLabels: string[] = [] + const visibleLabels: React.ReactElement[] = [] for (const [label, labelWidth] of zip(labels, clippedLabelWidths)) { width += labelWidth as number if (width > maxWidth) break - visibleLabels.push(label as string) + visibleLabels.push(label as React.ReactElement) } return visibleLabels @@ -493,10 +514,16 @@ export class Source extends React.Component<{ } } -const measureTabWidth = (label: string): number => { - return ( - 2 * TAB_PADDING + - Bounds.forText(label, { fontSize: TAB_FONT_SIZE }).width + - 2 // border - ) +const measureTabWidth = (label: string, secondary?: string): number => { + const getWidth = (text: string) => + Bounds.forText(text, { fontSize: TAB_FONT_SIZE }).width + + const labelWidth = getWidth(label) + const secondaryTextWidth = secondary + ? getWidth(secondary) + TAB_SECONDARY_MARGIN + : 0 + const padding = 2 * TAB_PADDING + const borderWidth = 2 + + return labelWidth + secondaryTextWidth + padding + borderWidth } diff --git a/packages/@ourworldindata/grapher/src/tabs/ExpandableTabs.tsx b/packages/@ourworldindata/grapher/src/tabs/ExpandableTabs.tsx index fefc229c848..22b01afa0aa 100644 --- a/packages/@ourworldindata/grapher/src/tabs/ExpandableTabs.tsx +++ b/packages/@ourworldindata/grapher/src/tabs/ExpandableTabs.tsx @@ -9,14 +9,14 @@ export const ExpandableTabs = ({ activeIndex, setActiveIndex, isExpandedDefault = false, - getVisibleLabels = (labels: string[]) => labels.slice(0, 3), + getVisibleLabels = (labels: React.ReactElement[]) => labels.slice(0, 3), maxTabWidth = 240, }: { - labels: string[] + labels: React.ReactElement[] activeIndex: number setActiveIndex: (index: number) => void isExpandedDefault?: boolean - getVisibleLabels?: (tabLabels: string[]) => string[] + getVisibleLabels?: (tabLabels: React.ReactElement[]) => React.ReactElement[] maxTabWidth?: number | null // if null, don't clip labels }) => { const [isExpanded, setExpanded] = useState(isExpandedDefault) diff --git a/packages/@ourworldindata/grapher/src/tabs/Tabs.tsx b/packages/@ourworldindata/grapher/src/tabs/Tabs.tsx index f8b51a0681c..51025ec053e 100644 --- a/packages/@ourworldindata/grapher/src/tabs/Tabs.tsx +++ b/packages/@ourworldindata/grapher/src/tabs/Tabs.tsx @@ -9,7 +9,7 @@ export const Tabs = ({ maxTabWidth = 240, slot, }: { - labels: string[] + labels: React.ReactElement[] activeIndex: number setActiveIndex: (label: number) => void horizontalScroll?: boolean @@ -68,7 +68,7 @@ export const Tabs = ({ const isActive = index === activeIndex return (