From 34ca45e98534af23eae871b0a61662ff2e360411 Mon Sep 17 00:00:00 2001 From: Dave Falke Date: Wed, 20 Nov 2024 09:36:16 -0500 Subject: [PATCH 1/4] checkpoint --- packages/libs/eda/src/index.tsx | 12 +++ .../lib/core/components/FilterChipList.tsx | 2 +- .../src/lib/notebook/EdaNotebookAnalysis.tsx | 86 +++++++++++++++++++ .../lib/notebook/EdaNotebookLandingPage.tsx | 37 ++++++++ .../eda/src/lib/notebook/NotebookRoute.tsx | 64 ++++++++++++++ 5 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 packages/libs/eda/src/lib/notebook/EdaNotebookAnalysis.tsx create mode 100644 packages/libs/eda/src/lib/notebook/EdaNotebookLandingPage.tsx create mode 100644 packages/libs/eda/src/lib/notebook/NotebookRoute.tsx diff --git a/packages/libs/eda/src/index.tsx b/packages/libs/eda/src/index.tsx index de7c8ec358..6432296ca0 100644 --- a/packages/libs/eda/src/index.tsx +++ b/packages/libs/eda/src/index.tsx @@ -60,6 +60,7 @@ import './index.css'; // snackbar import makeSnackbarProvider from '@veupathdb/coreui/lib/components/notifications/SnackbarProvider'; +import NotebookRoute from './lib/notebook/NotebookRoute'; // Set singleAppMode to the name of one app, if the eda should use one instance of one app only. // Otherwise, let singleAppMode remain undefined or set it to '' to allow multiple app instances. @@ -169,9 +170,20 @@ initialize({ All studies +

Notebook Links

