@titan-design/react-ui 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/bodymap.js +129 -76
- package/dist/bodymap.js.map +1 -1
- package/dist/bodymap.mjs +129 -76
- package/dist/bodymap.mjs.map +1 -1
- package/dist/index.d.mts +117 -26
- package/dist/index.d.ts +117 -26
- package/dist/index.js +677 -450
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +673 -451
- package/dist/index.mjs.map +1 -1
- package/dist/{pages-_3Ajpiqu.d.ts → pages-CsjsUn0G.d.ts} +30 -13
- package/dist/{pages-CpW3OB3g.d.mts → pages-ZbT_pD_U.d.mts} +30 -13
- package/dist/pages.d.mts +1 -1
- package/dist/pages.d.ts +1 -1
- package/dist/pages.js +676 -701
- package/dist/pages.js.map +1 -1
- package/dist/pages.mjs +676 -701
- package/dist/pages.mjs.map +1 -1
- package/dist/theme/index.d.mts +31 -7
- package/dist/theme/index.d.ts +31 -7
- package/dist/theme/index.js +84 -20
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +83 -21
- package/dist/theme/index.mjs.map +1 -1
- package/dist/theme/tokens-css.js +84 -20
- package/dist/theme/tokens-css.js.map +1 -1
- package/dist/theme/tokens-css.mjs +84 -20
- package/dist/theme/tokens-css.mjs.map +1 -1
- package/dist/theme/tokens.d.mts +56 -7
- package/dist/theme/tokens.d.ts +56 -7
- package/dist/theme/tokens.js +72 -20
- package/dist/theme/tokens.js.map +1 -1
- package/dist/theme/tokens.mjs +71 -21
- package/dist/theme/tokens.mjs.map +1 -1
- package/docs/render-testing-pattern.md +130 -0
- package/package.json +1 -1
- package/src/arch/Architecture.stories.tsx +3 -1
- package/src/arch/arch-graph.json +74 -72
- package/src/components/custom/ActiveWork/InitiativeBrief.tsx +2 -1
- package/src/components/custom/CircularTimer/CircularTimer.stories.tsx +8 -3
- package/src/components/custom/EmptyState/EmptyState.stories.tsx +1 -1
- package/src/components/custom/Gauge/Gauge.stories.tsx +4 -1
- package/src/components/custom/Gauge/Gauge.tsx +3 -1
- package/src/components/custom/Scatter/Scatter.stories.tsx +10 -7
- package/src/components/custom/Scatter/Scatter.tsx +6 -4
- package/src/components/custom/Sidebar/Sidebar.stories.tsx +1 -1
- package/src/components/custom/Table/Table.stories.tsx +1 -1
- package/src/components/custom/Table/Table.tsx +2 -2
- package/src/components/custom/Treemap/Treemap.stories.tsx +13 -10
- package/src/components/custom/Treemap/Treemap.tsx +4 -1
- package/src/components/custom/Workout/ActiveWorkoutPage.stories.tsx +2 -1
- package/src/components/custom/Workout/BaseBadge.stories.tsx +11 -7
- package/src/components/custom/Workout/BaseBadge.tsx +3 -2
- package/src/components/custom/Workout/BodyMap.tsx +5 -3
- package/src/components/custom/Workout/BodyMapDetailPanel.stories.tsx +13 -3
- package/src/components/custom/Workout/BodyMapDetailPanel.tsx +5 -3
- package/src/components/custom/Workout/CapacityBandChart.stories.tsx +2 -1
- package/src/components/custom/Workout/CapacityBandChart.tsx +5 -3
- package/src/components/custom/Workout/DeviationBar.test.tsx +5 -2
- package/src/components/custom/Workout/DeviationBar.tsx +5 -2
- package/src/components/custom/Workout/DualVelocityStrip.stories.tsx +7 -6
- package/src/components/custom/Workout/DualVelocityStrip.test.tsx +29 -16
- package/src/components/custom/Workout/ExerciseCard.stories.tsx +8 -8
- package/src/components/custom/Workout/ExerciseCard.test.tsx +39 -19
- package/src/components/custom/Workout/ExerciseCard.tsx +92 -167
- package/src/components/custom/Workout/ExerciseCardHeading.stories.tsx +89 -6
- package/src/components/custom/Workout/ExerciseCardHeading.test.tsx +189 -1
- package/src/components/custom/Workout/ExerciseCardHeading.tsx +167 -18
- package/src/components/custom/Workout/ExerciseDetailPage.tsx +3 -2
- package/src/components/custom/Workout/ExerciseHeading.tsx +192 -47
- package/src/components/custom/Workout/ExerciseIndicator.stories.tsx +6 -5
- package/src/components/custom/Workout/InputBar.tsx +4 -2
- package/src/components/custom/Workout/IntensityBar.tsx +4 -1
- package/src/components/custom/Workout/MesoCard.tsx +2 -1
- package/src/components/custom/Workout/MesoStatusCard.tsx +11 -10
- package/src/components/custom/Workout/PlaceholderStrip.stories.tsx +8 -3
- package/src/components/custom/Workout/PrHistoryModal.stories.tsx +12 -2
- package/src/components/custom/Workout/README.md +58 -12
- package/src/components/custom/Workout/ReadinessCheck.tsx +4 -2
- package/src/components/custom/Workout/RestTimer.stories.tsx +13 -2
- package/src/components/custom/Workout/RestTimer.tsx +4 -2
- package/src/components/custom/Workout/SegmentedBar.stories.tsx +16 -12
- package/src/components/custom/Workout/SegmentedBar.tsx +4 -3
- package/src/components/custom/Workout/SetStrip.stories.tsx +3 -2
- package/src/components/custom/Workout/SetsRepsLoad.tsx +23 -9
- package/src/components/custom/Workout/Sparkline.stories.tsx +13 -10
- package/src/components/custom/Workout/StrengthTrendChart.stories.tsx +2 -1
- package/src/components/custom/Workout/StrengthTrendChart.tsx +8 -6
- package/src/components/custom/Workout/TempoDisplay.stories.tsx +4 -3
- package/src/components/custom/Workout/TempoDisplay.tsx +2 -0
- package/src/components/custom/Workout/VelocityStrip.dual.stories.tsx +3 -2
- package/src/components/custom/Workout/VelocityStrip.expanded.stories.tsx +1 -1
- package/src/components/custom/Workout/VelocityStrip.hero.stories.tsx +40 -0
- package/src/components/custom/Workout/VelocityStrip.test.tsx +48 -6
- package/src/components/custom/Workout/VelocityStrip.tsx +23 -14
- package/src/components/custom/Workout/ZoneTrack.stories.tsx +3 -1
- package/src/components/custom/Workout/exerciseRowState.ts +29 -0
- package/src/components/custom/Workout/index.ts +12 -2
- package/src/components/custom/Workout/metricText.stories.tsx +9 -8
- package/src/components/custom/Workout/metricText.tsx +4 -2
- package/src/components/custom/Workout/setHeadingKit.tsx +12 -10
- package/src/components/custom/Workout/velocity-story-kit.tsx +2 -2
- package/src/components/custom/charts/README.md +5 -0
- package/src/components/custom/charts/SetBarChart.test.tsx +16 -0
- package/src/components/custom/charts/SetBarChart.tsx +14 -5
- package/src/components/custom/charts/flatBarGeometry.test.ts +41 -0
- package/src/components/custom/charts/flatBarGeometry.ts +32 -0
- package/src/components/custom/stepper/Stepper.tsx +8 -6
- package/src/components/ui/alert/Alert.stories.tsx +14 -4
- package/src/components/ui/alert/Alert.tsx +24 -3
- package/src/components/ui/button/Button.tsx +12 -12
- package/src/components/ui/checkbox/Checkbox.tsx +2 -2
- package/src/components/ui/data-row/DataRow.stories.tsx +6 -2
- package/src/components/ui/drawer/Drawer.tsx +4 -1
- package/src/components/ui/icon-box/IconBox.tsx +8 -6
- package/src/components/ui/indicator/Indicator.stories.tsx +4 -3
- package/src/components/ui/list-item/ListItem.stories.tsx +7 -4
- package/src/components/ui/modal/Modal.tsx +2 -0
- package/src/components/ui/pill/Pill.stories.tsx +53 -0
- package/src/components/ui/pill/Pill.tsx +10 -6
- package/src/components/ui/popover/Popover.stories.tsx +1 -1
- package/src/components/ui/progress/Progress.tsx +9 -6
- package/src/components/ui/radio/Radio.tsx +1 -1
- package/src/components/ui/section/Section.stories.tsx +10 -10
- package/src/components/ui/select/Select.tsx +2 -1
- package/src/components/ui/spinner/Spinner.tsx +3 -1
- package/src/components/ui/stack/Stack.stories.tsx +7 -7
- package/src/components/ui/surface/Surface.stories.tsx +75 -28
- package/src/components/ui/switch/Switch.tsx +1 -1
- package/src/components/ui/tabs/Tabs.tsx +4 -2
- package/src/components/ui/toast/Toast.tsx +6 -4
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +13 -6
- package/src/stories/PresetShowcase.stories.tsx +1 -1
- package/src/test/no-raw-color.test.ts +39 -0
- package/src/theme/Alpha.stories.tsx +103 -0
- package/src/theme/ProposedTokensVW82.stories.tsx +414 -0
- package/src/theme/config.ts +12 -0
- package/src/theme/global.css +15 -3
- package/src/theme/subtle-tone-weight.test.ts +163 -0
- package/src/theme/tailwind-var-opacity.test.ts +163 -0
- package/src/theme/tokens/primitives.ts +33 -0
- package/src/theme/tokens/semantic-hex-guard.test.ts +322 -0
- package/src/theme/tokens/semantic.ts +56 -20
- package/src/utils/colors.alpha-adoption.test.ts +408 -0
- package/tailwind.config.js +50 -9
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { RuleTester } from 'eslint'
|
|
2
|
+
import rule from '../../eslint-rules/no-raw-color'
|
|
3
|
+
|
|
4
|
+
const ruleTester = new RuleTester({
|
|
5
|
+
languageOptions: {
|
|
6
|
+
ecmaVersion: 2022,
|
|
7
|
+
sourceType: 'module',
|
|
8
|
+
parserOptions: { ecmaFeatures: { jsx: true } },
|
|
9
|
+
},
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
describe('no-raw-color', () => {
|
|
13
|
+
it('skips false positives while still flagging real raw colour', () => {
|
|
14
|
+
ruleTester.run('no-raw-color', rule as never, {
|
|
15
|
+
valid: [
|
|
16
|
+
// (a) enum-typed prop value: a bare colour word passed as color/variant/tone.
|
|
17
|
+
{ code: '<Spinner color="white" />' },
|
|
18
|
+
// (a) the same enum's members listed in a Storybook argTypes options array.
|
|
19
|
+
{
|
|
20
|
+
code: "const meta = { argTypes: { color: { control: 'select', options: ['primary', 'white'] } } }",
|
|
21
|
+
},
|
|
22
|
+
// (b) { value, label } demo data reusing colour words as IDs.
|
|
23
|
+
{ code: "const colorOptions = [{ value: 'red', label: 'Red' }]" },
|
|
24
|
+
// (c) documentation text in a <Text> element's children.
|
|
25
|
+
{ code: '<Text>{`background-color: #3C3C3C;`}</Text>' },
|
|
26
|
+
],
|
|
27
|
+
invalid: [
|
|
28
|
+
// Positive control: a real raw hex in a style prop must still be flagged,
|
|
29
|
+
// including on a <Text> element — only its *children* are exempt.
|
|
30
|
+
{
|
|
31
|
+
code: "<Text style={{ backgroundColor: '#123456' }} />",
|
|
32
|
+
errors: [{ messageId: 'hex' }],
|
|
33
|
+
},
|
|
34
|
+
// Positive control: a bare colour word outside any exempt shape is still named.
|
|
35
|
+
{ code: "const bg = 'white'", errors: [{ messageId: 'named' }] },
|
|
36
|
+
],
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
})
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import { View, Text } from 'react-native'
|
|
3
|
+
import { alpha } from '../utils/colors'
|
|
4
|
+
import { getSemanticColors } from './tokens/semantic'
|
|
5
|
+
import { primitiveColors } from './tokens/primitives'
|
|
6
|
+
import { SectionIntro, SectionTitle, SWATCH_BORDER } from './color-story-kit'
|
|
7
|
+
|
|
8
|
+
const t = getSemanticColors('dark')
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Foundations/Color/Alpha — deriving a translucent colour from a token instead
|
|
12
|
+
* of hardcoding an `rgba(...)` triple.
|
|
13
|
+
*
|
|
14
|
+
* `alpha(color, opacity)` (`packages/ui/src/utils/colors.ts`) takes a RESOLVED
|
|
15
|
+
* colour — a hex string or an `rgb()`/`rgba()` string, e.g. a semantic token's
|
|
16
|
+
* value or a primitive — and returns it as `rgba(r, g, b, opacity)`. It does
|
|
17
|
+
* NOT take a token name: `alpha('brand-primary', 0.1)` would try to parse the
|
|
18
|
+
* literal string `'brand-primary'` as a colour and fail. Resolve the token
|
|
19
|
+
* first (`t['brand-primary']`, `primitiveColors.white`, …), then wrap it.
|
|
20
|
+
*
|
|
21
|
+
* The payoff over a hand-picked `rgba(255, 121, 0, 0.1)`: when a ramp gets
|
|
22
|
+
* re-spaced or a semantic mapping moves, every `alpha()` call built on that
|
|
23
|
+
* token moves with it. A literal triple silently drifts from the token it was
|
|
24
|
+
* copied from and stays wrong until someone notices — the failure mode VW-78
|
|
25
|
+
* was opened to burn down (see `eslint-rules/raw-color-baseline.json`,
|
|
26
|
+
* enforced by `no-raw-color`'s `functional` rule).
|
|
27
|
+
*/
|
|
28
|
+
const meta: Meta = {
|
|
29
|
+
title: 'Foundations/Color/Alpha',
|
|
30
|
+
tags: ['autodocs'],
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default meta
|
|
34
|
+
|
|
35
|
+
const EXAMPLES = [
|
|
36
|
+
{ name: 'brand-primary @ 0.12', value: alpha(t['brand-primary'], 0.12) },
|
|
37
|
+
{ name: 'status-success @ 0.15', value: alpha(t['status-success'], 0.15) },
|
|
38
|
+
{ name: 'status-warning @ 0.25', value: alpha(t['status-warning'], 0.25) },
|
|
39
|
+
{ name: 'status-error @ 0.3', value: alpha(t['status-error'], 0.3) },
|
|
40
|
+
{ name: 'primitiveColors.white @ 0.08', value: alpha(primitiveColors.white, 0.08) },
|
|
41
|
+
] as const
|
|
42
|
+
|
|
43
|
+
function AlphaSwatch({ name, value }: { name: string; value: string }) {
|
|
44
|
+
return (
|
|
45
|
+
<View style={{ alignItems: 'center', width: 96 }}>
|
|
46
|
+
<View
|
|
47
|
+
style={{
|
|
48
|
+
width: 96,
|
|
49
|
+
height: 64,
|
|
50
|
+
borderRadius: 8,
|
|
51
|
+
backgroundColor: t['surface-elevated'],
|
|
52
|
+
borderWidth: 1,
|
|
53
|
+
borderColor: SWATCH_BORDER,
|
|
54
|
+
overflow: 'hidden',
|
|
55
|
+
}}
|
|
56
|
+
>
|
|
57
|
+
<View style={{ flex: 1, backgroundColor: value }} />
|
|
58
|
+
</View>
|
|
59
|
+
<Text className="text-text-secondary text-xs mt-1" style={{ textAlign: 'center' }}>
|
|
60
|
+
{name}
|
|
61
|
+
</Text>
|
|
62
|
+
<Text className="text-text-tertiary" style={{ fontSize: 9, marginTop: 1 }}>
|
|
63
|
+
{value}
|
|
64
|
+
</Text>
|
|
65
|
+
</View>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const Default: StoryObj = {
|
|
70
|
+
render: () => (
|
|
71
|
+
<View style={{ padding: 24 }}>
|
|
72
|
+
<Text className="text-2xl font-bold text-text-primary mb-2">Alpha</Text>
|
|
73
|
+
<SectionIntro>
|
|
74
|
+
`alpha(color, opacity)` derives a translucent colour from a RESOLVED token or primitive
|
|
75
|
+
instead of a hand-picked `rgba(...)` triple, so the wash tracks the token it came from. Each
|
|
76
|
+
swatch below is rendered over the elevated surface plane so the translucency is visible.
|
|
77
|
+
</SectionIntro>
|
|
78
|
+
|
|
79
|
+
<SectionTitle>Usage</SectionTitle>
|
|
80
|
+
<View
|
|
81
|
+
style={{
|
|
82
|
+
backgroundColor: t['surface-raised'],
|
|
83
|
+
borderRadius: 8,
|
|
84
|
+
padding: 12,
|
|
85
|
+
marginBottom: 20,
|
|
86
|
+
}}
|
|
87
|
+
>
|
|
88
|
+
<Text className="text-text-secondary" style={{ fontFamily: 'monospace', fontSize: 12 }}>
|
|
89
|
+
{"import { alpha } from '@/utils/colors'\n\n"}
|
|
90
|
+
{"const t = getSemanticColors('dark')\n"}
|
|
91
|
+
{"const wash = alpha(t['brand-primary'], 0.12)"}
|
|
92
|
+
</Text>
|
|
93
|
+
</View>
|
|
94
|
+
|
|
95
|
+
<SectionTitle>Examples</SectionTitle>
|
|
96
|
+
<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 16 }}>
|
|
97
|
+
{EXAMPLES.map((example) => (
|
|
98
|
+
<AlphaSwatch key={example.name} {...example} />
|
|
99
|
+
))}
|
|
100
|
+
</View>
|
|
101
|
+
</View>
|
|
102
|
+
),
|
|
103
|
+
}
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
2
|
+
import { View, Text } from 'react-native'
|
|
3
|
+
import { alpha } from '../utils/colors'
|
|
4
|
+
import { getSemanticColors } from './tokens/semantic'
|
|
5
|
+
import { greyRamp, primitiveColors, primitiveRamps } from './tokens/primitives'
|
|
6
|
+
import { SectionIntro, SectionTitle, SWATCH_BORDER } from './color-story-kit'
|
|
7
|
+
import { ToolbarButton } from '../components/ui/toolbar-button'
|
|
8
|
+
import { Treemap } from '../components/custom/Treemap'
|
|
9
|
+
|
|
10
|
+
const t = getSemanticColors('dark')
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Foundations/Color/Proposed VW-82 tokens — a DECISION story, not documentation.
|
|
14
|
+
*
|
|
15
|
+
* VW-82 (#200) migrated component source off raw colours. Every literal that had
|
|
16
|
+
* an exact token was swapped; the ones with no token were deliberately left raw
|
|
17
|
+
* and proposed rather than invented, because adding a token is a design call.
|
|
18
|
+
* This story renders those candidates in the context they would actually ship
|
|
19
|
+
* in, so the proposal can be accepted or rejected by eye instead of by hex.
|
|
20
|
+
*
|
|
21
|
+
* WHY THE SCRIMS ARE TOKENS AND NOT `bg-black/50`: Tailwind v3 cannot apply an
|
|
22
|
+
* opacity modifier to a `var()` colour — it fails to parse the value and emits
|
|
23
|
+
* NO rule at all. So a translucent role has to ship as its own rgba token, which
|
|
24
|
+
* is exactly what `hairline-*` already does (`rgba(255, 255, 255, 0.15)`, not
|
|
25
|
+
* `white/15`). The four scrims below are rendered through
|
|
26
|
+
* `alpha(primitiveColors.black, …)`, which is the value each token would carry.
|
|
27
|
+
*
|
|
28
|
+
* The two candidates that have NO token and no primitive — `on-control-idle`
|
|
29
|
+
* (#D1D1D1) and `on-data-strong` (#0B0B0B) — cannot be written as literals here:
|
|
30
|
+
* `no-raw-color` allots this file zero, and funding a new allowance to document
|
|
31
|
+
* a proposal would push the ratchet the wrong way. They are instead shown by
|
|
32
|
+
* rendering the REAL components that carry them today, side by side with the
|
|
33
|
+
* existing tokens that might replace them. That is stronger evidence anyway.
|
|
34
|
+
*/
|
|
35
|
+
const meta: Meta<ProposedTokensArgs> = {
|
|
36
|
+
title: 'Foundations/Color/Proposed VW-82 tokens',
|
|
37
|
+
tags: ['autodocs'],
|
|
38
|
+
argTypes: {
|
|
39
|
+
showScrims: {
|
|
40
|
+
control: 'boolean',
|
|
41
|
+
description: 'Lift all four scrims off the backdrop, to judge their impact.',
|
|
42
|
+
},
|
|
43
|
+
backdrop: {
|
|
44
|
+
control: 'radio',
|
|
45
|
+
options: ['pattern', 'gradient', 'surface'],
|
|
46
|
+
description:
|
|
47
|
+
'What the scrims sit on. `pattern` is the honest worst case — a scrim over a flat dark surface always looks fine.',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
args: { showScrims: true, backdrop: 'pattern' },
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default meta
|
|
54
|
+
|
|
55
|
+
interface ProposedTokensArgs {
|
|
56
|
+
showScrims: boolean
|
|
57
|
+
backdrop: 'pattern' | 'gradient' | 'surface'
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// 1 — scrims
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The four candidates, as the value each token would carry. Derived through
|
|
66
|
+
* `alpha()` from the black primitive rather than written as rgba triples, so
|
|
67
|
+
* they track the primitive the way the real token would.
|
|
68
|
+
*/
|
|
69
|
+
const SCRIMS = [
|
|
70
|
+
{
|
|
71
|
+
name: 'scrim-press',
|
|
72
|
+
opacity: 0.1,
|
|
73
|
+
usedBy: 'Alert close button — web:hover',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'scrim-press-strong',
|
|
77
|
+
opacity: 0.2,
|
|
78
|
+
usedBy: 'Alert close button — active',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'scrim-subtle',
|
|
82
|
+
opacity: 0.3,
|
|
83
|
+
usedBy: 'Modal backdrop (blurred), Select filled fill',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'scrim-default',
|
|
87
|
+
opacity: 0.5,
|
|
88
|
+
usedBy: 'Modal backdrop, Drawer overlay',
|
|
89
|
+
},
|
|
90
|
+
] as const
|
|
91
|
+
|
|
92
|
+
const CHECKER_LIGHT = greyRamp[50]
|
|
93
|
+
const CHECKER_DARK = greyRamp[950]
|
|
94
|
+
const CHECKER_STEP = 20
|
|
95
|
+
const PANEL_W = 196
|
|
96
|
+
const PANEL_H = 140
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* A deliberately hostile backdrop. A scrim over a flat dark plane reads as
|
|
100
|
+
* "fine" no matter what its opacity is; the only way to judge one is to put
|
|
101
|
+
* something with real tonal range under it.
|
|
102
|
+
*/
|
|
103
|
+
function Checkerboard({ rows, columns }: { rows: number; columns: number }) {
|
|
104
|
+
return (
|
|
105
|
+
<View style={{ position: 'absolute', top: 0, right: 0, bottom: 0, left: 0 }}>
|
|
106
|
+
{Array.from({ length: rows }, (_, row) => (
|
|
107
|
+
<View key={row} style={{ flexDirection: 'row' }}>
|
|
108
|
+
{Array.from({ length: columns }, (_, column) => (
|
|
109
|
+
<View
|
|
110
|
+
key={column}
|
|
111
|
+
style={{
|
|
112
|
+
width: CHECKER_STEP,
|
|
113
|
+
height: CHECKER_STEP,
|
|
114
|
+
backgroundColor: (row + column) % 2 === 0 ? CHECKER_LIGHT : CHECKER_DARK,
|
|
115
|
+
}}
|
|
116
|
+
/>
|
|
117
|
+
))}
|
|
118
|
+
</View>
|
|
119
|
+
))}
|
|
120
|
+
</View>
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Stand-in for the photographic mid-tones a real app backdrop has. */
|
|
125
|
+
function GradientWash() {
|
|
126
|
+
return (
|
|
127
|
+
<View
|
|
128
|
+
style={{
|
|
129
|
+
position: 'absolute',
|
|
130
|
+
top: 0,
|
|
131
|
+
right: 0,
|
|
132
|
+
bottom: 0,
|
|
133
|
+
left: 0,
|
|
134
|
+
// react-native-web renders backgroundImage at runtime (see DeviationBar).
|
|
135
|
+
backgroundImage: `linear-gradient(135deg, ${primitiveRamps.blue[300]} 0%, ${primitiveRamps.magenta[300]} 38%, ${primitiveRamps.amber[200]} 72%, ${greyRamp[950]} 100%)`,
|
|
136
|
+
}}
|
|
137
|
+
/>
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Cards + copy on top of the backdrop, so the scrim has content to obscure. */
|
|
142
|
+
function BackdropContent() {
|
|
143
|
+
return (
|
|
144
|
+
<View style={{ flexDirection: 'row', gap: 6, padding: 10 }}>
|
|
145
|
+
{[primitiveRamps.orange[400], primitiveRamps.green[300], primitiveRamps.blue[300]].map(
|
|
146
|
+
(fill) => (
|
|
147
|
+
<View
|
|
148
|
+
key={fill}
|
|
149
|
+
style={{
|
|
150
|
+
width: 56,
|
|
151
|
+
height: 48,
|
|
152
|
+
borderRadius: 6,
|
|
153
|
+
backgroundColor: fill,
|
|
154
|
+
padding: 5,
|
|
155
|
+
}}
|
|
156
|
+
>
|
|
157
|
+
<Text style={{ color: greyRamp[975], fontSize: 10, fontWeight: '700' }}>Card</Text>
|
|
158
|
+
</View>
|
|
159
|
+
)
|
|
160
|
+
)}
|
|
161
|
+
</View>
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function ScrimPanel({ showScrims, backdrop }: ProposedTokensArgs) {
|
|
166
|
+
return (
|
|
167
|
+
<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 14 }}>
|
|
168
|
+
{SCRIMS.map((scrim) => (
|
|
169
|
+
<View key={scrim.name} style={{ width: PANEL_W }}>
|
|
170
|
+
<View
|
|
171
|
+
style={{
|
|
172
|
+
height: PANEL_H,
|
|
173
|
+
borderRadius: 8,
|
|
174
|
+
overflow: 'hidden',
|
|
175
|
+
borderWidth: 1,
|
|
176
|
+
borderColor: SWATCH_BORDER,
|
|
177
|
+
backgroundColor: t['surface-base'],
|
|
178
|
+
}}
|
|
179
|
+
>
|
|
180
|
+
{backdrop === 'pattern' && (
|
|
181
|
+
<Checkerboard
|
|
182
|
+
rows={Math.ceil(PANEL_H / CHECKER_STEP)}
|
|
183
|
+
columns={Math.ceil(PANEL_W / CHECKER_STEP)}
|
|
184
|
+
/>
|
|
185
|
+
)}
|
|
186
|
+
{backdrop === 'gradient' && <GradientWash />}
|
|
187
|
+
<BackdropContent />
|
|
188
|
+
{showScrims && (
|
|
189
|
+
<View
|
|
190
|
+
style={{
|
|
191
|
+
position: 'absolute',
|
|
192
|
+
top: 0,
|
|
193
|
+
right: 0,
|
|
194
|
+
bottom: 0,
|
|
195
|
+
left: 0,
|
|
196
|
+
backgroundColor: alpha(primitiveColors.black, scrim.opacity),
|
|
197
|
+
alignItems: 'center',
|
|
198
|
+
justifyContent: 'center',
|
|
199
|
+
}}
|
|
200
|
+
>
|
|
201
|
+
<Text style={{ color: primitiveColors.white, fontSize: 12, fontWeight: '700' }}>
|
|
202
|
+
{scrim.name}
|
|
203
|
+
</Text>
|
|
204
|
+
</View>
|
|
205
|
+
)}
|
|
206
|
+
</View>
|
|
207
|
+
<Text className="text-text-primary text-xs font-semibold mt-2">{scrim.name}</Text>
|
|
208
|
+
<Text className="text-text-tertiary" style={{ fontSize: 10 }}>
|
|
209
|
+
{alpha(primitiveColors.black, scrim.opacity)}
|
|
210
|
+
</Text>
|
|
211
|
+
<Text className="text-text-secondary" style={{ fontSize: 10, marginTop: 2 }}>
|
|
212
|
+
{scrim.usedBy}
|
|
213
|
+
</Text>
|
|
214
|
+
</View>
|
|
215
|
+
))}
|
|
216
|
+
</View>
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// ---------------------------------------------------------------------------
|
|
221
|
+
// 2 — on-control
|
|
222
|
+
// ---------------------------------------------------------------------------
|
|
223
|
+
|
|
224
|
+
const TOOLBAR_FACE = greyRamp[800]
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* A toolbar-button face rendered with a chosen label colour, matching the real
|
|
228
|
+
* `ToolbarButton` geometry so the comparison beside it is like-for-like.
|
|
229
|
+
*/
|
|
230
|
+
function LabelChip({ label, color, caption }: { label: string; color: string; caption: string }) {
|
|
231
|
+
return (
|
|
232
|
+
<View style={{ alignItems: 'center', width: 116 }}>
|
|
233
|
+
<View
|
|
234
|
+
style={{
|
|
235
|
+
backgroundColor: TOOLBAR_FACE,
|
|
236
|
+
borderRadius: 4,
|
|
237
|
+
paddingHorizontal: 10,
|
|
238
|
+
paddingVertical: 4,
|
|
239
|
+
minHeight: 30,
|
|
240
|
+
justifyContent: 'center',
|
|
241
|
+
}}
|
|
242
|
+
>
|
|
243
|
+
<Text style={{ color, fontSize: 14, fontWeight: '700' }}>{label}</Text>
|
|
244
|
+
</View>
|
|
245
|
+
<Text className="text-text-secondary" style={{ fontSize: 10, marginTop: 4 }}>
|
|
246
|
+
{caption}
|
|
247
|
+
</Text>
|
|
248
|
+
<Text className="text-text-tertiary" style={{ fontSize: 9 }}>
|
|
249
|
+
{color.toUpperCase()}
|
|
250
|
+
</Text>
|
|
251
|
+
</View>
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function OnControlPanel() {
|
|
256
|
+
return (
|
|
257
|
+
<View className="bg-surface-elevated" style={{ borderRadius: 8, padding: 16 }}>
|
|
258
|
+
<Text className="text-text-secondary text-xs mb-3">
|
|
259
|
+
Left pair: the LIVE ToolbarButton, which is what the proposal is about. Right: the existing
|
|
260
|
+
tokens, drawn on the same face at the same size — does one of them already do the job?
|
|
261
|
+
</Text>
|
|
262
|
+
<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 14, alignItems: 'flex-start' }}>
|
|
263
|
+
<View style={{ alignItems: 'center', width: 116 }}>
|
|
264
|
+
<ToolbarButton label="Idle" isActive={false} variant="raised" />
|
|
265
|
+
<Text className="text-text-secondary" style={{ fontSize: 10, marginTop: 4 }}>
|
|
266
|
+
live · on-control-idle
|
|
267
|
+
</Text>
|
|
268
|
+
<Text className="text-text-tertiary" style={{ fontSize: 9 }}>
|
|
269
|
+
#D1D1D1
|
|
270
|
+
</Text>
|
|
271
|
+
</View>
|
|
272
|
+
<View style={{ alignItems: 'center', width: 116 }}>
|
|
273
|
+
<ToolbarButton label="Active" isActive variant="raised" />
|
|
274
|
+
<Text className="text-text-secondary" style={{ fontSize: 10, marginTop: 4 }}>
|
|
275
|
+
live · on-control-active
|
|
276
|
+
</Text>
|
|
277
|
+
<Text className="text-text-tertiary" style={{ fontSize: 9 }}>
|
|
278
|
+
#FFFFFF
|
|
279
|
+
</Text>
|
|
280
|
+
</View>
|
|
281
|
+
<LabelChip label="Idle" color={greyRamp[200]} caption="greyRamp[200]" />
|
|
282
|
+
<LabelChip label="Idle" color={t['text-secondary']} caption="text-secondary" />
|
|
283
|
+
<LabelChip label="Idle" color={t['text-primary']} caption="text-primary" />
|
|
284
|
+
<LabelChip label="Active" color={primitiveColors.white} caption="primitiveColors.white" />
|
|
285
|
+
</View>
|
|
286
|
+
<Text className="text-text-tertiary text-xs mt-3">
|
|
287
|
+
`on-control-active` is exactly `primitiveColors.white`, so the only real question is whether
|
|
288
|
+
it deserves a NAME — the toolbar face is a grey plane, not a brand fill, so borrowing
|
|
289
|
+
`on-brand-primary` for it would be the wrong role at the right value.
|
|
290
|
+
</Text>
|
|
291
|
+
</View>
|
|
292
|
+
)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// ---------------------------------------------------------------------------
|
|
296
|
+
// 3 — on-data-strong
|
|
297
|
+
// ---------------------------------------------------------------------------
|
|
298
|
+
|
|
299
|
+
const LIGHT_TILES = [
|
|
300
|
+
{ id: 'chest', value: 34, color: primitiveRamps.amber[200], label: 'Chest' },
|
|
301
|
+
{ id: 'back', value: 28, color: primitiveRamps.green[200], label: 'Back' },
|
|
302
|
+
{ id: 'quads', value: 21, color: primitiveRamps.blue[200], label: 'Quads' },
|
|
303
|
+
{ id: 'delts', value: 14, color: primitiveRamps.orange[200], label: 'Delts' },
|
|
304
|
+
{ id: 'arms', value: 9, color: primitiveRamps.magenta[200], label: 'Arms' },
|
|
305
|
+
]
|
|
306
|
+
|
|
307
|
+
function TileRow({ color, caption }: { color: string; caption: string }) {
|
|
308
|
+
return (
|
|
309
|
+
<View>
|
|
310
|
+
<View style={{ flexDirection: 'row', gap: 2 }}>
|
|
311
|
+
{LIGHT_TILES.map((tile) => (
|
|
312
|
+
<View
|
|
313
|
+
key={tile.id}
|
|
314
|
+
style={{
|
|
315
|
+
width: 62,
|
|
316
|
+
height: 44,
|
|
317
|
+
borderRadius: 3,
|
|
318
|
+
backgroundColor: tile.color,
|
|
319
|
+
opacity: 0.9,
|
|
320
|
+
padding: 4,
|
|
321
|
+
}}
|
|
322
|
+
>
|
|
323
|
+
<Text style={{ color, fontSize: 10, fontWeight: '600' }}>{tile.label}</Text>
|
|
324
|
+
</View>
|
|
325
|
+
))}
|
|
326
|
+
</View>
|
|
327
|
+
<Text className="text-text-secondary" style={{ fontSize: 10, marginTop: 4 }}>
|
|
328
|
+
{caption} · {color.toUpperCase()}
|
|
329
|
+
</Text>
|
|
330
|
+
</View>
|
|
331
|
+
)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function OnDataPanel() {
|
|
335
|
+
return (
|
|
336
|
+
<View className="bg-surface-elevated" style={{ borderRadius: 8, padding: 16 }}>
|
|
337
|
+
<Text className="text-text-secondary text-xs mb-3">
|
|
338
|
+
Top: the LIVE Treemap, whose label is the proposed `on-data-strong`. Below: the same tiles
|
|
339
|
+
with the nearest existing dark tokens, so the difference (or lack of one) is visible at
|
|
340
|
+
label size rather than as a swatch.
|
|
341
|
+
</Text>
|
|
342
|
+
<View style={{ gap: 12 }}>
|
|
343
|
+
<View>
|
|
344
|
+
<Treemap data={LIGHT_TILES} width={320} height={92} maxTiles={5} />
|
|
345
|
+
<Text className="text-text-secondary" style={{ fontSize: 10, marginTop: 4 }}>
|
|
346
|
+
live Treemap · on-data-strong · #0B0B0B
|
|
347
|
+
</Text>
|
|
348
|
+
</View>
|
|
349
|
+
<TileRow color={t['background-frame']} caption="background-frame" />
|
|
350
|
+
<TileRow color={greyRamp[950]} caption="greyRamp[950]" />
|
|
351
|
+
<TileRow color={primitiveColors.black} caption="primitiveColors.black" />
|
|
352
|
+
</View>
|
|
353
|
+
</View>
|
|
354
|
+
)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ---------------------------------------------------------------------------
|
|
358
|
+
|
|
359
|
+
function ApprovedSnaps() {
|
|
360
|
+
return (
|
|
361
|
+
<View
|
|
362
|
+
style={{
|
|
363
|
+
backgroundColor: t['surface-raised'],
|
|
364
|
+
borderRadius: 8,
|
|
365
|
+
padding: 12,
|
|
366
|
+
marginBottom: 20,
|
|
367
|
+
}}
|
|
368
|
+
>
|
|
369
|
+
<Text className="text-text-primary text-sm font-semibold mb-1">
|
|
370
|
+
Already approved — the six grey snaps (follow-up, NOT in #200)
|
|
371
|
+
</Text>
|
|
372
|
+
<Text className="text-text-secondary text-xs">
|
|
373
|
+
These need no new token: they are drifted Tailwind and ad-hoc neutrals that snap onto the
|
|
374
|
+
existing warm ramp. Approved for the follow-up PR because each one moves pixels.
|
|
375
|
+
{'\n\n'}
|
|
376
|
+
#6B7280 (Tailwind gray-500) → result-neutral, at IntensityBar, TempoDisplay, setHeadingKit,
|
|
377
|
+
Spinner · #9CA3AF (Tailwind gray-400) → text-secondary, at TempoDisplay ×4 · #333333 →
|
|
378
|
+
surface-raised · #2C2C2C → surface-elevated · #3A3A3A → surface-overlay · #0A0A0A →
|
|
379
|
+
background-frame
|
|
380
|
+
</Text>
|
|
381
|
+
</View>
|
|
382
|
+
)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
type Story = StoryObj<ProposedTokensArgs>
|
|
386
|
+
|
|
387
|
+
export const Default: Story = {
|
|
388
|
+
render: (args) => (
|
|
389
|
+
<View style={{ padding: 24, maxWidth: 900 }}>
|
|
390
|
+
<Text className="text-2xl font-bold text-text-primary mb-2">Proposed VW-82 tokens</Text>
|
|
391
|
+
<SectionIntro>
|
|
392
|
+
Seven candidates from #200, rendered where they would ship. Nothing here is in the token
|
|
393
|
+
layer — `semantic.ts`, `primitives.ts`, `global.css` and `tailwind.config.js` are untouched
|
|
394
|
+
until these are approved.
|
|
395
|
+
</SectionIntro>
|
|
396
|
+
|
|
397
|
+
<ApprovedSnaps />
|
|
398
|
+
|
|
399
|
+
<SectionTitle>1 · Scrims (4 candidates)</SectionTitle>
|
|
400
|
+
<Text className="text-text-secondary text-xs mb-3">
|
|
401
|
+
Toggle `showScrims` off to see what each one is hiding, and switch `backdrop` between the
|
|
402
|
+
checkerboard, a photographic gradient, and a plain surface. The plain surface is the case
|
|
403
|
+
that flatters every opacity equally — judge on the other two.
|
|
404
|
+
</Text>
|
|
405
|
+
<ScrimPanel {...args} />
|
|
406
|
+
|
|
407
|
+
<SectionTitle>2 · on-control (2 candidates)</SectionTitle>
|
|
408
|
+
<OnControlPanel />
|
|
409
|
+
|
|
410
|
+
<SectionTitle>3 · on-data-strong (1 candidate)</SectionTitle>
|
|
411
|
+
<OnDataPanel />
|
|
412
|
+
</View>
|
|
413
|
+
),
|
|
414
|
+
}
|
package/src/theme/config.ts
CHANGED
|
@@ -54,6 +54,8 @@ export const lightThemeCSSVars = {
|
|
|
54
54
|
|
|
55
55
|
'--color-on-brand-primary': semanticColorsLight['on-brand-primary'],
|
|
56
56
|
'--color-on-brand-secondary': semanticColorsLight['on-brand-secondary'],
|
|
57
|
+
'--color-on-brand-primary-subtle': semanticColorsLight['on-brand-primary-subtle'],
|
|
58
|
+
'--color-on-brand-secondary-subtle': semanticColorsLight['on-brand-secondary-subtle'],
|
|
57
59
|
|
|
58
60
|
'--color-status-success': semanticColorsLight['status-success'],
|
|
59
61
|
'--color-status-success-subtle': semanticColorsLight['status-success-subtle'],
|
|
@@ -126,6 +128,10 @@ export const lightThemeCSSVars = {
|
|
|
126
128
|
'--color-on-status-error': semanticColorsLight['on-status-error'],
|
|
127
129
|
'--color-on-status-warning': semanticColorsLight['on-status-warning'],
|
|
128
130
|
'--color-on-status-info': semanticColorsLight['on-status-info'],
|
|
131
|
+
'--color-on-status-success-subtle': semanticColorsLight['on-status-success-subtle'],
|
|
132
|
+
'--color-on-status-error-subtle': semanticColorsLight['on-status-error-subtle'],
|
|
133
|
+
'--color-on-status-warning-subtle': semanticColorsLight['on-status-warning-subtle'],
|
|
134
|
+
'--color-on-status-info-subtle': semanticColorsLight['on-status-info-subtle'],
|
|
129
135
|
|
|
130
136
|
'--color-result-improve': semanticColorsLight['result-improve'],
|
|
131
137
|
'--color-result-improve-light': semanticColorsLight['result-improve-light'],
|
|
@@ -191,6 +197,8 @@ export const darkThemeCSSVars = {
|
|
|
191
197
|
|
|
192
198
|
'--color-on-brand-primary': semanticColorsDark['on-brand-primary'],
|
|
193
199
|
'--color-on-brand-secondary': semanticColorsDark['on-brand-secondary'],
|
|
200
|
+
'--color-on-brand-primary-subtle': semanticColorsDark['on-brand-primary-subtle'],
|
|
201
|
+
'--color-on-brand-secondary-subtle': semanticColorsDark['on-brand-secondary-subtle'],
|
|
194
202
|
|
|
195
203
|
'--color-status-success': semanticColorsDark['status-success'],
|
|
196
204
|
'--color-status-success-subtle': semanticColorsDark['status-success-subtle'],
|
|
@@ -263,6 +271,10 @@ export const darkThemeCSSVars = {
|
|
|
263
271
|
'--color-on-status-error': semanticColorsDark['on-status-error'],
|
|
264
272
|
'--color-on-status-warning': semanticColorsDark['on-status-warning'],
|
|
265
273
|
'--color-on-status-info': semanticColorsDark['on-status-info'],
|
|
274
|
+
'--color-on-status-success-subtle': semanticColorsDark['on-status-success-subtle'],
|
|
275
|
+
'--color-on-status-error-subtle': semanticColorsDark['on-status-error-subtle'],
|
|
276
|
+
'--color-on-status-warning-subtle': semanticColorsDark['on-status-warning-subtle'],
|
|
277
|
+
'--color-on-status-info-subtle': semanticColorsDark['on-status-info-subtle'],
|
|
266
278
|
|
|
267
279
|
'--color-result-improve': semanticColorsDark['result-improve'],
|
|
268
280
|
'--color-result-improve-light': semanticColorsDark['result-improve-light'],
|
package/src/theme/global.css
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
--color-brand-secondary: #307B9B;
|
|
25
25
|
--color-brand-secondary-light: #2697B7;
|
|
26
26
|
--color-brand-secondary-dark: #2A617F;
|
|
27
|
-
--color-brand-secondary-subtle: rgba(
|
|
27
|
+
--color-brand-secondary-subtle: rgba(34, 211, 238, 0.12);
|
|
28
28
|
--color-brand-secondary-muted: rgba(48, 123, 155, 0.30);
|
|
29
29
|
--color-brand-secondary-strong: rgba(48, 123, 155, 0.50);
|
|
30
30
|
--color-brand-primary-hover: #FFA063;
|
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
|
|
35
35
|
--color-on-brand-primary: #FFFFFF;
|
|
36
36
|
--color-on-brand-secondary: #FFFFFF;
|
|
37
|
+
--color-on-brand-primary-subtle: #FF7900;
|
|
38
|
+
--color-on-brand-secondary-subtle: #22D3EE;
|
|
37
39
|
|
|
38
40
|
--color-status-success: #2ED573;
|
|
39
41
|
--color-status-success-light: #58F69E;
|
|
@@ -46,7 +48,7 @@
|
|
|
46
48
|
--color-status-error: #D14343;
|
|
47
49
|
--color-status-error-light: #E05254;
|
|
48
50
|
--color-status-error-dark: #A4221C;
|
|
49
|
-
--color-status-error-subtle: rgba(
|
|
51
|
+
--color-status-error-subtle: rgba(247, 113, 117, 0.08);
|
|
50
52
|
--color-status-error-muted: rgba(209, 67, 67, 0.30);
|
|
51
53
|
--color-status-error-strong: rgba(209, 67, 67, 0.50);
|
|
52
54
|
--color-status-error-vivid: #FF4757;
|
|
@@ -66,7 +68,7 @@
|
|
|
66
68
|
--color-status-info: #2196F3;
|
|
67
69
|
--color-status-info-light: #78C2FF;
|
|
68
70
|
--color-status-info-dark: #1072CB;
|
|
69
|
-
--color-status-info-subtle: rgba(
|
|
71
|
+
--color-status-info-subtle: rgba(120, 194, 255, 0.12);
|
|
70
72
|
--color-status-info-muted: rgba(33, 150, 243, 0.30);
|
|
71
73
|
--color-status-info-strong: rgba(33, 150, 243, 0.50);
|
|
72
74
|
|
|
@@ -74,6 +76,10 @@
|
|
|
74
76
|
--color-on-status-error: #FFFFFF;
|
|
75
77
|
--color-on-status-warning: #FFFFFF;
|
|
76
78
|
--color-on-status-info: #FFFFFF;
|
|
79
|
+
--color-on-status-success-subtle: #2ED573;
|
|
80
|
+
--color-on-status-error-subtle: #F77175;
|
|
81
|
+
--color-on-status-warning-subtle: #F9B415;
|
|
82
|
+
--color-on-status-info-subtle: #78C2FF;
|
|
77
83
|
|
|
78
84
|
--color-result-improve: #4caf50;
|
|
79
85
|
--color-result-improve-light: rgba(76, 175, 80, 0.16);
|
|
@@ -200,6 +206,8 @@
|
|
|
200
206
|
|
|
201
207
|
--color-on-brand-primary: #FFFFFF;
|
|
202
208
|
--color-on-brand-secondary: #FFFFFF;
|
|
209
|
+
--color-on-brand-primary-subtle: #FF7900;
|
|
210
|
+
--color-on-brand-secondary-subtle: #307B9B;
|
|
203
211
|
|
|
204
212
|
--color-status-success: #2ED573;
|
|
205
213
|
--color-status-success-light: #58F69E;
|
|
@@ -240,6 +248,10 @@
|
|
|
240
248
|
--color-on-status-error: #FFFFFF;
|
|
241
249
|
--color-on-status-warning: #FFFFFF;
|
|
242
250
|
--color-on-status-info: #FFFFFF;
|
|
251
|
+
--color-on-status-success-subtle: #2ED573;
|
|
252
|
+
--color-on-status-error-subtle: #D14343;
|
|
253
|
+
--color-on-status-warning-subtle: #F9B415;
|
|
254
|
+
--color-on-status-info-subtle: #2196F3;
|
|
243
255
|
|
|
244
256
|
--color-result-improve: #4caf50;
|
|
245
257
|
--color-result-improve-light: rgba(76, 175, 80, 0.12);
|