Improve modes

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
Charles de Dreuille
2026-02-25 10:15:28 +00:00
parent bf14b6e877
commit e1c87b33ca
4 changed files with 81 additions and 137 deletions
+15
View File
@@ -15,4 +15,19 @@ export const allModes = {
themeMode: 'dark',
themeName: 'spotify',
},
'light spotify neutral-1': {
themeMode: 'light',
themeName: 'spotify',
background: 'neutral-1',
},
'light spotify neutral-2': {
themeMode: 'light',
themeName: 'spotify',
background: 'neutral-2',
},
'light spotify neutral-3': {
themeMode: 'light',
themeName: 'spotify',
background: 'neutral-3',
},
} as const;
+37 -33
View File
@@ -3,14 +3,13 @@ import addonDocs from '@storybook/addon-docs';
import addonThemes from '@storybook/addon-themes';
import addonLinks from '@storybook/addon-links';
import { definePreview } from '@storybook/react-vite';
import { useEffect } from 'react';
import React, { useEffect } from 'react';
import { TestApiProvider } from '@backstage/test-utils';
import { AlertDisplay } from '@backstage/core-components';
import { apis } from './support/apis';
import { useGlobals } from 'storybook/preview-api';
import { UnifiedThemeProvider, themes } from '@backstage/theme';
import { allModes } from './modes';
import { Box } from '../packages/ui/src/components/Box';
// Default Backstage theme CSS (from packages/ui)
import '../packages/ui/src/css/styles.css';
@@ -20,6 +19,7 @@ import './storybook.css';
// Custom themes
import './themes/spotify.css';
import { Box } from '../packages/ui/src/components/Box';
export default definePreview({
tags: ['manifest'],
@@ -31,8 +31,8 @@ export default definePreview({
toolbar: {
icon: 'circlehollow',
items: [
{ value: 'light', icon: 'circlehollow', title: 'Light' },
{ value: 'dark', icon: 'circle', title: 'Dark' },
{ value: 'light', icon: 'sun', title: 'Light' },
{ value: 'dark', icon: 'moon', title: 'Dark' },
],
dynamicTitle: true,
},
@@ -50,11 +50,26 @@ export default definePreview({
dynamicTitle: true,
},
},
background: {
name: 'Background',
description: 'Global background for components',
defaultValue: 'app',
toolbar: {
icon: 'contrast',
items: [
{ value: 'app', title: 'App Background' },
{ value: 'neutral-1', title: 'Neutral 1 Background' },
{ value: 'neutral-2', title: 'Neutral 2 Background' },
{ value: 'neutral-3', title: 'Neutral 3 Background' },
],
},
},
},
initialGlobals: {
themeMode: 'light',
themeName: 'backstage',
background: 'app',
},
parameters: {
@@ -127,6 +142,8 @@ export default definePreview({
globals.themeMode === 'light' ? themes.light : themes.dark;
const selectedThemeMode = globals.themeMode || 'light';
const selectedThemeName = globals.themeName || 'backstage';
const selectedBackground = globals.background || 'app';
const isFullscreen = context.parameters.layout === 'fullscreen';
useEffect(() => {
document.body.removeAttribute('data-theme-mode');
@@ -140,47 +157,34 @@ export default definePreview({
}, [selectedTheme, selectedThemeName]);
document.body.style.backgroundColor = 'var(--bui-bg-app)';
document.body.style.padding =
isFullscreen && selectedBackground !== 'app' ? '1rem' : '';
const docsStoryElements = document.getElementsByClassName('docs-story');
Array.from(docsStoryElements).forEach(element => {
(element as HTMLElement).style.backgroundColor = 'var(--bui-bg-app)';
});
const content = (
return (
<UnifiedThemeProvider theme={selectedTheme}>
{/* @ts-ignore */}
<TestApiProvider apis={apis}>
<AlertDisplay />
<Story />
{Array.from({
length:
selectedBackground === 'app'
? 0
: parseInt(selectedBackground.split('-')[1], 10),
}).reduce<React.ReactNode>(
children => (
<Box bg="neutral-auto" p="4">
{children}
</Box>
),
<Story />,
)}
</TestApiProvider>
</UnifiedThemeProvider>
);
if (selectedThemeName !== 'spotify') {
return content;
}
const layout = context.parameters?.layout ?? 'padded';
const isFullscreen = context.parameters?.layout === 'fullscreen';
return (
<Box
bg="neutral-1"
style={{
minHeight: 'calc(100vh - 32px)',
width: 'calc(100vw - 32px)',
borderRadius: 'var(--bui-radius-3)',
...(layout === 'centered' && {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}),
}}
p="4"
m={isFullscreen ? '4' : '0'}
>
{content}
</Box>
);
},
],
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import preview from '../../../../../.storybook/preview';
import { allModes } from '../../../../../.storybook/modes';
import { Button } from './Button';
import { Flex } from '../Flex';
import { Box } from '../Box';
@@ -55,100 +56,37 @@ export const Variants = meta.story({
control: false,
},
},
chromatic: {
modes: {
'light spotify neutral-1': allModes['light spotify neutral-1'],
'light spotify neutral-2': allModes['light spotify neutral-2'],
'light spotify neutral-3': allModes['light spotify neutral-3'],
},
},
},
render: () => (
<Flex direction="column" gap="4">
<Flex direction="column" gap="4">
<Text>Default</Text>
<Flex align="center" p="4">
<Button iconStart={<RiCloudLine />} variant="primary">
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="secondary">
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="tertiary">
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="primary" destructive>
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="secondary" destructive>
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="tertiary" destructive>
Button
</Button>
</Flex>
<Flex align="center">
<Button iconStart={<RiCloudLine />} variant="primary">
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="secondary">
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="tertiary">
Button
</Button>
</Flex>
<Flex direction="column" gap="4">
<Text>Neutral 1</Text>
<Flex align="center" bg="neutral-1" p="4">
<Button iconStart={<RiCloudLine />} variant="primary">
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="secondary">
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="tertiary">
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="primary" destructive>
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="secondary" destructive>
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="tertiary" destructive>
Button
</Button>
</Flex>
</Flex>
<Flex direction="column" gap="4">
<Text>Neutral 2</Text>
<Flex align="center" bg="neutral-2" p="4">
<Button iconStart={<RiCloudLine />} variant="primary">
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="secondary">
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="tertiary">
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="primary" destructive>
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="secondary" destructive>
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="tertiary" destructive>
Button
</Button>
</Flex>
</Flex>
<Flex direction="column" gap="4">
<Text>Neutral 3</Text>
<Flex align="center" bg="neutral-3" p="4">
<Button iconStart={<RiCloudLine />} variant="primary">
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="secondary">
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="tertiary">
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="primary" destructive>
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="secondary" destructive>
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="tertiary" destructive>
Button
</Button>
</Flex>
<Flex align="center">
<Button iconStart={<RiCloudLine />} variant="primary" destructive>
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="secondary" destructive>
Button
</Button>
<Button iconStart={<RiCloudLine />} variant="tertiary" destructive>
Button
</Button>
</Flex>
</Flex>
),
@@ -208,20 +146,6 @@ export const Destructive = meta.story({
</Button>
</Flex>
</Flex>
<Flex direction="column" gap="4">
<Text>On Neutral 1</Text>
<Flex align="center" bg="neutral-1" p="4" gap="4">
<Button variant="primary" destructive>
Primary
</Button>
<Button variant="secondary" destructive>
Secondary
</Button>
<Button variant="tertiary" destructive>
Tertiary
</Button>
</Flex>
</Flex>
<Flex direction="column" gap="4">
<Text>Sizes</Text>
<Flex align="center" p="4" gap="4">
@@ -21,6 +21,7 @@
max-width: 120rem;
padding-inline: var(--bui-space-4);
margin-inline: auto;
padding-bottom: var(--bui-space-8);
}
@media (min-width: 640px) {