diff --git a/frontend/src/metabase/dashboard/components/DashboardActions.jsx b/frontend/src/metabase/dashboard/components/DashboardActions.jsx index 7537ff5bd6c80da503411df2cfd34519db5cbd91..8fac8b43b0fe436d81ee172ba7fa51836ba336f5 100644 --- a/frontend/src/metabase/dashboard/components/DashboardActions.jsx +++ b/frontend/src/metabase/dashboard/components/DashboardActions.jsx @@ -30,6 +30,7 @@ export const getDashboardActions = ( onRefreshPeriodChange, onSharingClick, onFullscreenChange, + hasNightModeToggle, }, ) => { const isPublicLinksEnabled = MetabaseSettings.get("enable-public-sharing"); @@ -117,7 +118,7 @@ export const getDashboardActions = ( ); } - if (!isEditing && isFullscreen) { + if (!isEditing && isFullscreen && hasNightModeToggle) { buttons.push( <Tooltip key="night" diff --git a/frontend/src/metabase/dashboard/hoc/DashboardControls.jsx b/frontend/src/metabase/dashboard/hoc/DashboardControls.jsx index c73063fee13f8377927d8ab5cf6e8e97120df27d..44ff13f430554f9737996155e1bed8a7cd39af9a 100644 --- a/frontend/src/metabase/dashboard/hoc/DashboardControls.jsx +++ b/frontend/src/metabase/dashboard/hoc/DashboardControls.jsx @@ -24,7 +24,7 @@ export default ComposedComponent => state = { isFullscreen: false, - isNightMode: false, + theme: null, refreshPeriod: null, @@ -66,7 +66,7 @@ export default ComposedComponent => ? null : options.refresh, ); - this.setNightMode(options.theme === "night" || options.night); // DEPRECATED: options.night + this.setTheme(options.theme); this.setFullscreen(options.fullscreen); this.setHideParameters(options.hide_parameters); }; @@ -84,7 +84,7 @@ export default ComposedComponent => }; setValue("refresh", this.state.refreshPeriod); setValue("fullscreen", this.state.isFullscreen); - setValue("theme", this.state.isNightMode ? "night" : null); + setValue("theme", this.state.theme); delete options.night; // DEPRECATED: options.night @@ -127,9 +127,14 @@ export default ComposedComponent => } }; + // Preserve existing behavior, while keeping state in a new `theme` key setNightMode = isNightMode => { - isNightMode = !!isNightMode; - this.setState({ isNightMode }); + const theme = isNightMode ? "night" : null; + this.setState({ theme }); + }; + + setTheme = theme => { + this.setState({ theme }); }; setFullscreen = async (isFullscreen, browserFullscreen = true) => { @@ -213,6 +218,8 @@ export default ComposedComponent => <ComposedComponent {...this.props} {...this.state} + isNightMode={this.state.theme === "night"} + hasNightModeToggle={this.state.theme !== "transparent"} setRefreshElapsedHook={this.setRefreshElapsedHook} loadDashboardParams={this.loadDashboardParams} updateDashboardParams={this.updateDashboardParams} diff --git a/frontend/src/metabase/public/components/EmbedFrame.css b/frontend/src/metabase/public/components/EmbedFrame.css index 88e698098e59fe5818af87a51f2f93dc24717396..aa50d6bb355d70ae96066180ab9f214b0198c30a 100644 --- a/frontend/src/metabase/public/components/EmbedFrame.css +++ b/frontend/src/metabase/public/components/EmbedFrame.css @@ -38,3 +38,16 @@ .Theme--night.EmbedFrame .enable-dots .dc-tooltip circle.dot { fill: currentColor; } + +.Theme--transparent.EmbedFrame { + background-color: transparent; +} + +.Theme--transparent .EmbedFrame-header, +.Theme--transparent .EmbedFrame-footer { + background-color: transparent; +} + +.Theme--transparent.EmbedFrame .DashCard .Card { + background-color: transparent; +} diff --git a/frontend/src/metabase/public/components/widgets/AdvancedEmbedPane.jsx b/frontend/src/metabase/public/components/widgets/AdvancedEmbedPane.jsx index b089bd03241615f3a0d72e26bc52368e6eb79b5b..8af0f2e817c721f91e8d13242dc0bd29a891159a 100644 --- a/frontend/src/metabase/public/components/widgets/AdvancedEmbedPane.jsx +++ b/frontend/src/metabase/public/components/widgets/AdvancedEmbedPane.jsx @@ -1,6 +1,8 @@ /* eslint-disable react/prop-types */ import React from "react"; +import _ from "underscore"; + import ToggleLarge from "metabase/components/ToggleLarge"; import Button from "metabase/core/components/Button"; import ActionButton from "metabase/components/ActionButton"; @@ -9,8 +11,6 @@ import AdvancedSettingsPane from "./AdvancedSettingsPane"; import PreviewPane from "./PreviewPane"; import EmbedCodePane from "./EmbedCodePane"; -import _ from "underscore"; - const AdvancedEmbedPane = ({ pane, resource, @@ -74,7 +74,11 @@ const AdvancedEmbedPane = ({ onChange={() => onChangePane(pane === "preview" ? "code" : "preview")} /> {pane === "preview" ? ( - <PreviewPane className="flex-full" previewUrl={iframeUrl} /> + <PreviewPane + className="flex-full" + previewUrl={iframeUrl} + isTransparent={displayOptions.theme === "transparent"} + /> ) : pane === "code" ? ( <EmbedCodePane className="flex-full" diff --git a/frontend/src/metabase/public/components/widgets/DisplayOptionsPane.jsx b/frontend/src/metabase/public/components/widgets/DisplayOptionsPane.jsx index 30268dc1ec6f618e9a4ef19a19b7babba834c108..90552622b83e442aaf03fa61e48bbb730c0691b1 100644 --- a/frontend/src/metabase/public/components/widgets/DisplayOptionsPane.jsx +++ b/frontend/src/metabase/public/components/widgets/DisplayOptionsPane.jsx @@ -23,6 +23,7 @@ import { const THEME_OPTIONS = [ { name: t`Light`, value: null }, { name: t`Dark`, value: "night" }, + { name: t`Transparent`, value: "transparent" }, ]; const mapStateToProps = state => ({ diff --git a/frontend/src/metabase/public/components/widgets/PreviewPane.jsx b/frontend/src/metabase/public/components/widgets/PreviewPane.jsx index c0491026757511faee3ba2b6917883e851260403..8e1ddd8a668c8a90e4aa498bd4bf0f0a352ff1ac 100644 --- a/frontend/src/metabase/public/components/widgets/PreviewPane.jsx +++ b/frontend/src/metabase/public/components/widgets/PreviewPane.jsx @@ -2,6 +2,7 @@ import React, { Component } from "react"; import cx from "classnames"; +import { PreviewPaneContainer } from "./PreviewPane.styled"; export default class PreviewPane extends Component { constructor(props) { @@ -19,9 +20,10 @@ export default class PreviewPane extends Component { } render() { - const { className, previewUrl } = this.props; + const { className, previewUrl, isTransparent } = this.props; return ( - <div + <PreviewPaneContainer + isTransparent={isTransparent} className={cx(className, "flex relative")} style={{ minHeight: 280 }} > @@ -32,7 +34,7 @@ export default class PreviewPane extends Component { allowTransparency onLoad={() => this.setState({ loading: false })} /> - </div> + </PreviewPaneContainer> ); } } diff --git a/frontend/src/metabase/public/components/widgets/PreviewPane.styled.js b/frontend/src/metabase/public/components/widgets/PreviewPane.styled.js new file mode 100644 index 0000000000000000000000000000000000000000..d05de958b056d8044bf5741c29addeb3fdddc510 --- /dev/null +++ b/frontend/src/metabase/public/components/widgets/PreviewPane.styled.js @@ -0,0 +1,7 @@ +import styled from "@emotion/styled"; + +export const PreviewPaneContainer = styled.div` + ${({ isTransparent }) => + isTransparent && + `background-image: url("app/img/pattern_checkerboard.svg")`}; +`; diff --git a/resources/frontend_client/app/img/pattern_checkerboard.svg b/resources/frontend_client/app/img/pattern_checkerboard.svg new file mode 100644 index 0000000000000000000000000000000000000000..4862640de513006357d5e73291dbf2a6d0b6c7ad --- /dev/null +++ b/resources/frontend_client/app/img/pattern_checkerboard.svg @@ -0,0 +1,11 @@ +<svg + width="20" + height="20" + viewBox="0 0 20 20" + fill="none" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" +> + <rect width="10" height="10" fill="#F4F4F4" /> + <rect x="10" y="10" width="10" height="10" fill="#F4F4F4" /> +</svg>