From eebf6bd2245c00f2a596668323bff1bb78af5fb2 Mon Sep 17 00:00:00 2001 From: sophiamersmann Date: Tue, 2 Apr 2024 08:10:51 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A8=20(grapher)=20refactor=20modals?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- explorer/Explorer.tsx | 2 +- .../src/DataCitation/DataCitation.tsx | 8 +- .../grapher/src/controls/SettingsMenu.scss | 7 -- .../grapher/src/controls/SettingsMenu.tsx | 4 +- .../grapher/src/core/grapher.scss | 18 +++ .../grapher/src/core/typography.scss | 103 ++++++++++++++++++ .../src/entitySelector/EntitySelector.scss | 8 +- .../grapher/src/modal/DownloadModal.scss | 69 ++++-------- .../grapher/src/modal/DownloadModal.tsx | 26 +++-- .../grapher/src/modal/EmbedModal.scss | 14 +-- .../grapher/src/modal/EmbedModal.tsx | 18 +-- .../grapher/src/modal/Modal.scss | 60 +++++----- .../grapher/src/modal/Modal.tsx | 19 ++-- .../grapher/src/modal/SourcesModal.scss | 19 ++-- .../grapher/src/modal/SourcesModal.tsx | 16 ++- .../grapher/src/sidePanel/SidePanel.scss | 18 +-- .../grapher/src/sidePanel/SidePanel.tsx | 14 ++- .../src/slideInDrawer/SlideInDrawer.scss | 15 ++- .../src/slideInDrawer/SlideInDrawer.tsx | 8 +- 19 files changed, 273 insertions(+), 173 deletions(-) create mode 100644 packages/@ourworldindata/grapher/src/core/typography.scss diff --git a/explorer/Explorer.tsx b/explorer/Explorer.tsx index 00acecf515f..6cd073b1721 100644 --- a/explorer/Explorer.tsx +++ b/explorer/Explorer.tsx @@ -958,7 +958,7 @@ export class Explorer @computed get embedDialogAdditionalElements() { return ( -
+
{props.citationShort && ( - <> +

In-line citation If you have limited space (e.g. in data visualizations), @@ -19,10 +19,10 @@ export const DataCitation = (props: { theme="light" useMarkdown={true} /> - +

)} {props.citationLong && ( - <> +

Full citation

@@ -31,7 +31,7 @@ export const DataCitation = (props: { theme="light" useMarkdown={true} /> - +
)}
) diff --git a/packages/@ourworldindata/grapher/src/controls/SettingsMenu.scss b/packages/@ourworldindata/grapher/src/controls/SettingsMenu.scss index 103d898bf5c..ae6aa9210fc 100644 --- a/packages/@ourworldindata/grapher/src/controls/SettingsMenu.scss +++ b/packages/@ourworldindata/grapher/src/controls/SettingsMenu.scss @@ -54,13 +54,6 @@ nav.controlsRow .chart-controls .settings-menu { position: sticky; top: 0; z-index: 1; - - .settings-menu-title { - text-transform: uppercase; - letter-spacing: 0.1em; - color: $light-text; - font: $bold 12px/16px $lato; - } } .settings-menu-controls { diff --git a/packages/@ourworldindata/grapher/src/controls/SettingsMenu.tsx b/packages/@ourworldindata/grapher/src/controls/SettingsMenu.tsx index 61f079dfe45..c4720e52cdd 100644 --- a/packages/@ourworldindata/grapher/src/controls/SettingsMenu.tsx +++ b/packages/@ourworldindata/grapher/src/controls/SettingsMenu.tsx @@ -316,7 +316,9 @@ export class SettingsMenu extends React.Component<{ }} >
-
{menuTitle}
+
+ {menuTitle} +
this.toggleVisibility()} />
diff --git a/packages/@ourworldindata/grapher/src/core/grapher.scss b/packages/@ourworldindata/grapher/src/core/grapher.scss index cfa8428f3ab..1c46df263f3 100644 --- a/packages/@ourworldindata/grapher/src/core/grapher.scss +++ b/packages/@ourworldindata/grapher/src/core/grapher.scss @@ -10,6 +10,8 @@ @import "../../../components/src/IndicatorSources/IndicatorSources.scss"; @import "../../../components/src/IndicatorProcessing/IndicatorProcessing.scss"; +@import "./typography.scss"; + // grapher frame $frame-color: #f2f2f2; @@ -87,6 +89,14 @@ $zindex-controls-drawer: 150; @import "../../../components/src/Checkbox.scss"; @import "../closeButton/CloseButton.scss"; +.grapher_dark { + color: $dark-text; +} + +.grapher_light { + color: $light-text; +} + .GrapherComponent, .GrapherComponent h2, .GrapherComponent p, @@ -170,6 +180,14 @@ $zindex-controls-drawer: 150; --code-snippet-button: #{$dark-text}; --code-snippet-button-hover: #{$light-text}; --code-snippet-button-active: #{$light-text}; + + margin-bottom: 0 !important; + } + + &.GrapherComponentNarrow { + .wp-code-snippet { + padding: 16px; + } } } diff --git a/packages/@ourworldindata/grapher/src/core/typography.scss b/packages/@ourworldindata/grapher/src/core/typography.scss new file mode 100644 index 00000000000..7b4981f260b --- /dev/null +++ b/packages/@ourworldindata/grapher/src/core/typography.scss @@ -0,0 +1,103 @@ +// +// headings +// + +@mixin grapher_h3-semibold { + display: block; + margin: 0; + + font-family: $serif-font-stack; + font-size: 1.125rem; + font-weight: 600; + line-height: 1.1111; + letter-spacing: 0; +} + +.grapher_h3-semibold { + @include grapher_h3-semibold; +} + +@mixin grapher_h4-semibold { + display: block; + margin: 0; + + font-family: $serif-font-stack; + font-size: 1.1rem; + font-weight: 600; + line-height: 1.5; + letter-spacing: 0; +} + +.grapher_h4-semibold { + @include grapher_h4-semibold; +} + +@mixin grapher_h5-black-caps { + display: block; + margin: 0; + + font-family: $sans-serif-font-stack; + font-size: 0.75rem; + font-weight: 900; + line-height: 1.3333; + letter-spacing: 0.1em; + + text-transform: uppercase; +} + +.grapher_h5-black-caps { + @include grapher_h5-black-caps; +} + +// +// body +// + +@mixin grapher_body-2-semibold { + display: block; + margin: 0; + + font-family: $sans-serif-font-stack; + font-size: 1rem; + font-weight: 600; + line-height: 1.5; + letter-spacing: 0; +} + +.grapher_body-2-semibold { + @include grapher_body-2-semibold; +} + +@mixin grapher_body-3-medium { + display: block; + margin: 0; + + font-family: $sans-serif-font-stack; + font-size: 0.8125rem; + font-weight: 500; + line-height: 1.3846; + letter-spacing: 0; +} + +.grapher_body-3-medium { + @include grapher_body-3-medium; +} + +// +// labels +// + +@mixin grapher_label-1-medium { + display: block; + margin: 0; + + font-family: $sans-serif-font-stack; + font-size: 0.875rem; + font-weight: 500; + line-height: 1.2; + letter-spacing: 0; +} + +.grapher_label-1-medium { + @include grapher_label-1-medium; +} diff --git a/packages/@ourworldindata/grapher/src/entitySelector/EntitySelector.scss b/packages/@ourworldindata/grapher/src/entitySelector/EntitySelector.scss index a42b4bc150a..373f1e1f7b8 100644 --- a/packages/@ourworldindata/grapher/src/entitySelector/EntitySelector.scss +++ b/packages/@ourworldindata/grapher/src/entitySelector/EntitySelector.scss @@ -4,7 +4,7 @@ $active-fill: #dbe5f0; text-align: left; - margin-bottom: 1.5em; + margin: 0 var(--modal-padding, 16px) var(--modal-padding, 16px); ul { margin: 0; @@ -166,10 +166,4 @@ } } } - - .SidePanel .EntitySelector, - .SlideInDrawer .EntitySelector { - margin-left: 16px; - margin-right: 16px; - } } diff --git a/packages/@ourworldindata/grapher/src/modal/DownloadModal.scss b/packages/@ourworldindata/grapher/src/modal/DownloadModal.scss index 8a2221a6138..cafd18859c5 100644 --- a/packages/@ourworldindata/grapher/src/modal/DownloadModal.scss +++ b/packages/@ourworldindata/grapher/src/modal/DownloadModal.scss @@ -1,20 +1,17 @@ -.DownloadModalContent { +.download-modal-content { color: $dark-text; - padding-bottom: $modal-padding; + padding: 0 var(--modal-padding) var(--modal-padding); + min-height: 45px; + position: relative; .grouped-menu-section { - h2 { - color: $dark-text; - font-family: $serif-font-stack; - font-size: 1.125em; - font-weight: 600; - margin: 0; + h3 { margin-bottom: 16px; } } .grouped-menu-section + .grouped-menu-section { - margin-top: 1.5em; + margin-top: 24px; } .grouped-menu-item + .grouped-menu-item { @@ -29,7 +26,7 @@ background-color: #f7f7f7; position: relative; width: 100%; - padding: 1em; + padding: 16px; overflow: hidden; text-align: left; @@ -51,27 +48,11 @@ 0px 93px 37px 0px rgba(49, 37, 2, 0.01), 0px 145px 41px 0px rgba(49, 37, 2, 0); padding: 0; - margin: 0; + margin: 0 24px 0 0; } .grouped-menu-content { flex: 1; - padding: 0 1.5em; - - .title { - margin: 0; - font-weight: 600; - font-size: 1em; - line-height: 1.5; - } - - .description { - margin: 0; - color: $light-text; - font-size: 0.875em; - font-weight: 500; - line-height: 1.15; - } } .grouped-menu-section-data .grouped-menu-content { @@ -79,8 +60,8 @@ } .download-icon { - padding: 0 0.5em; - font-size: 1em; + padding: 0 8px 0 16px; + font-size: 16px; } .grouped-menu-item:hover .download-icon { @@ -91,29 +72,20 @@ border-radius: 8px; border: 1px solid #dadada; background: #f7f7f7; - padding: 1em; + padding: 16px; svg { - margin-right: 0.5em; + margin-right: 8px; color: $light-text; } .title { - margin: 0; - font-family: $serif-font-stack; - font-size: 1em; - font-weight: 600; - line-height: 1.5; + font-size: 1rem; } p { - font-size: 0.875em; - margin: 0.5em 0 0; - opacity: 0.9; - color: $light-text; - font-weight: 500; - line-height: 1.15; - letter-spacing: 0.14px; + margin: 8px 0 0; + font-size: 0.875rem; } a { @@ -128,8 +100,8 @@ } .static-exports-options { - margin: 1em 0 1.5em; - padding-bottom: 1.5em; + margin: 16px 0 24px; + padding-bottom: 24px; border-bottom: 1px solid #f2f2f2; > .checkbox + .checkbox { @@ -137,9 +109,8 @@ } } -&.GrapherComponentNarrow .DownloadModalContent { - .grouped-menu-icon + .grouped-menu-content { - padding-left: 1em; - padding-right: 0.5em; +&.GrapherComponentNarrow .download-modal-content { + .grouped-menu-icon img { + display: none; } } diff --git a/packages/@ourworldindata/grapher/src/modal/DownloadModal.tsx b/packages/@ourworldindata/grapher/src/modal/DownloadModal.tsx index d60c5f99694..2f8d0f5fa94 100644 --- a/packages/@ourworldindata/grapher/src/modal/DownloadModal.tsx +++ b/packages/@ourworldindata/grapher/src/modal/DownloadModal.tsx @@ -259,7 +259,7 @@ export class DownloadModal extends React.Component {
{manager.isOnChartOrMapTab && (
-

Visualization

+

Visualization

{
)}
-

Data

+

Data

{this.nonRedistributable ? (
-

+

The data in this chart is not available to download -

-

+ +

The data is published under a license that doesn't allow us to redistribute it. {this.nonRedistributableSourceLink && ( @@ -352,6 +352,10 @@ export class DownloadModal extends React.Component { ) } + @action.bound private onDismiss(): void { + this.manager.isDownloadModalOpen = false + } + componentDidMount(): void { this.export() } @@ -360,12 +364,10 @@ export class DownloadModal extends React.Component { return ( (this.manager.isDownloadModalOpen = false) - )} bounds={this.modalBounds} + onDismiss={this.onDismiss} > -

+
{this.isReady ? ( this.renderReady() ) : ( @@ -399,8 +401,10 @@ function DownloadButton(props: DownloadButtonProps): JSX.Element {
)}
-

{props.title}

-

{props.description}

+

{props.title}

+

+ {props.description} +

diff --git a/packages/@ourworldindata/grapher/src/modal/EmbedModal.scss b/packages/@ourworldindata/grapher/src/modal/EmbedModal.scss index 85ff5f0a033..f88795663ac 100644 --- a/packages/@ourworldindata/grapher/src/modal/EmbedModal.scss +++ b/packages/@ourworldindata/grapher/src/modal/EmbedModal.scss @@ -1,12 +1,12 @@ -.embedMenu { - text-align: left; +.embed-modal-content { color: $dark-text; - margin-bottom: $modal-padding; + margin: 0 var(--modal-padding) var(--modal-padding); p { - margin-bottom: 1.15em; - margin-top: 0; - font-size: 0.875em; - font-weight: 500; + margin-bottom: 16px; + } + + .embed-additional-elements { + margin-top: 16px; } } diff --git a/packages/@ourworldindata/grapher/src/modal/EmbedModal.tsx b/packages/@ourworldindata/grapher/src/modal/EmbedModal.tsx index cb5abc31378..ab6bc066943 100644 --- a/packages/@ourworldindata/grapher/src/modal/EmbedModal.tsx +++ b/packages/@ourworldindata/grapher/src/modal/EmbedModal.tsx @@ -19,6 +19,10 @@ interface EmbedModalProps { @observer export class EmbedModal extends React.Component { + @computed get manager(): EmbedModalManager { + return this.props.manager + } + @computed private get frameBounds(): Bounds { return this.manager.frameBounds ?? DEFAULT_BOUNDS } @@ -34,22 +38,22 @@ export class EmbedModal extends React.Component { return `` } - @computed get manager(): EmbedModalManager { - return this.props.manager + @action.bound private onDismiss(): void { + this.manager.isEmbedModalOpen = false } render(): JSX.Element { return ( (this.manager.isEmbedModalOpen = false) - )} bounds={this.modalBounds} alignVertical="bottom" + onDismiss={this.onDismiss} > -
-

Paste this into any HTML page:

+
+

+ Paste this into any HTML page: +

{this.manager.embedDialogAdditionalElements}
diff --git a/packages/@ourworldindata/grapher/src/modal/Modal.scss b/packages/@ourworldindata/grapher/src/modal/Modal.scss index dcbaf7a7a74..ad51c3e341b 100644 --- a/packages/@ourworldindata/grapher/src/modal/Modal.scss +++ b/packages/@ourworldindata/grapher/src/modal/Modal.scss @@ -1,65 +1,55 @@ -$modal-padding: 1.5em; +.modal-overlay { + --modal-padding: 24px; -// the base font size for modals is 16px and on -// smaller devices scales down to 14px. -// it is never scaled up though. - -.modalOverlay { position: absolute; + // -1px to hide the frame border top: -1px; right: -1px; bottom: -1px; left: -1px; + background-color: rgba(0, 0, 0, 0.4); z-index: $zindex-modal; - .modalWrapper { + .modal-wrapper { position: relative; height: 100%; - .modalContent { + .modal-content { position: absolute; border-radius: 4px; background: #fff; box-shadow: 0px 4px 30px 0px rgba(0, 0, 0, 0.15); - padding: $modal-padding; - padding-bottom: 0; min-height: 150px; + // necessary to allow modal to scroll display: flex; flex-direction: column; - } - .close-button--top-right { - position: absolute; - top: $modal-padding; - right: $modal-padding; - } + .close-button--top-right { + position: absolute; + top: 0; + right: 0; + margin: var(--modal-padding); + } - .modalHeader { - flex-shrink: 0; // necessary to allow modal to scroll - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 1em; + .modal-header { + flex-shrink: 0; // necessary to allow modal to scroll - &__empty { - margin-bottom: 4px; + display: flex; + justify-content: space-between; + align-items: center; + padding: var(--modal-padding) var(--modal-padding) 16px; } - .modalTitle { - text-transform: uppercase; - color: $light-text; - font-size: 0.75em; - font-weight: 900; - letter-spacing: 1.2px; - margin: 0; + .modal-scrollable { + overflow-y: auto; } } - - .modalScrollable { - overflow-y: auto; - } } } + +&.GrapherComponentNarrow .modal-overlay { + --modal-padding: 16px; +} diff --git a/packages/@ourworldindata/grapher/src/modal/Modal.tsx b/packages/@ourworldindata/grapher/src/modal/Modal.tsx index 03c2c38e0ba..0dd218a2b7b 100644 --- a/packages/@ourworldindata/grapher/src/modal/Modal.tsx +++ b/packages/@ourworldindata/grapher/src/modal/Modal.tsx @@ -1,7 +1,6 @@ import React from "react" import { observer } from "mobx-react" import { action, computed } from "mobx" -import cx from "classnames" import { Bounds } from "@ourworldindata/utils" import { CloseButton } from "../closeButton/CloseButton.js" @@ -87,20 +86,18 @@ export class Modal extends React.Component<{ } return ( -
-
+
+
{this.showStickyHeader ? ( -
-
{this.title}
+
+

+ {this.title} +

) : ( @@ -109,7 +106,7 @@ export class Modal extends React.Component<{ onClick={this.props.onDismiss} /> )} -
+
{this.props.children}
diff --git a/packages/@ourworldindata/grapher/src/modal/SourcesModal.scss b/packages/@ourworldindata/grapher/src/modal/SourcesModal.scss index 5208c6c36e2..9a636d7a837 100644 --- a/packages/@ourworldindata/grapher/src/modal/SourcesModal.scss +++ b/packages/@ourworldindata/grapher/src/modal/SourcesModal.scss @@ -1,15 +1,19 @@ -.SourcesModalContent { +.sources-modal-content { // keep in sync with variables in SourcesModal.tsx $max-content-width: 640px; $tab-padding: 16px; $tab-font-size: 13px; $tab-gap: 8px; - padding-bottom: $modal-padding; + $border: #e7e7e7; + max-width: $max-content-width; margin: 0 auto; + padding: 0 var(--modal-padding) var(--modal-padding); - $border: #e7e7e7; + &.sources-modal-content--pad-top { + margin-top: var(--modal-padding); + } .note-multiple-indicators { margin-top: 0; @@ -26,6 +30,7 @@ @include h1-semibold; margin-top: 0; margin-bottom: 8px; + margin-right: 8px; color: $dark-text; @include sm-up { @@ -56,8 +61,8 @@ .title-fragments { color: $light-text; font-size: 1.25rem; - margin-left: 8px; } + a { color: inherit; text-decoration: underline; @@ -153,8 +158,8 @@ margin-right: $tab-gap; } - .data-citation .wp-code-snippet { - margin-bottom: 16px; + .data-citation__item:not(:first-of-type) { + margin-top: 16px; } .citation__paragraph { @@ -188,7 +193,7 @@ } } -&.GrapherComponentSmall .SourcesModalContent { +&.GrapherComponentSmall .sources-modal-content { .source { --text-small: 0.8125rem; diff --git a/packages/@ourworldindata/grapher/src/modal/SourcesModal.tsx b/packages/@ourworldindata/grapher/src/modal/SourcesModal.tsx index 17af8409f65..fdadfc31df4 100644 --- a/packages/@ourworldindata/grapher/src/modal/SourcesModal.tsx +++ b/packages/@ourworldindata/grapher/src/modal/SourcesModal.tsx @@ -23,6 +23,7 @@ import { DataCitation, } from "@ourworldindata/components" import React from "react" +import cx from "classnames" import { action, computed } from "mobx" import { observer } from "mobx-react" import { faPencilAlt } from "@fortawesome/free-solid-svg-icons" @@ -250,17 +251,24 @@ export class SourcesModal extends React.Component< : this.renderMultipleSources() } + @action.bound private onDismiss(): void { + this.manager.isSourcesModalOpen = false + } + render(): JSX.Element { return ( (this.manager.isSourcesModalOpen = false) - )} bounds={this.modalBounds} isHeightFixed={true} + onDismiss={this.onDismiss} showStickyHeader={this.showStickyModalHeader} > -
+
{this.manager.isReady ? ( this.renderModalContent() ) : ( diff --git a/packages/@ourworldindata/grapher/src/sidePanel/SidePanel.scss b/packages/@ourworldindata/grapher/src/sidePanel/SidePanel.scss index b5b195aee5c..8499c3098a1 100644 --- a/packages/@ourworldindata/grapher/src/sidePanel/SidePanel.scss +++ b/packages/@ourworldindata/grapher/src/sidePanel/SidePanel.scss @@ -1,15 +1,19 @@ -.SidePanel { +.side-panel { flex-grow: 0; flex-shrink: 0; border-left: 1px solid $frame-color; overflow-y: auto; - .title { - text-transform: uppercase; - color: $light-text; - font-size: 12px; - font-weight: 900; - letter-spacing: 1.2px; + // necessary for scrolling + display: flex; + flex-direction: column; + + .side-panel__header { margin: 16px; + flex-shrink: 0; // necessary for scrolling + } + + .side-panel__scrollable { + overflow-y: auto; } } diff --git a/packages/@ourworldindata/grapher/src/sidePanel/SidePanel.tsx b/packages/@ourworldindata/grapher/src/sidePanel/SidePanel.tsx index 1989b2b6d3c..61ef2a49cfb 100644 --- a/packages/@ourworldindata/grapher/src/sidePanel/SidePanel.tsx +++ b/packages/@ourworldindata/grapher/src/sidePanel/SidePanel.tsx @@ -6,7 +6,7 @@ import { Bounds } from "@ourworldindata/utils" @observer export class SidePanel extends React.Component<{ bounds: Bounds - title?: string + title: string children: React.ReactNode }> { @computed private get bounds(): Bounds { @@ -16,16 +16,18 @@ export class SidePanel extends React.Component<{ render(): JSX.Element { return (
- {this.props.title && ( -

{this.props.title}

- )} - {this.props.children} +

+ {this.props.title} +

+
+ {this.props.children} +
) } diff --git a/packages/@ourworldindata/grapher/src/slideInDrawer/SlideInDrawer.scss b/packages/@ourworldindata/grapher/src/slideInDrawer/SlideInDrawer.scss index e9e7080bcdb..7f6f3692167 100644 --- a/packages/@ourworldindata/grapher/src/slideInDrawer/SlideInDrawer.scss +++ b/packages/@ourworldindata/grapher/src/slideInDrawer/SlideInDrawer.scss @@ -21,6 +21,10 @@ overflow-y: scroll; background: white; + // necessary for scrolling + display: flex; + flex-direction: column; + .grapher-drawer-header { position: static; display: flex; @@ -33,12 +37,11 @@ z-index: 1; margin-bottom: 16px; - .grapher-drawer-title { - text-transform: uppercase; - letter-spacing: 0.1em; - color: $light-text; - font: $bold 12px/16px $lato; - } + flex-shrink: 0; // necessary for scrolling + } + + .grapher-drawer-scrollable { + overflow-y: auto; } } diff --git a/packages/@ourworldindata/grapher/src/slideInDrawer/SlideInDrawer.tsx b/packages/@ourworldindata/grapher/src/slideInDrawer/SlideInDrawer.tsx index 6e046bdfce9..dbcdc03fc82 100644 --- a/packages/@ourworldindata/grapher/src/slideInDrawer/SlideInDrawer.tsx +++ b/packages/@ourworldindata/grapher/src/slideInDrawer/SlideInDrawer.tsx @@ -70,7 +70,7 @@ export class SlideInDrawer extends React.Component<{ @computed get drawerContents(): JSX.Element { return ( -
+
-
+
{this.props.title}
this.toggleVisibility()} />
- {this.props.children} +
+ {this.props.children} +
)