Skip to content

Commit

Permalink
Support themes
Browse files Browse the repository at this point in the history
  • Loading branch information
drx committed May 28, 2024
1 parent a5c9417 commit ff1a611
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 46 deletions.
7 changes: 5 additions & 2 deletions react/src/CanvasElement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { SearchComponent } from './components/SearchComponent';
import { Theme, getTheme } from './components/layout/themes/theme.util';
import { Table } from './Table';
import { SvgChart } from './SvgChart';
import { ChartTheme } from './ChartTheme';

export const CanvasElement = ({
element,
Expand All @@ -25,13 +26,15 @@ export const CanvasElement = ({

const { elementType, title } = element;

const mergedTheme = getTheme(theme);
const mergedTheme = getTheme(theme as any);

if (elementType.type === 'chart') {
const chartTitle = title || 'Chart';
return (
<Element key={elementId} title={chartTitle} elementId={elementId}>
<SvgChart data={elementType.chartData} theme={mergedTheme} />
<ChartTheme data={elementType.chartData} theme={mergedTheme}>
<SvgChart data={elementType.chartData} theme={mergedTheme} />
</ChartTheme>
</Element>
);
}
Expand Down
4 changes: 2 additions & 2 deletions react/src/ChartTheme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ export function ChartTheme({
children,
}: {
data: ChartData | undefined;
theme: Theme;
theme: Theme | undefined;
children: ReactNode;
}): ReactElement {
const colors = useMemo(() => {
if (data) {
if (data && theme) {
return getColors(data, theme);
}
}, [data, theme]);
Expand Down
84 changes: 42 additions & 42 deletions react/src/components/layout/themes/theme.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ import chroma from 'chroma-js';
export type FontFamily =
| {
type: 'file';
fileType: 'woff2';
fileType: 'woff' | 'woff2';
name: string;
url: string;
}
| { type: 'browser'; name: string };

type Palette = string[] | { light: string[]; dark: string[] } | { scale: string[] };
type Palette = { type: 'palette' | 'scale' | 'map'; colors: string[]; darkColors?: string[]; name: string };

export type Theme = {
palettes: { [palette: string]: Palette };
palettes?: Palette[];
fonts?: {
// Body font - required
body: FontFamily;
// Body font
body?: FontFamily;

// Display font (headings, titles, etc.), if different from body font
display?: FontFamily;
Expand All @@ -25,68 +25,68 @@ export type Theme = {
};
};

export const DEFAULT_PALETTE: Palette = {
name: 'Bright',
type: 'palette',
colors: ['#5ba8f7', '#9b54f3', '#e6482c', '#f98517', '#fdd146', '#72b622'],
};
export const DEFAULT_MAP_PALETTE: Palette = { type: 'map', colors: ['#5aa7f6', '#f4f7fb'], name: 'Map Default' };

export const defaultTheme: Theme = {
palettes: {
default: {
light: ['#3742a0', '#129dc9', '#28c093', '#df3f3f', '#f48d54', '#fac372'],
dark: ['#5ba8f7', '#129dc9', '#28c093', '#df3f3f', '#f48d54', '#fac372'],
},
Bright: ['#5ba8f7', '#9b54f3', '#e6482c', '#f98517', '#fdd146', '#72b622'],
Plasma: {
scale: ['#1d1489', '#f4bb4d'],
},
GreenYellow: {
scale: ['#103338', '#D1DA62'],
},
Blue: {
scale: ['#0E2836', '#55C4F9'],
palettes: [
DEFAULT_PALETTE,
DEFAULT_MAP_PALETTE,
{
type: 'palette',
colors: ['#3742a0', '#129dc9', '#28c093', '#df3f3f', '#f48d54', '#fac372'],
darkColors: ['#5ba8f7', '#129dc9', '#28c093', '#df3f3f', '#f48d54', '#fac372'],
name: 'Rainbow',
},
Red: {
scale: ['#bd0026', '#fed976'],
},
Gray: {
scale: ['#28323f', '#d9e2ec'],
},
},
{ name: 'Plasma', type: 'scale', colors: ['#1d1489', '#f4bb4d'] },
{ name: 'GreenYellow', type: 'scale', colors: ['#103338', '#D1DA62'] },
{ name: 'Blue', type: 'scale', colors: ['#0E2836', '#55C4F9'] },
{ name: 'Red', type: 'scale', colors: ['#bd0026', '#fed976'] },
{ name: 'Gray', type: 'scale', colors: ['#28323f', '#d9e2ec'] },
],
fonts: {
body: { type: 'browser', name: 'inherit' },
display: { type: 'browser', name: 'inherit' },
},
};

const DEFAULT_PALETTE_ID = 'Rainbow'; // Unfortunately I didn't name this 'default' or make it null
const fallbackPalette = ['#3742a0', '#129dc9', '#28c093', '#df3f3f', '#f48d54', '#fac372'];
const fallbackPalette: Palette = {
type: 'palette',
colors: ['#3742a0', '#129dc9', '#28c093', '#df3f3f', '#f48d54', '#fac372'],
name: 'Rainbow',
};

export function colorTable(colorPaletteId: string, steps: number, theme: Theme, dark?: boolean): string[] {
// Default to brand theme if present, otherwise our default
const defaultPalette = theme.palettes.brand ?? theme.palettes.default;
const defaultPalette = theme.palettes?.[0];

const palette =
(colorPaletteId === DEFAULT_PALETTE_ID ? defaultPalette : theme.palettes[colorPaletteId]) ?? fallbackPalette;
(colorPaletteId === DEFAULT_PALETTE_ID
? defaultPalette
: theme.palettes?.find(({ name }) => name === colorPaletteId)) ?? fallbackPalette;

if ('scale' in palette) {
const scale = chroma.scale(palette.scale).mode('lch');
if (palette.type === 'scale') {
const scale = chroma.scale(palette.colors).mode('lch');
return scale.colors(steps);
} else if ('light' in palette) {
if (dark) {
return palette.dark ? palette.dark.slice(0, steps) : palette.light.slice(0, steps);
}
return palette.light.slice(0, steps);
} else if ('darkColors' in palette && palette.darkColors && dark) {
return palette.darkColors.slice(0, steps);
} else {
return palette.slice(0, steps);
return palette.colors.slice(0, steps);
}
}

export function getTheme(theme?: Theme) {
export function getTheme(theme?: Theme): Theme {
if (!theme) {
return defaultTheme;
}

const fullTheme = {
palettes: {
...defaultTheme.palettes,
...theme.palettes,
},
palettes: [...(theme.palettes ?? []), ...(defaultTheme.palettes ?? [])],
...(theme && 'fonts' in theme ? theme.fonts : defaultTheme.fonts),
};

Expand Down

0 comments on commit ff1a611

Please sign in to comment.