Skip to content

Commit 1e40d3e

Browse files
authored
feat: Theming - Inline svgs (#1651)
1 parent 21131fe commit 1e40d3e

106 files changed

Lines changed: 1409 additions & 665 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/* eslint-disable react/jsx-props-no-spreading */
2+
import React from 'react';
3+
import classnames from 'classnames';
4+
import { sampleSectionIdAndClasses } from './utils';
5+
6+
const tabs = ['Tab 1', 'Tab 2', 'Tab 3'];
7+
8+
function Tab({
9+
isActive,
10+
title,
11+
}: {
12+
isActive: boolean;
13+
title: string;
14+
}): JSX.Element {
15+
return (
16+
<li className={classnames('lm_tab', isActive && 'lm_active')}>
17+
<span className="lm_title_before" />
18+
<span className="lm_title">{title}</span>
19+
<span className="lm_close_tab" />
20+
</li>
21+
);
22+
}
23+
24+
export function GoldenLayout(): JSX.Element {
25+
return (
26+
<div {...sampleSectionIdAndClasses('golden-layout')}>
27+
<h2 className="ui-title">Golden Layout</h2>
28+
{[false, true].map(isMaximised => (
29+
<React.Fragment key={String(isMaximised)}>
30+
<h5>{isMaximised ? 'Minimized' : 'Maximised'}</h5>
31+
<div
32+
style={{ position: 'relative', border: 'none' }}
33+
className={isMaximised ? 'lm_maximised' : undefined}
34+
>
35+
<div className="lm_header">
36+
<ul className="lm_tabs">
37+
{tabs.map((tab, i) => (
38+
<Tab key={tab} isActive={i === 0} title={tab} />
39+
))}
40+
</ul>
41+
<ul className="lm_controls">
42+
<li className="lm_tabpreviousbutton" />
43+
<li className="lm_tabnextbutton" />
44+
<li className="lm_maximise" />
45+
<li className="lm_popout" />
46+
<li className="lm_tabdropdown" />
47+
<li className="lm_close" />
48+
</ul>
49+
</div>
50+
</div>
51+
</React.Fragment>
52+
))}
53+
</div>
54+
);
55+
}
56+
57+
export default GoldenLayout;

packages/code-studio/src/styleguide/Inputs.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,10 +304,11 @@ function Inputs(): React.ReactElement {
304304
validationError={!validateValue ? 'Value not set' : undefined}
305305
isModified={!!validateValue}
306306
id="validateInput1"
307-
labelText="Input Field"
307+
labelText={`Input Field${on ? ' (disabled)' : ''}`}
308308
hintText="Hint text"
309309
>
310310
<input
311+
disabled={on}
311312
type="text"
312313
className="form-control"
313314
aria-describedby="emailHelp"
@@ -320,9 +321,10 @@ function Inputs(): React.ReactElement {
320321
validateOption === 'Invalid' ? 'Invalid value' : undefined
321322
}
322323
id="validateLabelInput2"
323-
labelText="Dropdown"
324+
labelText={`Dropdown${on ? ' (disabled)' : ''}`}
324325
>
325326
<Select
327+
disabled={on}
326328
onChange={eventTargetValue =>
327329
setValidateOption(eventTargetValue)
328330
}

packages/code-studio/src/styleguide/StyleGuide.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import SpectrumComponents from './SpectrumComponents';
2828
import SamplesMenu, { SampleMenuCategory } from './SamplesMenu';
2929
import GotoTopButton from './GotoTopButton';
3030
import { HIDE_FROM_E2E_TESTS_CLASS } from './utils';
31+
import { GoldenLayout } from './GoldenLayout';
3132

3233
const stickyProps = {
3334
position: 'sticky',
@@ -85,6 +86,9 @@ function StyleGuide(): React.ReactElement {
8586
<Colors />
8687
<ThemeColors />
8788

89+
<SampleMenuCategory data-menu-category="Layout" />
90+
<GoldenLayout />
91+
8892
<SampleMenuCategory data-menu-category="Components" />
8993
<Buttons />
9094
<Progress />

packages/code-studio/src/styleguide/ThemeColors.module.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
.label {
1313
display: flex;
14-
align-items: end;
14+
align-items: flex-end;
1515
justify-content: space-between;
1616
gap: 4px;
1717
height: var(--swatch-height);

packages/code-studio/src/styleguide/ThemeColors.tsx

Lines changed: 15 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -10,78 +10,19 @@ import semanticGrid from '@deephaven/components/src/theme/theme-dark/theme-dark-
1010
import components from '@deephaven/components/src/theme/theme-dark/theme-dark-components.css?inline';
1111
import styles from './ThemeColors.module.scss';
1212
import { sampleSectionIdAndClasses } from './utils';
13-
14-
// Group names are extracted from var names via a regex capture group. Most of
15-
// them work pretty well, but some need to be remapped to a more appropriate
16-
// group.
17-
const reassignVarGroups: Record<string, string> = {
18-
'--dh-color-black': 'gray',
19-
'--dh-color-white': 'gray',
20-
// Semantic
21-
'--dh-color-visual-positive': 'Visual Status',
22-
'--dh-color-visual-negative': 'Visual Status',
23-
'--dh-color-visual-notice': 'Visual Status',
24-
'--dh-color-visual-info': 'Visual Status',
25-
// Editor
26-
'--dh-color-editor-bg': 'editor',
27-
'--dh-color-editor-fg': 'editor',
28-
'--dh-color-editor-context-menu-bg': 'menus',
29-
'--dh-color-editor-context-menu-fg': 'menus',
30-
'--dh-color-editor-menu-selection-bg': 'menus',
31-
// Grid
32-
'--dh-color-grid-bg': 'grid',
33-
'--dh-color-grid-number-positive': 'Data Types',
34-
'--dh-color-grid-number-negative': 'Data Types',
35-
'--dh-color-grid-number-zero': 'Data Types',
36-
'--dh-color-grid-date': 'Data Types',
37-
'--dh-color-grid-string-null': 'Data Types',
38-
};
39-
40-
// Mappings of variable groups to rename
41-
const renameGroups = {
42-
editor: {
43-
line: 'editor',
44-
comment: 'code',
45-
string: 'code',
46-
number: 'code',
47-
delimiter: 'code',
48-
identifier: 'code',
49-
keyword: 'code',
50-
operator: 'code',
51-
storage: 'code',
52-
predefined: 'code',
53-
selection: 'state',
54-
focus: 'state',
55-
},
56-
chart: {
57-
axis: 'Chart',
58-
bg: 'Chart',
59-
grid: 'Chart',
60-
plot: 'Chart',
61-
title: 'Chart',
62-
active: 'Data',
63-
trend: 'Data',
64-
area: 'Data',
65-
range: 'Data',
66-
line: 'Deprecated',
67-
},
68-
grid: { data: 'Data Bars', context: 'Context Menu' },
69-
semantic: {
70-
positive: 'status',
71-
negative: 'status',
72-
notice: 'status',
73-
info: 'status',
74-
well: 'wells',
75-
},
76-
};
13+
import {
14+
buildColorGroups,
15+
contrastColor,
16+
INVALID_COLOR_BORDER_STYLE,
17+
} from './colorUtils';
7718

7819
const swatchDataGroups = {
79-
'Theme Color Palette': buildColorGroups(palette, 1),
80-
'Semantic Colors': buildColorGroups(semantic, 1, renameGroups.semantic),
81-
'Chart Colors': buildColorGroups(chart, 2, renameGroups.chart),
82-
'Editor Colors': buildColorGroups(semanticEditor, 2, renameGroups.editor),
83-
'Grid Colors': buildColorGroups(semanticGrid, 2, renameGroups.grid),
84-
'Component Colors': buildColorGroups(components, 1),
20+
'Theme Color Palette': buildColorGroups('palette', palette, 1),
21+
'Semantic Colors': buildColorGroups('semantic', semantic, 1),
22+
'Chart Colors': buildColorGroups('chart', chart, 2),
23+
'Editor Colors': buildColorGroups('editor', semanticEditor, 2),
24+
'Grid Colors': buildColorGroups('grid', semanticGrid, 2),
25+
'Component Colors': buildColorGroups('component', components, 1),
8526
};
8627

8728
export function ThemeColors(): JSX.Element {
@@ -110,6 +51,10 @@ export function ThemeColors(): JSX.Element {
11051
className={styles.swatch}
11152
style={{
11253
backgroundColor: value,
54+
border:
55+
value === '' && name.length > 0
56+
? INVALID_COLOR_BORDER_STYLE
57+
: undefined,
11358
color: `var(--dh-color-${contrastColor(value)})`,
11459
}}
11560
>
@@ -137,94 +82,3 @@ export function ThemeColors(): JSX.Element {
13782
}
13883

13984
export default ThemeColors;
140-
141-
/** Return black or white contrast color */
142-
function contrastColor(color: string): 'black' | 'white' {
143-
const rgba = ColorUtils.parseRgba(ColorUtils.asRgbOrRgbaString(color) ?? '');
144-
if (rgba == null || rgba.a < 0.5) {
145-
return 'white';
146-
}
147-
148-
const { r, g, b } = rgba;
149-
const y = (299 * r + 587 * g + 114 * b) / 1000;
150-
return y >= 128 ? 'black' : 'white';
151-
}
152-
153-
/** Extract an array of { name, value } pairs for css variables in a given string */
154-
function extractColorVars(
155-
styleText: string
156-
): { name: string; value: string }[] {
157-
const computedStyle = getComputedStyle(document.documentElement);
158-
const varNames = styleText
159-
.split(/[\n;]/g)
160-
// Non-minified css will have leading 2 spaces in front of each css variable
161-
// declaration. Minified has no prefix except for the first line which will
162-
// have ':root{' prefix.
163-
.map(line => /^(?:\s{2}|:root\{)?(--dh-color-(?:[^:]+))/.exec(line)?.[1])
164-
.filter((match): match is string => Boolean(match));
165-
166-
return varNames
167-
.map(varName => {
168-
const value = computedStyle.getPropertyValue(varName);
169-
170-
// Chart colorway consists of multiple colors, so split into separate
171-
// swatches for illustration. Note that this assumes the colors are hsl
172-
// values. We'll need to make this more robust if we ever change the
173-
// default themes to use non-hsl.
174-
if (varName === '--dh-color-chart-colorway') {
175-
const colorwayColors = value
176-
.split('hsl')
177-
.filter(Boolean)
178-
.map(v => `hsl${v.trim()}`);
179-
180-
return colorwayColors.map((varExp, i) => ({
181-
name: `${varName}-${i}`,
182-
value: varExp,
183-
}));
184-
}
185-
186-
return {
187-
name: varName,
188-
value,
189-
};
190-
})
191-
.flat();
192-
}
193-
194-
/** Group color data based on capture group value */
195-
function buildColorGroups(
196-
styleText: string,
197-
captureGroupI: number,
198-
groupRemap: Record<string, string> = {}
199-
): Record<string, { name: string; value: string }[]> {
200-
const swatchData = extractColorVars(styleText);
201-
202-
const groupData = swatchData.reduce(
203-
(acc, { name, value }) => {
204-
const match = /^--dh-color-([^-]+)(?:-([^-]+))?/.exec(name);
205-
let group =
206-
reassignVarGroups[name] ??
207-
match?.[captureGroupI] ??
208-
match?.[1] ??
209-
'???';
210-
211-
group = groupRemap[group] ?? group;
212-
213-
if (acc[group] == null) {
214-
acc[group] = [];
215-
}
216-
217-
// Add a spacer for black / white
218-
if (name === '--dh-color-black') {
219-
acc[group].push({ name: '', value: '' });
220-
}
221-
222-
acc[group].push({ name, value });
223-
224-
return acc;
225-
},
226-
{} as Record<string, { name: string; value: string }[]>
227-
);
228-
229-
return groupData;
230-
}

0 commit comments

Comments
 (0)