+ ), }, + { + path: '/notebook', + exact: false, + component: () => , + }, { path: '/eda', exact: false, diff --git a/packages/libs/eda/src/lib/core/components/FilterChipList.tsx b/packages/libs/eda/src/lib/core/components/FilterChipList.tsx index 7d3bbef119..326b6151b6 100644 --- a/packages/libs/eda/src/lib/core/components/FilterChipList.tsx +++ b/packages/libs/eda/src/lib/core/components/FilterChipList.tsx @@ -10,7 +10,7 @@ import { colors, Warning } from '@veupathdb/coreui'; // Material UI CSS declarations const useStyles = makeStyles((theme) => ({ chips: { - display: 'flex', + display: 'inline-flex', flexWrap: 'wrap', '& > *:not(:last-of-type)': { // Spacing between chips diff --git a/packages/libs/eda/src/lib/notebook/EdaNotebookAnalysis.tsx b/packages/libs/eda/src/lib/notebook/EdaNotebookAnalysis.tsx new file mode 100644 index 0000000000..42dd05d224 --- /dev/null +++ b/packages/libs/eda/src/lib/notebook/EdaNotebookAnalysis.tsx @@ -0,0 +1,86 @@ +import React, { useState } from 'react'; +import { + Filter, + useAnalysis, + useStudyEntities, + useStudyMetadata, + useStudyRecord, +} from '../core'; +import { safeHtml } from '@veupathdb/wdk-client/lib/Utils/ComponentUtils'; +import { SaveableTextEditor } from '@veupathdb/wdk-client/lib/Components'; +import Subsetting from '../workspace/Subsetting'; +import { useEntityCounts } from '../core/hooks/entityCounts'; +import FilterChipList from '../core/components/FilterChipList'; + +interface Props { + analysisId: string; +} + +export function EdaNotebookAnalysis(props: Props) { + const { analysisId } = props; + const analysisState = useAnalysis( + analysisId === 'new' ? undefined : analysisId + ); + const studyRecord = useStudyRecord(); + const studyMetadata = useStudyMetadata(); + const entities = useStudyEntities(); + const totalCountsResult = useEntityCounts(); + const filteredCountsResult = useEntityCounts( + analysisState.analysis?.descriptor.subset.descriptor + ); + const [entityId, setEntityId] = useState(); + const [variableId, setVariableId] = useState(); + return ( +
+

EDA Notebook

+ {safeHtml(studyRecord.displayName, null, 'h2')} +

+ +

+
+ + Subset    + + analysisState.setFilters((filters) => + filters.filter( + (f) => + f.entityId !== filter.entityId || + f.variableId !== filter.variableId + ) + ) + } + variableLinkConfig={{ + type: 'button', + onClick: (value) => { + setEntityId(value?.entityId); + setVariableId(value?.variableId); + }, + }} + /> + + { + setEntityId(value?.entityId); + setVariableId(value?.variableId); + }, + }} + /> +
+
+ ); +} diff --git a/packages/libs/eda/src/lib/notebook/EdaNotebookLandingPage.tsx b/packages/libs/eda/src/lib/notebook/EdaNotebookLandingPage.tsx new file mode 100644 index 0000000000..bd1b86c167 --- /dev/null +++ b/packages/libs/eda/src/lib/notebook/EdaNotebookLandingPage.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { useWdkStudyRecords } from '../core/hooks/study'; +import { useConfiguredSubsettingClient } from '../core/hooks/client'; +import { Link, useRouteMatch } from 'react-router-dom'; +import { safeHtml } from '@veupathdb/wdk-client/lib/Utils/ComponentUtils'; + +interface Props { + edaServiceUrl: string; +} + +export function EdaNotebookLandingPage(props: Props) { + const subsettingClient = useConfiguredSubsettingClient(props.edaServiceUrl); + const datasets = useWdkStudyRecords(subsettingClient); + const { url } = useRouteMatch(); + return ( +
+

EDA Notebooks

+
+

Start a new notebook

+
    + {datasets?.map((dataset) => ( +
  • + {safeHtml( + dataset.displayName, + { to: `${url}/${dataset.attributes.dataset_id as string}/new` }, + Link + )} +
  • + ))} +
+
+
+
MY NOTEBOOKS
+
SHARED NOTEBOOKS
+
+ ); +} diff --git a/packages/libs/eda/src/lib/notebook/NotebookRoute.tsx b/packages/libs/eda/src/lib/notebook/NotebookRoute.tsx new file mode 100644 index 0000000000..cec69d1b8f --- /dev/null +++ b/packages/libs/eda/src/lib/notebook/NotebookRoute.tsx @@ -0,0 +1,64 @@ +import React, { ComponentType } from 'react'; +import { Route, Switch, useRouteMatch } from 'react-router-dom'; +import { EdaNotebookLandingPage } from './EdaNotebookLandingPage'; +import { EdaNotebookAnalysis } from './EdaNotebookAnalysis'; +import { + EDAWorkspaceContainer, + useConfiguredAnalysisClient, + useConfiguredComputeClient, + useConfiguredDataClient, + useConfiguredDownloadClient, + useConfiguredSubsettingClient, +} from '../core'; +import { DocumentationContainer } from '../core/components/docs/DocumentationContainer'; +import { QueryClientProvider } from '@tanstack/react-query'; +import { queryClient } from '../core/api/queryClient'; + +interface Props { + edaServiceUrl: string; + datasetId?: string; + analysisId?: string; +} + +export default function NotebookRoute(props: Props) { + const { edaServiceUrl } = props; + const match = useRouteMatch(); + const analysisClient = useConfiguredAnalysisClient(edaServiceUrl); + const subsettingClient = useConfiguredSubsettingClient(edaServiceUrl); + const downloadClient = useConfiguredDownloadClient(edaServiceUrl); + const dataClient = useConfiguredDataClient(edaServiceUrl); + const computeClient = useConfiguredComputeClient(edaServiceUrl); + + return ( + + + + ( + + )} + /> + ( + + + + )} + /> + + + + ); +} From e162ad7caa8ec5c9a6b76738b04df866f7ff08c8 Mon Sep 17 00:00:00 2001 From: Dave Falke Date: Thu, 21 Nov 2024 14:07:26 -0500 Subject: [PATCH 2/4] Checkpoint - Basics of cell types - Persistence - Iterate on styling --- .../src/lib/core/components/VariableLink.tsx | 2 +- .../eda/src/lib/notebook/EdaNotebook.scss | 35 ++++ .../src/lib/notebook/EdaNotebookAnalysis.tsx | 153 ++++++++++-------- .../eda/src/lib/notebook/NotebookCell.tsx | 28 ++++ .../lib/notebook/SubsettingNotebookCell.tsx | 58 +++++++ packages/libs/eda/src/lib/notebook/Types.ts | 44 +++++ 6 files changed, 250 insertions(+), 70 deletions(-) create mode 100644 packages/libs/eda/src/lib/notebook/EdaNotebook.scss create mode 100644 packages/libs/eda/src/lib/notebook/NotebookCell.tsx create mode 100644 packages/libs/eda/src/lib/notebook/SubsettingNotebookCell.tsx create mode 100644 packages/libs/eda/src/lib/notebook/Types.ts diff --git a/packages/libs/eda/src/lib/core/components/VariableLink.tsx b/packages/libs/eda/src/lib/core/components/VariableLink.tsx index 02fd7d9c29..f1625ce260 100644 --- a/packages/libs/eda/src/lib/core/components/VariableLink.tsx +++ b/packages/libs/eda/src/lib/core/components/VariableLink.tsx @@ -70,12 +70,12 @@ export const VariableLink = forwardRef( tabIndex={0} style={finalStyle} onKeyDown={(event) => { - event.preventDefault(); if (disabled) { return; } if (event.key === 'Enter' || event.key === ' ') { linkConfig.onClick(value); + event.preventDefault(); } }} onClick={(event) => { diff --git a/packages/libs/eda/src/lib/notebook/EdaNotebook.scss b/packages/libs/eda/src/lib/notebook/EdaNotebook.scss new file mode 100644 index 0000000000..0f0a50c61b --- /dev/null +++ b/packages/libs/eda/src/lib/notebook/EdaNotebook.scss @@ -0,0 +1,35 @@ +.EdaNotebook { + .Heading { + display: flex; + gap: 2em; + align-items: baseline; + } + + .Paper { + max-width: 1250px; + padding: 1em; + margin: 1em auto; + background-color: #f3f3f3; + box-shadow: 0 0 2px #b5b5b5; + + > * + * { + margin-block-start: 1rem; + } + h2, + h3 { + padding: 0; + } + h3 { + font-size: 1em; + font-weight: 400; + line-height: 1.5; + } + } + + .Title { + fieldset { + padding: 0; + margin: 0; + } + } +} diff --git a/packages/libs/eda/src/lib/notebook/EdaNotebookAnalysis.tsx b/packages/libs/eda/src/lib/notebook/EdaNotebookAnalysis.tsx index 42dd05d224..327a3a7a20 100644 --- a/packages/libs/eda/src/lib/notebook/EdaNotebookAnalysis.tsx +++ b/packages/libs/eda/src/lib/notebook/EdaNotebookAnalysis.tsx @@ -1,16 +1,31 @@ -import React, { useState } from 'react'; -import { - Filter, - useAnalysis, - useStudyEntities, - useStudyMetadata, - useStudyRecord, -} from '../core'; +// Notes +// ===== +// +// - For now, we will only support "fixed" notebooks. If we want to allow "custom" notebooks, +// we have to make some decisions. +// - Do we want a top-down data flow? E.g., subsetting is global for an analysis. +// - Do we want to separate compute config from visualization? If so, how do we +// support that in the UI? +// - Do we want text-based cells? +// - Do we want download cells? It could have a preview. +// + +import React, { useCallback, useMemo } from 'react'; +import { useAnalysis, useStudyRecord } from '../core'; import { safeHtml } from '@veupathdb/wdk-client/lib/Utils/ComponentUtils'; import { SaveableTextEditor } from '@veupathdb/wdk-client/lib/Components'; -import Subsetting from '../workspace/Subsetting'; -import { useEntityCounts } from '../core/hooks/entityCounts'; -import FilterChipList from '../core/components/FilterChipList'; +import { ExpandablePanel } from '@veupathdb/coreui'; +import { NotebookCell as NotebookCellType } from './Types'; +import { NotebookCell } from './NotebookCell'; + +import './EdaNotebook.scss'; + +interface NotebookSettings { + /** Ordered array of notebook cells */ + cells: NotebookCellType[]; +} + +const NOTEBOOK_UI_SETTINGS_KEY = '@@NOTEBOOK@@'; interface Props { analysisId: string; @@ -18,69 +33,69 @@ interface Props { export function EdaNotebookAnalysis(props: Props) { const { analysisId } = props; + const studyRecord = useStudyRecord(); const analysisState = useAnalysis( analysisId === 'new' ? undefined : analysisId ); - const studyRecord = useStudyRecord(); - const studyMetadata = useStudyMetadata(); - const entities = useStudyEntities(); - const totalCountsResult = useEntityCounts(); - const filteredCountsResult = useEntityCounts( - analysisState.analysis?.descriptor.subset.descriptor + const { analysis } = analysisState; + const notebookSettings = useMemo((): NotebookSettings => { + const storedSettings = + analysis?.descriptor.subset.uiSettings[NOTEBOOK_UI_SETTINGS_KEY]; + if (storedSettings == null) + return { + cells: [ + { + type: 'subset', + title: 'Subset data', + }, + ], + }; + return storedSettings as any as NotebookSettings; + }, [analysis]); + const updateCell = useCallback( + (cell: Partial>, cellIndex: number) => { + const oldCell = notebookSettings.cells[cellIndex]; + const newCell = { ...oldCell, ...cell }; + const nextCells = notebookSettings.cells.concat(); + nextCells[cellIndex] = newCell; + const nextSettings = { + ...notebookSettings, + cells: nextCells, + }; + analysisState.setVariableUISettings({ + [NOTEBOOK_UI_SETTINGS_KEY]: nextSettings, + }); + }, + [analysisState, notebookSettings] ); - const [entityId, setEntityId] = useState(); - const [variableId, setVariableId] = useState(); return ( -
-

EDA Notebook

- {safeHtml(studyRecord.displayName, null, 'h2')} -

- -

-
- - Subset    - - analysisState.setFilters((filters) => - filters.filter( - (f) => - f.entityId !== filter.entityId || - f.variableId !== filter.variableId - ) - ) - } - variableLinkConfig={{ - type: 'button', - onClick: (value) => { - setEntityId(value?.entityId); - setVariableId(value?.variableId); - }, - }} - /> - - { - setEntityId(value?.entityId); - setVariableId(value?.variableId); - }, - }} - /> -
+
+
+

EDA Notebook

+
+
+
+

+ +

+

Study: {safeHtml(studyRecord.displayName)}

+
+ {notebookSettings.cells.map((cell, index) => ( + +
+ updateCell(update, index)} + /> +
+
+ ))} +
); } diff --git a/packages/libs/eda/src/lib/notebook/NotebookCell.tsx b/packages/libs/eda/src/lib/notebook/NotebookCell.tsx new file mode 100644 index 0000000000..dbf36328e3 --- /dev/null +++ b/packages/libs/eda/src/lib/notebook/NotebookCell.tsx @@ -0,0 +1,28 @@ +import { AnalysisState } from '../core'; +import { NotebookCell as NotebookCellType } from './Types'; +import { SubsettingNotebookCell } from './SubsettingNotebookCell'; + +interface Props { + analysisState: AnalysisState; + cell: NotebookCellType; + updateCell: (cell: Partial>) => void; +} + +/** + * Top-level component that delegates to imeplementations of NotebookCell variants. + */ +export function NotebookCell(props: Props) { + const { cell, analysisState, updateCell } = props; + switch (cell.type) { + case 'subset': + return ( + + ); + default: + return null; + } +} diff --git a/packages/libs/eda/src/lib/notebook/SubsettingNotebookCell.tsx b/packages/libs/eda/src/lib/notebook/SubsettingNotebookCell.tsx new file mode 100644 index 0000000000..ef817993a1 --- /dev/null +++ b/packages/libs/eda/src/lib/notebook/SubsettingNotebookCell.tsx @@ -0,0 +1,58 @@ +import { useMemo } from 'react'; +import { useEntityCounts } from '../core/hooks/entityCounts'; +import { useStudyEntities } from '../core/hooks/workspace'; +import { NotebookCellComponentProps } from './Types'; +import { VariableLinkConfig } from '../core/components/VariableLink'; +import FilterChipList from '../core/components/FilterChipList'; +import Subsetting from '../workspace/Subsetting'; + +export function SubsettingNotebookCell( + props: NotebookCellComponentProps<'subset'> +) { + const { analysisState, cell, updateCell } = props; + const { selectedVariable } = cell; + const entities = useStudyEntities(); + const totalCountsResult = useEntityCounts(); + const filteredCountsResult = useEntityCounts( + analysisState.analysis?.descriptor.subset.descriptor + ); + const variableLinkConfig = useMemo( + (): VariableLinkConfig => ({ + type: 'button', + onClick: (selectedVariable) => { + updateCell({ selectedVariable }); + }, + }), + [updateCell] + ); + return ( +
+
+ { + analysisState.setFilters((filters) => + filters.filter( + (f) => + f.entityId !== filter.entityId || + f.variableId !== filter.variableId + ) + ); + }} + variableLinkConfig={variableLinkConfig} + /> +
+ +
+ ); +} diff --git a/packages/libs/eda/src/lib/notebook/Types.ts b/packages/libs/eda/src/lib/notebook/Types.ts new file mode 100644 index 0000000000..9575556c55 --- /dev/null +++ b/packages/libs/eda/src/lib/notebook/Types.ts @@ -0,0 +1,44 @@ +import { AnalysisState } from '../core/hooks/analysis'; +import { VariableDescriptor } from '../core/types/variable'; + +export interface NotebookCellBase { + type: T; + title: string; +} + +export interface SubsettingNotebookCell extends NotebookCellBase<'subset'> { + selectedVariable?: Partial; +} + +export interface ComputeNotebookCell extends NotebookCellBase<'compute'> { + computeId: string; +} + +export interface VisualizationNotebookCell + extends NotebookCellBase<'visualization'> { + visualizationId: string; +} + +export interface TextNotebookCell extends NotebookCellBase<'text'> { + text: string; +} + +export type NotebookCell = + | SubsettingNotebookCell + | ComputeNotebookCell + | VisualizationNotebookCell + | TextNotebookCell; + +type FindByType = Union extends { type: Type } ? Union : never; + +export type NotebookCellOfType = FindByType< + NotebookCell, + T +>; + +export interface NotebookCellComponentProps { + analysisState: AnalysisState; + cell: NotebookCellOfType; + // Allow partial updates, but don't allow `type` to be changed. + updateCell: (cell: Omit>, 'type'>) => void; +} From d1db6f97101662d1686f4be7bc14d6692a8aaba1 Mon Sep 17 00:00:00 2001 From: Dave Falke Date: Fri, 22 Nov 2024 12:19:24 -0500 Subject: [PATCH 3/4] Checkpoint - Expose some coreui theme values as custom css properties - Replace ExpandablePanel with
- Replace SCSS file with CSS file --- .../components/theming/UIThemeProvider.tsx | 14 ++- .../libs/eda/src/lib/notebook/EdaNotebook.css | 116 ++++++++++++++++++ .../eda/src/lib/notebook/EdaNotebook.scss | 35 ------ .../src/lib/notebook/EdaNotebookAnalysis.tsx | 30 ++--- 4 files changed, 141 insertions(+), 54 deletions(-) create mode 100644 packages/libs/eda/src/lib/notebook/EdaNotebook.css delete mode 100644 packages/libs/eda/src/lib/notebook/EdaNotebook.scss diff --git a/packages/libs/coreui/src/components/theming/UIThemeProvider.tsx b/packages/libs/coreui/src/components/theming/UIThemeProvider.tsx index e6481d115a..b6c35d226c 100644 --- a/packages/libs/coreui/src/components/theming/UIThemeProvider.tsx +++ b/packages/libs/coreui/src/components/theming/UIThemeProvider.tsx @@ -14,13 +14,23 @@ export default function UIThemeProvider({ children, }: UIThemeProviderProps) { useCoreUIFonts(); + // In addition to making the theme available via React Context, + // we will also expose the theme as custom CSS properties. return ( diff --git a/packages/libs/eda/src/lib/notebook/EdaNotebook.css b/packages/libs/eda/src/lib/notebook/EdaNotebook.css new file mode 100644 index 0000000000..be2665e7d6 --- /dev/null +++ b/packages/libs/eda/src/lib/notebook/EdaNotebook.css @@ -0,0 +1,116 @@ +.EdaNotebook { + .Heading { + display: flex; + gap: 2em; + align-items: baseline; + } + + .Paper { + /* A4 dimensions */ + --paper-width: 2480px; + --paper-height: 3508px; + --paper-scale: 0.5; + + width: calc(var(--paper-width) * var(--paper-scale)); + /* height: calc(var(--paper-height) * var(--paper-scale)); */ + + padding: 2em; + margin: 1em auto; + + /* background-color: #f3f3f3; */ + box-shadow: 0 0 2px #b5b5b5; + + > * + * { + margin-block-start: 1rem; + } + + .Heading { + display: flex; + flex-direction: row; + justify-content: space-between; + gap: 0.5em; + + h1 { + padding: 0; + font-size: 1.75em; + } + + h2 { + font-size: 1em; + font-weight: bold; + padding: 0.25em 0.5em; + color: var(--coreui-color-primary, black); + border: 2px solid; + border-radius: 0.25em; + background-color: color-mix( + in srgb, + var(--coreui-color-primary) 5%, + transparent + ); + } + } + + > details { + border: 1px solid; + border-color: color-mix( + in srgb, + var(--coreui-color-primary) 30%, + transparent + ); + border-top-left-radius: 0.5em; + border-top-right-radius: 0.5em; + border-bottom-left-radius: 0.5em; + border-bottom-right-radius: 0.5em; + + > summary { + padding: 0.75em; + cursor: pointer; + font-size: 1.2em; + font-weight: 500; + background-color: color-mix( + in srgb, + var(--coreui-color-primary) 10%, + transparent + ); + + &:hover { + background-color: color-mix( + in srgb, + var(--coreui-color-primary) 20%, + transparent + ); + } + + &:active { + background-color: color-mix( + in srgb, + var(--coreui-color-primary) 15%, + transparent + ); + } + + transition: background-color 100ms ease-in; + } + + &[open] > summary { + border-bottom: 1px solid; + border-color: color-mix( + in srgb, + var(--coreui-color-primary) 30%, + transparent + ); + } + + > div { + padding: 1em; + } + } + } + + .Title { + fieldset { + padding: 0; + margin: 0; + } + } +} diff --git a/packages/libs/eda/src/lib/notebook/EdaNotebook.scss b/packages/libs/eda/src/lib/notebook/EdaNotebook.scss deleted file mode 100644 index 0f0a50c61b..0000000000 --- a/packages/libs/eda/src/lib/notebook/EdaNotebook.scss +++ /dev/null @@ -1,35 +0,0 @@ -.EdaNotebook { - .Heading { - display: flex; - gap: 2em; - align-items: baseline; - } - - .Paper { - max-width: 1250px; - padding: 1em; - margin: 1em auto; - background-color: #f3f3f3; - box-shadow: 0 0 2px #b5b5b5; - - > * + * { - margin-block-start: 1rem; - } - h2, - h3 { - padding: 0; - } - h3 { - font-size: 1em; - font-weight: 400; - line-height: 1.5; - } - } - - .Title { - fieldset { - padding: 0; - margin: 0; - } - } -} diff --git a/packages/libs/eda/src/lib/notebook/EdaNotebookAnalysis.tsx b/packages/libs/eda/src/lib/notebook/EdaNotebookAnalysis.tsx index 327a3a7a20..6cb8f53d72 100644 --- a/packages/libs/eda/src/lib/notebook/EdaNotebookAnalysis.tsx +++ b/packages/libs/eda/src/lib/notebook/EdaNotebookAnalysis.tsx @@ -18,7 +18,7 @@ import { ExpandablePanel } from '@veupathdb/coreui'; import { NotebookCell as NotebookCellType } from './Types'; import { NotebookCell } from './NotebookCell'; -import './EdaNotebook.scss'; +import './EdaNotebook.css'; interface NotebookSettings { /** Ordered array of notebook cells */ @@ -70,30 +70,26 @@ export function EdaNotebookAnalysis(props: Props) { ); return (
-
-

EDA Notebook

-
-
-

+
+

-

-

Study: {safeHtml(studyRecord.displayName)}

+

+

{safeHtml(studyRecord.displayName)}

{notebookSettings.cells.map((cell, index) => ( - -
- updateCell(update, index)} - /> -
-
+
+ {cell.title} + updateCell(update, index)} + /> +
))}
From d3d696645d2e1fa96e78eabc5d4b760b374d29b3 Mon Sep 17 00:00:00 2001 From: Dave Falke Date: Fri, 22 Nov 2024 13:10:15 -0500 Subject: [PATCH 4/4] Expose all coreui color definitions as css custom properties. --- .../coreui/src/components/theming/UIThemeProvider.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/libs/coreui/src/components/theming/UIThemeProvider.tsx b/packages/libs/coreui/src/components/theming/UIThemeProvider.tsx index b6c35d226c..db0c10088b 100644 --- a/packages/libs/coreui/src/components/theming/UIThemeProvider.tsx +++ b/packages/libs/coreui/src/components/theming/UIThemeProvider.tsx @@ -3,6 +3,7 @@ import { css, Global, ThemeProvider } from '@emotion/react'; import { useCoreUIFonts } from '../../hooks'; import { UITheme } from './types'; +import colors from '../../definitions/colors'; export type UIThemeProviderProps = { theme: UITheme; @@ -21,6 +22,15 @@ export default function UIThemeProvider({ + typeof byHueOrValue === 'string' + ? [`--coreui-${colorName}: ${byHueOrValue};`] + : Object.entries(byHueOrValue).map( + ([hueName, colorValue]) => + `--coreui-${colorName}-${hueName}: ${colorValue};` + ) + )} + --coreui-color-primary: ${theme.palette.primary.hue[ theme.palette.primary.level ]};