Skip to content
Snippets Groups Projects
Unverified Commit a6035a1a authored by Denis Berezin's avatar Denis Berezin Committed by GitHub
Browse files

Add custom theming support for SDK InteractiveQuestion component (#42663)

* Add proper brand colors to drills menu

* Add theming for filters and drills

* Fix css vars

* Fix table css

* Add SDK theme colors interface and remapping

* Fix dashboard brand color issue

* Fix theme colors interface

* Fix default theme table cell background

* Fix typo

* Fix for qb filters panel custom border
parent c64187b1
No related branches found
No related tags found
No related merge requests found
Showing
with 160 additions and 82 deletions
......@@ -42,6 +42,11 @@ const SdkContentWrapperInner = styled.div<
--mb-color-brand-alpha-88: ${({ theme }) =>
alpha(theme.fn.themeColor("brand"), 0.88)};
--mb-color-focus: ${({ theme }) => theme.fn.themeColor("focus")};
--mb-color-bg-white: ${({ theme }) => theme.fn.themeColor("bg-white")};
--mb-color-bg-black: ${({ theme }) => theme.fn.themeColor("bg-black")};
--mb-color-shadow: ${({ theme }) => theme.fn.themeColor("shadow")};
--mb-color-border: ${({ theme }) => theme.fn.themeColor("border")};
--mb-color-text-dark: ${({ theme }) => theme.fn.themeColor("text-dark")};
${aceEditorStyles}
${saveDomImageStyles}
......
......@@ -3,9 +3,11 @@ import { memo } from "react";
import { Provider } from "react-redux";
import { AppInitializeController } from "embedding-sdk/components/private/AppInitializeController";
import {} from "embedding-sdk/components/private/PublicComponentWrapper";
import type { SdkPluginsConfig } from "embedding-sdk/lib/plugins";
import { getEmbeddingThemeOverride } from "embedding-sdk/lib/theme/get-embedding-theme";
import {
getEmbeddingThemeOverride,
getThemedColorsPalette,
} from "embedding-sdk/lib/theme/get-embedding-theme";
import { store } from "embedding-sdk/store";
import {
setErrorComponent,
......@@ -14,6 +16,8 @@ import {
} from "embedding-sdk/store/reducer";
import type { SDKConfig } from "embedding-sdk/types";
import type { MetabaseTheme } from "embedding-sdk/types/theme";
import { colors } from "metabase/lib/colors";
import type { ColorName } from "metabase/lib/colors/types";
import { EmotionCacheProvider } from "metabase/styled-components/components/EmotionCacheProvider";
import { ThemeProvider } from "metabase/ui/components/theme/ThemeProvider";
......@@ -34,6 +38,12 @@ const MetabaseProviderInternal = ({
theme,
}: MetabaseProviderProps): JSX.Element => {
const themeOverride = useMemo(() => {
const combinedThemeColors = getThemedColorsPalette(theme?.colors);
Object.entries(combinedThemeColors).forEach(([key, value]) => {
colors[key as ColorName] = value;
});
return theme && getEmbeddingThemeOverride(theme);
}, [theme]);
......
......@@ -27,7 +27,7 @@ export const DEFAULT_EMBEDDED_COMPONENT_THEME: MetabaseComponentTheme = merge(
{
table: {
cell: {
backgroundColor: "white",
backgroundColor: "bg-white",
},
},
},
......
import { merge } from "icepick";
import { colors } from "metabase/lib/colors";
import type { ColorName, ColorPalette } from "metabase/lib/colors/types";
import type {
MetabaseTheme,
MetabaseColors,
MetabaseColor,
MetabaseComponentTheme,
} from "../../types/theme";
......@@ -40,10 +44,54 @@ export function getEmbeddingThemeOverride(
const color = theme.colors[name as MetabaseColor];
if (color) {
override.colors[name] = colorTuple(color);
const themeColorName =
SDK_TO_MAIN_APP_COLORS_MAPPING[name as MetabaseColor];
override.colors[themeColorName] = colorTuple(color);
}
}
}
return override;
}
const SDK_TO_MAIN_APP_COLORS_MAPPING: Record<MetabaseColor, ColorName> = {
brand: "brand",
border: "border",
filter: "filter",
summarize: "summarize",
"text-primary": "text-dark",
"text-secondary": "text-medium",
"text-tertiary": "text-light",
background: "bg-white",
"background-hover": "bg-light",
// shadow: "shadow",
// positive: "success",
// negative: "danger",
// warning: "warning",
// white
// black
};
const originalColors = { ...colors };
export function getThemedColorsPalette(
themeColors?: MetabaseColors,
): ColorPalette {
if (!themeColors) {
return originalColors;
}
const mappedThemeColors: ColorPalette = {};
Object.entries(themeColors).forEach(([key, value]) => {
const mappedKey = SDK_TO_MAIN_APP_COLORS_MAPPING[key as MetabaseColor];
mappedThemeColors[mappedKey] = value;
});
return {
...originalColors,
...mappedThemeColors,
};
}
......@@ -10,8 +10,8 @@ describe("Transform Embedding Theme Override", () => {
fontFamily: "Roboto",
colors: {
brand: "hotpink",
"text-dark": "yellow",
"text-light": "green",
"text-primary": "yellow",
"text-tertiary": "green",
},
});
......
......@@ -24,17 +24,32 @@ export interface MetabaseTheme {
}
export interface MetabaseColors {
/** Primary brand color */
/** Primary brand color used for buttons and links */
brand?: string;
/** Text color on dark elements. Should be a lighter color for readability. */
"text-dark"?: string;
"text-primary"?: string;
/** Lighter variation of dark text on light elements. */
"text-secondary"?: string;
/** Text color on light elements. Should be a darker color for readability. */
"text-light"?: string;
"text-tertiary"?: string;
/** Lighter variation of dark text on light elements. */
"text-medium"?: string;
/** Default background color. */
background?: string;
/** Slightly darker background color used for hover and accented elements. */
"background-hover"?: string;
/** Color used for borders */
border?: string;
/** Color used for filters context */
filter?: string;
/** Color used for aggregations and breakouts context */
summarize?: string;
}
export type MetabaseColor = keyof MetabaseColors;
......@@ -50,7 +65,7 @@ export interface MetabaseComponentTheme {
/** Text color of cells, defaults to `text-dark`. */
textColor?: string;
/** Default background color of cells, defaults to `white` */
/** Default background color of cells, defaults to `bg-white` */
backgroundColor?: string;
};
......
......@@ -2,7 +2,7 @@ import { colors } from "metabase/lib/colors/palette";
import MetabaseSettings from "metabase/lib/settings";
export function updateColors() {
const scheme = MetabaseSettings.get("application-colors");
const scheme = MetabaseSettings.get("application-colors") || {};
for (const [colorName, themeColor] of Object.entries(scheme)) {
colors[colorName] = themeColor;
}
......
......@@ -23,7 +23,7 @@
/* create a slightly larger arrow on the right for border purposes */
.arrowRight::before {
right: -20px;
border-left-color: var(--color-border);
border-left-color: var(--mb-color-border);
}
/* create a smaller inset arrow on the right */
......
:root {
--breadcrumbs-color: var(--color-text-light);
--breadcrumb-page-color: var(--color-text-dark);
--breadcrumb-page-color: var(--mb-color-text-dark);
--breadcrumb-divider-spacing: 0.75em;
/* taken from Sidebar.css, should probably factor them out into variables */
......
:root {
--title-color: var(--color-text-dark);
--title-color: var(--mb-color-text-dark);
--subtitle-color: var(--color-text-medium);
--muted-color: var(--color-text-light);
}
......
......@@ -17,8 +17,8 @@
.PopoverBody.PopoverBodyWithBackground {
border: 1px solid #edf2f5;
box-shadow: 0 4px 10px var(--color-shadow);
background-color: var(--color-bg-white);
box-shadow: 0 4px 10px var(--mb-color-shadow);
background-color: var(--mb-color-bg-white);
border-radius: 6px;
overflow: auto;
}
......@@ -33,13 +33,13 @@
:global(.tippy-box[data-theme~="tooltip"]) {
color: white;
font-weight: bold;
background-color: var(--color-bg-black);
background-color: var(--mb-color-bg-black);
border: none;
pointer-events: none;
line-height: 1.26;
font-size: 12px;
border-radius: 6px;
box-shadow: 0 4px 10px var(--color-shadow);
box-shadow: 0 4px 10px var(--mb-color-shadow);
overflow-wrap: break-word;
}
......@@ -53,9 +53,9 @@
:global(.tippy-box[data-theme~="popover"]) {
font-size: inherit;
border: 1px solid var(--color-border);
box-shadow: 0 4px 10px var(--color-shadow);
background-color: var(--color-bg-white);
border: 1px solid var(--mb-color-border);
box-shadow: 0 4px 10px var(--mb-color-shadow);
background-color: var(--mb-color-bg-white);
border-radius: 6px;
overflow: auto;
}
......@@ -101,7 +101,7 @@
background: white;
position: absolute;
bottom: 0;
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--mb-color-border);
border-bottom-right-radius: 6px;
border-bottom-left-radius: 6px;
padding-top: 8px;
......@@ -115,25 +115,25 @@
/* create a slightly larger arrow on the top for border purposes */
:global(.tether-element-attached-top) .PopoverBodyWithArrow::before {
top: -20px;
border-bottom-color: var(--color-border);
border-bottom-color: var(--mb-color-border);
}
/* create a smaller inset arrow on the top */
:global(.tether-element-attached-top) .PopoverBodyWithArrow::after {
top: -18px;
border-bottom-color: var(--color-bg-white);
border-bottom-color: var(--mb-color-bg-white);
}
/* create a slightly larger arrow on the bottom for border purposes */
:global(.tether-element-attached-bottom) .PopoverBodyWithArrow::before {
bottom: -20px;
border-top-color: var(--color-border);
border-top-color: var(--mb-color-border);
}
/* create a smaller inset arrow on the bottom */
:global(.tether-element-attached-bottom) .PopoverBodyWithArrow::after {
bottom: -18px;
border-top-color: var(--color-bg-white);
border-top-color: var(--mb-color-bg-white);
}
/* if the tether element is attached right, move our arrows right */
......
.borderTop {
border-top: 1px solid var(--color-border);
border-top: 1px solid var(--mb-color-border);
.borderBottom + & {
border-top: none;
......@@ -11,7 +11,7 @@
}
.borderBottom {
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--mb-color-border);
&:last-child {
border-bottom: none;
......@@ -19,7 +19,7 @@
}
.action {
color: var(--color-text-dark);
color: var(--mb-color-text-dark);
&:hover {
color: inherit;
......
......@@ -10,7 +10,7 @@
}
.ContentTable thead {
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid var(--mb-color-border);
}
.PageHeader {
......@@ -32,7 +32,7 @@
}
.ContentTable th {
color: var(--color-text-dark);
color: var(--mb-color-text-dark);
padding: 1em;
}
......@@ -48,11 +48,11 @@
.AdminList {
background-color: var(--color-bg-light);
border: var(--border-size) var(--border-style) var(--color-border);
border: var(--border-size) var(--border-style) var(--mb-color-border);
border-radius: var(--default-border-radius);
width: 266px;
min-height: 300px;
box-shadow: inset -1px -1px 3px var(--color-shadow);
box-shadow: inset -1px -1px 3px var(--mb-color-shadow);
padding-bottom: 0.75em;
}
......@@ -76,7 +76,7 @@
width: 100%;
border-top-left-radius: var(--default-border-radius);
border-top-right-radius: var(--default-border-radius);
border-bottom-color: var(--color-border);
border-bottom-color: var(--mb-color-border);
}
.AdminListItem {
......@@ -93,12 +93,12 @@
.AdminListItem.selected,
.AdminListItem:hover {
background-color: white;
border-color: var(--color-border);
border-color: var(--mb-color-border);
margin-left: -0.5em;
margin-right: -0.5em;
padding-left: 1.5em;
padding-right: 1.5em;
box-shadow: 0 1px 2px var(--color-shadow);
box-shadow: 0 1px 2px var(--mb-color-shadow);
}
.AdminListSection {
......@@ -112,7 +112,7 @@
}
.AdminInput {
color: var(--color-text-dark);
color: var(--mb-color-text-dark);
padding: var(--padding-1);
background-color: var(--color-bg-light);
border: 1px solid transparent;
......@@ -163,7 +163,7 @@
}
.AdminTable thead {
border-bottom: var(--border-size) var(--border-style) var(--color-border);
border-bottom: var(--border-size) var(--border-style) var(--mb-color-border);
}
.AdminTable tbody tr:first-child td {
......
......@@ -8,8 +8,8 @@
text-decoration: none;
padding: 0.5rem 0.75rem;
background: transparent;
border: 1px solid color-mod(var(--color-border) blackness(5%));
color: var(--color-text-dark);
border: 1px solid color-mod(var(--mb-color-border) blackness(5%));
color: var(--mb-color-text-dark);
cursor: pointer;
font-weight: bold;
font-family: var(--mb-default-font-family), sans-serif;
......@@ -18,7 +18,7 @@
.Button:hover {
color: var(--mb-color-brand);
border-color: color-mod(var(--color-border) blackness(12%));
border-color: color-mod(var(--mb-color-border) blackness(12%));
background: var(--color-bg-light);
transition: all 200ms linear;
transition-property: color, border-color, background-color;
......@@ -90,8 +90,8 @@
.ButtonWhite {
background-color: white;
color: var(--color-text-dark);
border-color: var(--color-border);
color: var(--mb-color-text-dark);
border-color: var(--mb-color-border);
}
.ButtonBorderless {
......@@ -108,14 +108,14 @@
.ButtonOnlyIcon {
border: none;
background: transparent;
color: var(--color-text-dark);
color: var(--mb-color-text-dark);
padding: 0;
}
.ButtonGroup {
display: inline-block;
border-radius: var(--default-button-border-radius);
border: 1px solid var(--color-border);
border: 1px solid var(--mb-color-border);
overflow: hidden;
clear: both;
}
......
......@@ -31,10 +31,10 @@
font-family: var(--mb-default-font-family);
font-weight: 700;
font-size: 16px;
color: var(--color-text-dark);
background-color: var(--color-bg-white);
color: var(--mb-color-text-dark);
background-color: var(--mb-color-bg-white);
padding: 0.75em;
border: 1px solid var(--color-border);
border: 1px solid var(--mb-color-border);
border-radius: 8px;
outline: none;
}
......
.ListSectionHeader :global(.Icon),
.ListItem .ListItemArrow :global(.Icon) {
color: var(--color-text-dark);
color: var(--mb-color-text-dark);
}
.ListSectionHeader:hover :global(.Icon) {
......@@ -12,7 +12,7 @@
}
.ListSectionHeader {
color: var(--color-text-dark);
color: var(--mb-color-text-dark);
border: 2px solid transparent;
/* so that spacing matches [data-element-id=list-item] */
......@@ -34,7 +34,7 @@
}
.ListSectionExpanded .ListSectionHeader .ListSectionTitle {
color: var(--color-text-dark);
color: var(--mb-color-text-dark);
}
.ListSectionTitle {
......@@ -61,7 +61,7 @@
/* LIST ITEM TITLE */
.ListItemTitle {
color: var(--color-text-dark);
color: var(--mb-color-text-dark);
}
.ListItemDisabled .ListItemTitle {
......@@ -82,7 +82,7 @@
}
.ListItemDisabled .ListItemDescription {
color: var(--color-text-dark);
color: var(--mb-color-text-dark);
}
.ListItemCursor:not(.ListItemDisabled) .ListItemDescription,
......
......@@ -5,7 +5,7 @@
.Modal {
margin: auto;
width: 640px;
box-shadow: 0 0 6px var(--color-shadow);
box-shadow: 0 0 6px var(--mb-color-shadow);
max-height: 90%;
overflow-y: auto;
}
......@@ -49,7 +49,7 @@
}
.ModalBackdrop {
background-color: color-mod(var(--color-bg-black) alpha(-40%));
background-color: color-mod(var(--mb-color-bg-black) alpha(-40%));
}
/* TRANSITIONS */
......@@ -58,22 +58,22 @@
.ModalBackdrop.ModalAppear,
.ModalBackdrop.ModalEnter {
background-color: color-mod(var(--color-bg-black) alpha(-99%));
background-color: color-mod(var(--mb-color-bg-black) alpha(-99%));
}
.ModalBackdrop.ModalAppearActive,
.ModalBackdrop.ModalEnterActive {
transition: background-color 200ms ease-in-out;
background-color: color-mod(var(--color-bg-black) alpha(-40%));
background-color: color-mod(var(--mb-color-bg-black) alpha(-40%));
}
.ModalBackdrop.ModalExit {
background-color: color-mod(var(--color-bg-black) alpha(-40%));
background-color: color-mod(var(--mb-color-bg-black) alpha(-40%));
}
.ModalBackdrop.ModalExitActive {
transition: background-color 200ms ease-in-out 100ms;
background-color: color-mod(var(--color-bg-black) alpha(-99%));
background-color: color-mod(var(--mb-color-bg-black) alpha(-99%));
}
/* modal */
......
......@@ -2,15 +2,15 @@
--border-size: 1px;
--border-size-medium: 2px;
--border-style: solid;
--border-color: var(--color-border);
--border-color: var(--mb-color-border);
}
.bordered {
border: var(--border-size) var(--border-style) var(--color-border);
border: var(--border-size) var(--border-style) var(--mb-color-border);
}
.borderBottom {
border-bottom: var(--border-size) var(--border-style) var(--color-border);
border-bottom: var(--border-size) var(--border-style) var(--mb-color-border);
}
/* ensure that a border-top item inside of a bordered element won't double up */
......@@ -19,7 +19,7 @@
}
.borderTop {
border-top: var(--border-size) var(--border-style) var(--color-border);
border-top: var(--border-size) var(--border-style) var(--mb-color-border);
}
/* ensure that a border-top item inside of a bordered element won't double up */
......@@ -28,7 +28,7 @@
}
.borderRowDivider {
border-bottom: var(--border-size) var(--border-style) var(--color-border);
border-bottom: var(--border-size) var(--border-style) var(--mb-color-border);
}
.borderRowDivider:last-child {
......@@ -36,15 +36,15 @@
}
.borderRight {
border-right: var(--border-size) var(--border-style) var(--color-border);
border-right: var(--border-size) var(--border-style) var(--mb-color-border);
}
.borderLeft {
border-left: var(--border-size) var(--border-style) var(--color-border);
border-left: var(--border-size) var(--border-style) var(--mb-color-border);
}
.borderLight {
border-color: color-mod(var(--color-border) alpha(-80%)) !important;
border-color: color-mod(var(--mb-color-border) alpha(-80%)) !important;
}
.borderError {
......
......@@ -6,21 +6,21 @@
--color-success: #84bb4c;
--color-summarize: #88bf4d;
--color-error: #ed6e6e;
--color-text-dark: #4c5773;
--mb-color-text-dark: #4c5773;
--color-text-medium: #696e7b;
--color-text-light: #949aab;
--color-text-white: #fff;
--color-bg-black: #2e353b;
--mb-color-bg-black: #2e353b;
--color-bg-dark: #93a1ab;
--color-bg-medium: #edf2f5;
--color-bg-light: #f9fbfc;
--color-bg-white: #fff;
--color-shadow: rgba(0, 0, 0, 0.13);
--color-border: #eeecec;
--mb-color-bg-white: #fff;
--mb-color-shadow: rgba(0, 0, 0, 0.13);
--mb-color-border: #eeecec;
}
.textDefault {
color: var(--color-text-dark);
color: var(--mb-color-text-dark);
}
.textBrand {
......@@ -43,7 +43,7 @@
}
.bgErrorInput {
background-color: var(--color-bg-white);
background-color: var(--mb-color-bg-white);
}
.textSlate {
......@@ -65,7 +65,7 @@
.textDark,
.textDarkHover:hover {
color: var(--color-text-dark);
color: var(--mb-color-text-dark);
}
.bgLight,
......@@ -84,7 +84,7 @@
}
.bgWhite {
background-color: var(--color-bg-white);
background-color: var(--mb-color-bg-white);
}
.bgLightBlue {
......@@ -92,7 +92,7 @@
}
.DashboardNight .bgLight {
background-color: var(--color-bg-black);
background-color: var(--mb-color-bg-black);
}
.DashboardNight .bgMedium {
......
:root {
--input-border-color: var(--color-border);
--input-border-color: var(--mb-color-border);
--input-border-radius: 8px;
}
.input {
color: var(--color-text-dark);
color: var(--mb-color-text-dark);
font-size: 1.12em;
padding: 0.75rem 0.75rem;
border: 1px solid var(--input-border-color);
......@@ -23,7 +23,7 @@
outline: none;
border: 1px solid var(--mb-color-brand);
transition: border 0.3s linear;
color: var(--color-text-dark);
color: var(--mb-color-text-dark);
}
.inputBorderless,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment