@wallarm-org/design-system 1.25.0 → 1.26.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 +2 -0
- package/dist/components/AppShell/story-content/_storyAccountDropdown.d.ts +1 -1
- package/dist/components/AppShell/story-content/_storyAccountDropdown.js +64 -17
- package/dist/components/NavPanel/NavPanelGroupItem.js +8 -1
- package/dist/components/NavPanel/classes.js +2 -2
- package/dist/components/NavRail/NavRailItem.js +3 -2
- package/dist/components/NavRail/classes.d.ts +1 -0
- package/dist/components/NavRail/classes.js +7 -2
- package/dist/components/ThemeProvider/ThemeProvider.d.ts +4 -1
- package/dist/components/ThemeProvider/ThemeProvider.js +18 -2
- package/dist/components/ThemeProvider/ThemeProviderContext.d.ts +3 -1
- package/dist/components/ThemeProvider/ThemeProviderContext.js +3 -1
- package/dist/components/ThemeProvider/index.d.ts +1 -1
- package/dist/components/ThemeProvider/types.d.ts +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/metadata/components.json +18 -2
- package/dist/theme/components/app-shell.css +11 -0
- package/dist/theme/index.css +4 -0
- package/dist/theme/semantic.css +79 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,6 +37,8 @@ export const App = () => {
|
|
|
37
37
|
};
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
`ThemeProvider` also controls the Frame style (`useTheme().setFrameStyle`, `'neutral' | 'branded'`) - see [Installation Guide](docs/installation.md) for details.
|
|
41
|
+
|
|
40
42
|
```css
|
|
41
43
|
/* App.css */
|
|
42
44
|
@import 'tailwindcss';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type NavRailMode } from '../../NavRail';
|
|
2
|
-
import type
|
|
2
|
+
import { type Theme } from '../../ThemeProvider';
|
|
3
3
|
export type SidebarMode = 'adaptive' | 'expanded' | 'collapsed' | 'compact';
|
|
4
4
|
/** Adaptive collapses the rail inside a product and expands it on Home; the other modes pin it. */
|
|
5
5
|
export declare const railModeFor: (mode: SidebarMode, onHome: boolean) => NavRailMode;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Fragment } from "react";
|
|
3
3
|
import { LogOut, PanelLeftDashed, PencilRuler, Settings, User, UserRound } from "../../../icons/index.js";
|
|
4
|
+
import { cn } from "../../../utils/cn.js";
|
|
4
5
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuItemContent, DropdownMenuItemIcon, DropdownMenuItemText, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger, DropdownMenuTriggerItem } from "../../DropdownMenu/index.js";
|
|
5
6
|
import { NavRailItem } from "../../NavRail/index.js";
|
|
6
7
|
import { HStack, VStack } from "../../Stack/index.js";
|
|
7
8
|
import { Text } from "../../Text/index.js";
|
|
9
|
+
import { useTheme } from "../../ThemeProvider/index.js";
|
|
8
10
|
const railModeFor = (mode, onHome)=>{
|
|
9
11
|
if ('adaptive' === mode) return onHome ? 'expanded' : 'collapsed';
|
|
10
12
|
return mode;
|
|
@@ -32,13 +34,27 @@ const THEME_LABELS = {
|
|
|
32
34
|
light: 'Light',
|
|
33
35
|
dark: 'Dark'
|
|
34
36
|
};
|
|
37
|
+
const FRAME_STYLES = [
|
|
38
|
+
'neutral',
|
|
39
|
+
'branded'
|
|
40
|
+
];
|
|
41
|
+
const FRAME_STYLE_LABELS = {
|
|
42
|
+
neutral: 'Neutral',
|
|
43
|
+
branded: 'Branded'
|
|
44
|
+
};
|
|
45
|
+
const FRAME_STYLE_SWATCH = {
|
|
46
|
+
neutral: 'bg-icon-secondary',
|
|
47
|
+
branded: 'bg-icon-brand'
|
|
48
|
+
};
|
|
35
49
|
const SIDEBAR_MODE_LABELS = {
|
|
36
50
|
adaptive: 'Adaptive',
|
|
37
51
|
expanded: 'Always expanded',
|
|
38
52
|
collapsed: 'Always collapsed',
|
|
39
53
|
compact: 'Compact'
|
|
40
54
|
};
|
|
41
|
-
const AccountDropdown = ({ sidebarMode, onSidebarModeChange, theme, onThemeChange })
|
|
55
|
+
const AccountDropdown = ({ sidebarMode, onSidebarModeChange, theme, onThemeChange })=>{
|
|
56
|
+
const { frameStyle, setFrameStyle } = useTheme();
|
|
57
|
+
return /*#__PURE__*/ jsxs(DropdownMenu, {
|
|
42
58
|
positioning: {
|
|
43
59
|
placement: 'right-end',
|
|
44
60
|
gutter: 6,
|
|
@@ -106,30 +122,60 @@ const AccountDropdown = ({ sidebarMode, onSidebarModeChange, theme, onThemeChang
|
|
|
106
122
|
/*#__PURE__*/ jsx(DropdownMenuItemText, {
|
|
107
123
|
children: "Appearance"
|
|
108
124
|
}),
|
|
109
|
-
/*#__PURE__*/
|
|
125
|
+
/*#__PURE__*/ jsxs(Text, {
|
|
110
126
|
size: "xs",
|
|
111
127
|
color: "secondary",
|
|
112
|
-
children:
|
|
128
|
+
children: [
|
|
129
|
+
THEME_LABELS[theme],
|
|
130
|
+
" and ",
|
|
131
|
+
FRAME_STYLE_LABELS[frameStyle].toLowerCase()
|
|
132
|
+
]
|
|
113
133
|
})
|
|
114
134
|
]
|
|
115
135
|
})
|
|
116
136
|
]
|
|
117
137
|
}),
|
|
118
|
-
/*#__PURE__*/
|
|
138
|
+
/*#__PURE__*/ jsxs(DropdownMenuContent, {
|
|
119
139
|
className: "w-132",
|
|
120
|
-
children:
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
children:
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
140
|
+
children: [
|
|
141
|
+
/*#__PURE__*/ jsx(DropdownMenuRadioGroup, {
|
|
142
|
+
value: theme,
|
|
143
|
+
onValueChange: ({ value })=>{
|
|
144
|
+
const next = THEMES.find((t)=>t === value);
|
|
145
|
+
if (next) onThemeChange(next);
|
|
146
|
+
},
|
|
147
|
+
children: THEMES.map((t)=>/*#__PURE__*/ jsx(DropdownMenuRadioItem, {
|
|
148
|
+
value: t,
|
|
149
|
+
children: /*#__PURE__*/ jsx(DropdownMenuItemText, {
|
|
150
|
+
children: THEME_LABELS[t]
|
|
151
|
+
})
|
|
152
|
+
}, t))
|
|
153
|
+
}),
|
|
154
|
+
/*#__PURE__*/ jsx(DropdownMenuSeparator, {}),
|
|
155
|
+
/*#__PURE__*/ jsx(DropdownMenuRadioGroup, {
|
|
156
|
+
value: frameStyle,
|
|
157
|
+
onValueChange: ({ value })=>{
|
|
158
|
+
const next = FRAME_STYLES.find((s)=>s === value);
|
|
159
|
+
if (next) setFrameStyle(next);
|
|
160
|
+
},
|
|
161
|
+
children: FRAME_STYLES.map((s)=>/*#__PURE__*/ jsxs(DropdownMenuRadioItem, {
|
|
162
|
+
value: s,
|
|
163
|
+
children: [
|
|
164
|
+
/*#__PURE__*/ jsx(DropdownMenuItemIcon, {
|
|
165
|
+
children: /*#__PURE__*/ jsx("span", {
|
|
166
|
+
className: "flex size-16 items-center justify-center",
|
|
167
|
+
children: /*#__PURE__*/ jsx("span", {
|
|
168
|
+
className: cn('size-8 rounded-full', FRAME_STYLE_SWATCH[s])
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
}),
|
|
172
|
+
/*#__PURE__*/ jsx(DropdownMenuItemText, {
|
|
173
|
+
children: FRAME_STYLE_LABELS[s]
|
|
174
|
+
})
|
|
175
|
+
]
|
|
176
|
+
}, s))
|
|
177
|
+
})
|
|
178
|
+
]
|
|
133
179
|
})
|
|
134
180
|
]
|
|
135
181
|
}),
|
|
@@ -192,4 +238,5 @@ const AccountDropdown = ({ sidebarMode, onSidebarModeChange, theme, onThemeChang
|
|
|
192
238
|
})
|
|
193
239
|
]
|
|
194
240
|
});
|
|
241
|
+
};
|
|
195
242
|
export { AccountDropdown, railModeFor };
|
|
@@ -4,7 +4,7 @@ import { cn } from "../../utils/cn.js";
|
|
|
4
4
|
import { useTestId } from "../../utils/testId.js";
|
|
5
5
|
import { Text } from "../Text/index.js";
|
|
6
6
|
import { navPanelGroupItemVariants } from "./classes.js";
|
|
7
|
-
import { useNavPanelDepth, useNavPanelIndent } from "./NavPanelContext.js";
|
|
7
|
+
import { NAV_PANEL_BASE_PADDING, useNavPanelDepth, useNavPanelIndent } from "./NavPanelContext.js";
|
|
8
8
|
const NavPanelGroupItem = ({ ref, asChild = false, icon: Icon, active = false, className, children, ...props })=>{
|
|
9
9
|
const testId = useTestId('group-item');
|
|
10
10
|
const depth = useNavPanelDepth();
|
|
@@ -33,6 +33,13 @@ const NavPanelGroupItem = ({ ref, asChild = false, icon: Icon, active = false, c
|
|
|
33
33
|
size: "sm",
|
|
34
34
|
truncate: true,
|
|
35
35
|
children: children
|
|
36
|
+
}),
|
|
37
|
+
active && depth > 0 && /*#__PURE__*/ jsx("span", {
|
|
38
|
+
"aria-hidden": true,
|
|
39
|
+
className: "absolute top-0 bottom-0 hidden w-px bg-border-brand branded:block",
|
|
40
|
+
style: {
|
|
41
|
+
left: depth * indent - NAV_PANEL_BASE_PADDING
|
|
42
|
+
}
|
|
36
43
|
})
|
|
37
44
|
]
|
|
38
45
|
});
|
|
@@ -2,7 +2,7 @@ import { cva } from "class-variance-authority";
|
|
|
2
2
|
const navPanelItemVariants = cva('overlay flex h-32 shrink-0 w-full cursor-pointer items-center gap-8 rounded-10 p-8 text-sm text-text-primary transition-colors outline-none', {
|
|
3
3
|
variants: {
|
|
4
4
|
active: {
|
|
5
|
-
true: 'overlay-states-primary-active font-semibold',
|
|
5
|
+
true: 'overlay-states-primary-active font-semibold branded:overlay-states-brand-active branded:text-text-brand',
|
|
6
6
|
false: 'hover:overlay-states-primary-hover focus-visible:overlay-states-primary-hover active:overlay-states-primary-pressed'
|
|
7
7
|
}
|
|
8
8
|
},
|
|
@@ -13,7 +13,7 @@ const navPanelItemVariants = cva('overlay flex h-32 shrink-0 w-full cursor-point
|
|
|
13
13
|
const navPanelGroupItemVariants = cva('overlay flex h-32 shrink-0 w-full cursor-pointer items-center gap-8 rounded-10 py-8 pr-8 text-sm text-text-primary transition-colors outline-none', {
|
|
14
14
|
variants: {
|
|
15
15
|
active: {
|
|
16
|
-
true: 'overlay-states-primary-active font-semibold',
|
|
16
|
+
true: 'overlay-states-primary-active font-semibold branded:overlay-states-brand-active branded:text-text-brand',
|
|
17
17
|
false: 'hover:overlay-states-primary-hover focus-visible:overlay-states-primary-hover active:overlay-states-primary-pressed'
|
|
18
18
|
}
|
|
19
19
|
},
|
|
@@ -31,14 +31,15 @@ const NavRailItem = ({ ref, asChild = false, icon: Icon, label, shortcut, active
|
|
|
31
31
|
"data-testid": testId,
|
|
32
32
|
className: cn(navRailItemVariants({
|
|
33
33
|
mode,
|
|
34
|
-
active
|
|
34
|
+
active,
|
|
35
|
+
avatar: hasPlate
|
|
35
36
|
}), className),
|
|
36
37
|
children: [
|
|
37
38
|
/*#__PURE__*/ jsx("span", {
|
|
38
39
|
className: "flex shrink-0 items-center justify-center",
|
|
39
40
|
children: hasPlate ? /*#__PURE__*/ jsxs("span", {
|
|
40
41
|
"data-slot": "nav-rail-item-avatar",
|
|
41
|
-
className: cn('-m-4 grid size-24 place-items-center overflow-hidden rounded-8 bg-states-primary-hover *:col-start-1 *:row-start-1', !photo && 'border border-border-primary'),
|
|
42
|
+
className: cn('-m-4 grid size-24 place-items-center overflow-hidden rounded-8 bg-states-primary-hover branded:bg-states-brand-hover branded:text-icon-brand *:col-start-1 *:row-start-1', !photo && 'border border-border-primary branded:border-border-brand'),
|
|
42
43
|
children: [
|
|
43
44
|
/*#__PURE__*/ jsx(Icon, {
|
|
44
45
|
size: "md"
|
|
@@ -13,5 +13,6 @@ export declare const navRailSkeletonVariants: (props?: ({
|
|
|
13
13
|
export declare const navRailItemVariants: (props?: ({
|
|
14
14
|
mode?: "collapsed" | "compact" | "expanded" | null | undefined;
|
|
15
15
|
active?: boolean | null | undefined;
|
|
16
|
+
avatar?: boolean | null | undefined;
|
|
16
17
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
17
18
|
export declare const navRailItemCompactLabelClassName = "line-clamp-2 w-56 shrink-0 text-center text-2xs font-medium text-ellipsis break-normal";
|
|
@@ -52,13 +52,18 @@ const navRailItemVariants = cva('overlay flex w-full cursor-pointer items-center
|
|
|
52
52
|
compact: 'min-h-42 flex-col justify-center gap-2 px-8 py-6'
|
|
53
53
|
},
|
|
54
54
|
active: {
|
|
55
|
-
true: 'overlay-states-primary-active',
|
|
55
|
+
true: 'overlay-states-primary-active branded:overlay-states-brand-active branded:data-[state=open]:overlay-states-brand-active branded:text-text-brand',
|
|
56
56
|
false: 'hover:overlay-states-primary-hover focus-visible:overlay-states-primary-hover active:overlay-states-primary-pressed'
|
|
57
|
+
},
|
|
58
|
+
avatar: {
|
|
59
|
+
true: 'branded:hover:overlay-states-brand-hover branded:focus-visible:overlay-states-brand-hover branded:active:overlay-states-brand-pressed branded:data-[state=open]:overlay-states-brand-active',
|
|
60
|
+
false: ''
|
|
57
61
|
}
|
|
58
62
|
},
|
|
59
63
|
defaultVariants: {
|
|
60
64
|
mode: 'expanded',
|
|
61
|
-
active: false
|
|
65
|
+
active: false,
|
|
66
|
+
avatar: false
|
|
62
67
|
}
|
|
63
68
|
});
|
|
64
69
|
const navRailItemCompactLabelClassName = 'line-clamp-2 w-56 shrink-0 text-center text-2xs font-medium text-ellipsis break-normal';
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { type FC, type ReactNode } from 'react';
|
|
2
|
-
import type { Theme } from './types';
|
|
2
|
+
import type { FrameStyle, Theme } from './types';
|
|
3
3
|
interface ThemeProviderProps {
|
|
4
4
|
children: ReactNode;
|
|
5
5
|
defaultTheme?: Theme;
|
|
6
6
|
storageKey?: string;
|
|
7
|
+
/** Frame style used until the user picks one. */
|
|
8
|
+
defaultFrameStyle?: FrameStyle;
|
|
9
|
+
frameStyleStorageKey?: string;
|
|
7
10
|
}
|
|
8
11
|
export declare const ThemeProvider: FC<ThemeProviderProps>;
|
|
9
12
|
export {};
|
|
@@ -1,23 +1,39 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useMemo, useState } from "react";
|
|
3
3
|
import { ThemeProviderContext } from "./ThemeProviderContext.js";
|
|
4
|
-
const ThemeProvider = ({ children, defaultTheme = 'light', storageKey = 'wasd-theme', ...props })=>{
|
|
4
|
+
const ThemeProvider = ({ children, defaultTheme = 'light', storageKey = 'wasd-theme', defaultFrameStyle = 'neutral', frameStyleStorageKey = 'wasd-frame-style', ...props })=>{
|
|
5
5
|
const [theme, setTheme] = useState(()=>localStorage.getItem(storageKey) || defaultTheme);
|
|
6
|
+
const [frameStyle, setFrameStyle] = useState(()=>{
|
|
7
|
+
const stored = localStorage.getItem(frameStyleStorageKey);
|
|
8
|
+
return 'neutral' === stored || 'branded' === stored ? stored : defaultFrameStyle;
|
|
9
|
+
});
|
|
6
10
|
useEffect(()=>{
|
|
7
11
|
const root = window.document.documentElement;
|
|
8
12
|
root.setAttribute('data-theme', theme);
|
|
9
13
|
}, [
|
|
10
14
|
theme
|
|
11
15
|
]);
|
|
16
|
+
useEffect(()=>{
|
|
17
|
+
window.document.documentElement.setAttribute('data-frame-style', frameStyle);
|
|
18
|
+
}, [
|
|
19
|
+
frameStyle
|
|
20
|
+
]);
|
|
12
21
|
const value = useMemo(()=>({
|
|
13
22
|
theme,
|
|
14
23
|
setTheme: (theme)=>{
|
|
15
24
|
localStorage.setItem(storageKey, theme);
|
|
16
25
|
setTheme(theme);
|
|
26
|
+
},
|
|
27
|
+
frameStyle,
|
|
28
|
+
setFrameStyle: (frameStyle)=>{
|
|
29
|
+
localStorage.setItem(frameStyleStorageKey, frameStyle);
|
|
30
|
+
setFrameStyle(frameStyle);
|
|
17
31
|
}
|
|
18
32
|
}), [
|
|
19
33
|
theme,
|
|
20
|
-
storageKey
|
|
34
|
+
storageKey,
|
|
35
|
+
frameStyle,
|
|
36
|
+
frameStyleStorageKey
|
|
21
37
|
]);
|
|
22
38
|
return /*#__PURE__*/ jsx(ThemeProviderContext.Provider, {
|
|
23
39
|
...props,
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type { Theme } from './types';
|
|
1
|
+
import type { FrameStyle, Theme } from './types';
|
|
2
2
|
export interface ThemeProviderState {
|
|
3
3
|
theme: Theme;
|
|
4
4
|
setTheme: (theme: Theme) => void;
|
|
5
|
+
frameStyle: FrameStyle;
|
|
6
|
+
setFrameStyle: (frameStyle: FrameStyle) => void;
|
|
5
7
|
}
|
|
6
8
|
export declare const ThemeProviderContext: import("react").Context<ThemeProviderState>;
|
package/dist/index.d.ts
CHANGED
|
@@ -87,7 +87,7 @@ export { Tabs, TabsButton, TabsContent, TabsLineActions, TabsList, TabsSeparator
|
|
|
87
87
|
export { Tag, TagClose, type TagProps } from './components/Tag';
|
|
88
88
|
export { Text, type TextProps } from './components/Text';
|
|
89
89
|
export { Textarea, type TextareaProps } from './components/Textarea';
|
|
90
|
-
export { type Theme, ThemeProvider, useTheme, } from './components/ThemeProvider';
|
|
90
|
+
export { type FrameStyle, type Theme, ThemeProvider, useTheme, } from './components/ThemeProvider';
|
|
91
91
|
export { TimeInput, type TimeInputProps } from './components/TimeInput';
|
|
92
92
|
export { Timeline, TimelineConnector, type TimelineConnectorProps, TimelineContent, type TimelineContentProps, TimelineDescription, type TimelineDescriptionProps, TimelineIndicator, type TimelineIndicatorProps, TimelineItem, type TimelineItemProps, type TimelineProps, TimelineSeparator, type TimelineSeparatorProps, TimelineTitle, type TimelineTitleProps, } from './components/Timeline';
|
|
93
93
|
export { Toast, ToastActions, Toaster, toaster } from './components/Toast';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
3
|
-
"generatedAt": "2026-09-
|
|
2
|
+
"version": "1.25.0",
|
|
3
|
+
"generatedAt": "2026-09-28T09:09:05.490Z",
|
|
4
4
|
"components": [
|
|
5
5
|
{
|
|
6
6
|
"name": "Accordion",
|
|
@@ -45049,6 +45049,14 @@
|
|
|
45049
45049
|
"false"
|
|
45050
45050
|
],
|
|
45051
45051
|
"defaultValue": "false"
|
|
45052
|
+
},
|
|
45053
|
+
{
|
|
45054
|
+
"name": "avatar",
|
|
45055
|
+
"options": [
|
|
45056
|
+
"true",
|
|
45057
|
+
"false"
|
|
45058
|
+
],
|
|
45059
|
+
"defaultValue": "false"
|
|
45052
45060
|
}
|
|
45053
45061
|
],
|
|
45054
45062
|
"subComponents": [
|
|
@@ -102204,6 +102212,10 @@
|
|
|
102204
102212
|
"name": "--color-component-app-shell-bg",
|
|
102205
102213
|
"value": "var(--color-slate-100)"
|
|
102206
102214
|
},
|
|
102215
|
+
{
|
|
102216
|
+
"name": "--color-component-app-shell-bg-branded",
|
|
102217
|
+
"value": "var(--color-w-orange-50)"
|
|
102218
|
+
},
|
|
102207
102219
|
{
|
|
102208
102220
|
"name": "--color-component-app-shell-ambient-dot",
|
|
102209
102221
|
"value": "--alpha(var(--color-slate-500) / 28%)"
|
|
@@ -103282,6 +103294,10 @@
|
|
|
103282
103294
|
"name": "--color-component-app-shell-bg",
|
|
103283
103295
|
"value": "var(--color-slate-975)"
|
|
103284
103296
|
},
|
|
103297
|
+
{
|
|
103298
|
+
"name": "--color-component-app-shell-bg-branded",
|
|
103299
|
+
"value": "#160e1a"
|
|
103300
|
+
},
|
|
103285
103301
|
{
|
|
103286
103302
|
"name": "--color-component-app-shell-ambient-dot",
|
|
103287
103303
|
"value": "--alpha(var(--color-slate-50) / 15%)"
|
|
@@ -40,6 +40,17 @@
|
|
|
40
40
|
--app-shell-ambient-grain-blend: screen;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/* Branded Frame (WDS-182): multiplying or screening gray noise over the warm base dulls it
|
|
44
|
+
toward gray. Soft-light adds the same texture and keeps the orange. */
|
|
45
|
+
:root[data-frame-style='branded'] {
|
|
46
|
+
--app-shell-ambient-grain-opacity: 0.6;
|
|
47
|
+
--app-shell-ambient-grain-blend: soft-light;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
:root[data-theme='dark'][data-frame-style='branded'] {
|
|
51
|
+
--app-shell-ambient-grain-opacity: 0.35;
|
|
52
|
+
}
|
|
53
|
+
|
|
43
54
|
@utility app-shell-ambient {
|
|
44
55
|
position: absolute;
|
|
45
56
|
inset: 0;
|
package/dist/theme/index.css
CHANGED
|
@@ -31,6 +31,10 @@
|
|
|
31
31
|
@import './components/app-shell.css';
|
|
32
32
|
@import './components/chart.css';
|
|
33
33
|
|
|
34
|
+
/* Frame style (WDS-182): styles that apply only while the user has picked the Branded Frame.
|
|
35
|
+
ThemeProvider writes `data-frame-style` on <html>, so this reaches every micro-frontend. */
|
|
36
|
+
@custom-variant branded (&:where([data-frame-style='branded'] *));
|
|
37
|
+
|
|
34
38
|
[data-scope='scroll-area'][data-part='viewport'] {
|
|
35
39
|
scrollbar-width: none;
|
|
36
40
|
&::-webkit-scrollbar {
|
package/dist/theme/semantic.css
CHANGED
|
@@ -215,6 +215,11 @@
|
|
|
215
215
|
--color-component-toast-ic-success: var(--color-green-400);
|
|
216
216
|
--color-component-toast-ic-info: var(--color-blue-400);
|
|
217
217
|
--color-component-app-shell-bg: var(--color-slate-100);
|
|
218
|
+
/* Branded Frame (WDS-182): the Frame fill when the user picks the Branded Frame style.
|
|
219
|
+
* Swapped in for the token above under `[data-frame-style='branded']` (end of file), so
|
|
220
|
+
* AppShell follows with no component change; the Ambient tones below get their own
|
|
221
|
+
* Branded recipe at the end of the file. */
|
|
222
|
+
--color-component-app-shell-bg-branded: var(--color-w-orange-50);
|
|
218
223
|
|
|
219
224
|
/* AppShell Frame ambient — the soft spots and dot raster painted into the
|
|
220
225
|
* Frame (header + rail). Every tone derives from the Frame token above, so
|
|
@@ -661,6 +666,7 @@
|
|
|
661
666
|
--color-component-toast-ic-success: var(--color-green-600);
|
|
662
667
|
--color-component-toast-ic-info: var(--color-blue-600);
|
|
663
668
|
--color-component-app-shell-bg: var(--color-slate-975);
|
|
669
|
+
--color-component-app-shell-bg-branded: #160e1a;
|
|
664
670
|
|
|
665
671
|
/* AppShell Frame ambient (dark) — on a near-black base only lifts read, so
|
|
666
672
|
* every spot mixes toward white. */
|
|
@@ -876,3 +882,76 @@
|
|
|
876
882
|
--color-data-viz-1: #ffffff;
|
|
877
883
|
--temp-token: #ffffff;
|
|
878
884
|
}
|
|
885
|
+
|
|
886
|
+
/* ========================================
|
|
887
|
+
* FRAME STYLE: BRANDED (WDS-182)
|
|
888
|
+
* ThemeProvider writes `data-frame-style` on <html>. Branded is not a value swap like
|
|
889
|
+
* dark: components switch to the existing brand tokens through the `branded:` variant
|
|
890
|
+
* (index.css). Only the Frame base and the Ambient tones change here. These rules are
|
|
891
|
+
* unlayered, so they beat the light theme values in `@layer theme`; the doubled
|
|
892
|
+
* specificity of `:root[...]` beats `[data-theme='dark']`.
|
|
893
|
+
*
|
|
894
|
+
* The neutral Ambient recipe mixes the base toward white/black in oklch. The achromatic
|
|
895
|
+
* end has no hue, so on a pale orange base the tones lose theirs and read gray. Branded
|
|
896
|
+
* tints the spots toward the brand oranges in oklab instead, which keeps the hue, and
|
|
897
|
+
* lifts only part-way to white so they stay warm. The grain's blend lives in app-shell.css.
|
|
898
|
+
* ======================================== */
|
|
899
|
+
:root[data-frame-style='branded'] {
|
|
900
|
+
--color-component-app-shell-bg: var(--color-component-app-shell-bg-branded);
|
|
901
|
+
--color-component-app-shell-ambient-lift: color-mix(
|
|
902
|
+
in oklab,
|
|
903
|
+
var(--color-component-app-shell-bg),
|
|
904
|
+
white 40%
|
|
905
|
+
);
|
|
906
|
+
--color-component-app-shell-ambient-lift-soft: color-mix(
|
|
907
|
+
in srgb,
|
|
908
|
+
color-mix(in oklab, var(--color-component-app-shell-bg), white 25%) 70%,
|
|
909
|
+
transparent
|
|
910
|
+
);
|
|
911
|
+
--color-component-app-shell-ambient-shade: color-mix(
|
|
912
|
+
in srgb,
|
|
913
|
+
color-mix(in oklab, var(--color-component-app-shell-bg), var(--color-w-orange-300) 30%) 70%,
|
|
914
|
+
transparent
|
|
915
|
+
);
|
|
916
|
+
--color-component-app-shell-ambient-shade-soft: color-mix(
|
|
917
|
+
in srgb,
|
|
918
|
+
color-mix(in oklab, var(--color-component-app-shell-bg), var(--color-w-orange-200) 30%) 65%,
|
|
919
|
+
transparent
|
|
920
|
+
);
|
|
921
|
+
--color-component-app-shell-ambient-header: color-mix(
|
|
922
|
+
in srgb,
|
|
923
|
+
color-mix(in oklab, var(--color-component-app-shell-bg), var(--color-w-orange-300) 25%) 22%,
|
|
924
|
+
transparent
|
|
925
|
+
);
|
|
926
|
+
--color-component-app-shell-ambient-dot: --alpha(var(--color-w-orange-500) / 28%);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
/* Dark: only a faint warm glow toward the deepest brand oranges, as quiet as the neutral lifts. */
|
|
930
|
+
:root[data-theme='dark'][data-frame-style='branded'] {
|
|
931
|
+
--color-component-app-shell-ambient-lift: color-mix(
|
|
932
|
+
in srgb,
|
|
933
|
+
color-mix(in oklab, var(--color-component-app-shell-bg), var(--color-w-orange-900) 10%) 95%,
|
|
934
|
+
transparent
|
|
935
|
+
);
|
|
936
|
+
--color-component-app-shell-ambient-lift-soft: color-mix(
|
|
937
|
+
in srgb,
|
|
938
|
+
color-mix(in oklab, var(--color-component-app-shell-bg), var(--color-w-orange-900) 14%) 70%,
|
|
939
|
+
transparent
|
|
940
|
+
);
|
|
941
|
+
--color-component-app-shell-ambient-shade: color-mix(
|
|
942
|
+
in srgb,
|
|
943
|
+
color-mix(in oklab, var(--color-component-app-shell-bg), var(--color-w-orange-900) 12%) 60%,
|
|
944
|
+
transparent
|
|
945
|
+
);
|
|
946
|
+
--color-component-app-shell-ambient-shade-soft: color-mix(
|
|
947
|
+
in srgb,
|
|
948
|
+
color-mix(in oklab, var(--color-component-app-shell-bg), var(--color-w-orange-950) 18%) 95%,
|
|
949
|
+
transparent
|
|
950
|
+
);
|
|
951
|
+
--color-component-app-shell-ambient-header: color-mix(
|
|
952
|
+
in srgb,
|
|
953
|
+
color-mix(in oklab, var(--color-component-app-shell-bg), var(--color-w-orange-900) 10%) 30%,
|
|
954
|
+
transparent
|
|
955
|
+
);
|
|
956
|
+
--color-component-app-shell-ambient-dot: --alpha(var(--color-w-orange-300) / 15%);
|
|
957
|
+
}
|