mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Storybook: Fixes theming of the padded story (that makes stories use primary background by default) (#33166)
This commit is contained in:
parent
bad048b7ba
commit
dc6d134276
@ -9,7 +9,6 @@ import '../../../public/vendor/flot/jquery.flot.crosshair';
|
|||||||
import '../../../public/vendor/flot/jquery.flot.dashes';
|
import '../../../public/vendor/flot/jquery.flot.dashes';
|
||||||
import '../../../public/vendor/flot/jquery.flot.gauge';
|
import '../../../public/vendor/flot/jquery.flot.gauge';
|
||||||
import { withTheme } from '../src/utils/storybook/withTheme';
|
import { withTheme } from '../src/utils/storybook/withTheme';
|
||||||
import { withPaddedStory } from '../src/utils/storybook/withPaddedStory';
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import lightTheme from '../../../public/sass/grafana.light.scss';
|
import lightTheme from '../../../public/sass/grafana.light.scss';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -33,7 +32,7 @@ addons.setConfig({
|
|||||||
theme: GrafanaDark,
|
theme: GrafanaDark,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const decorators = [withTheme(handleThemeChange), withPaddedStory];
|
export const decorators = [withTheme(handleThemeChange)];
|
||||||
|
|
||||||
export const parameters = {
|
export const parameters = {
|
||||||
docs: {
|
docs: {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { renderComponentWithTheme } from '../../utils/storybook/withTheme';
|
|
||||||
import { CallToActionCard, CallToActionCardProps } from './CallToActionCard';
|
import { CallToActionCard, CallToActionCardProps } from './CallToActionCard';
|
||||||
import { Story, Meta } from '@storybook/react';
|
import { Story, Meta } from '@storybook/react';
|
||||||
import { Button } from '../Button/Button';
|
import { Button } from '../Button/Button';
|
||||||
@ -37,11 +36,9 @@ export const Basic: Story<StoryProps> = (args) => {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
return renderComponentWithTheme(CallToActionCard, {
|
return (
|
||||||
message: args.message,
|
<CallToActionCard message={args.message} callToActionElement={ctaElements[args.Element]} footer={args.footer} />
|
||||||
callToActionElement: ctaElements[args.Element],
|
);
|
||||||
footer: args.footer,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Basic.args = {
|
Basic.args = {
|
||||||
|
@ -1,32 +1,27 @@
|
|||||||
import React, { useContext } from 'react';
|
import React from 'react';
|
||||||
import { render } from 'enzyme';
|
import { render } from 'enzyme';
|
||||||
import { CallToActionCard, CallToActionCardProps } from './CallToActionCard';
|
import { CallToActionCard } from './CallToActionCard';
|
||||||
import { ThemeContext } from '../../themes';
|
|
||||||
|
|
||||||
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
|
||||||
|
|
||||||
const TestRenderer = (props: Omit<CallToActionCardProps, 'theme'>) => {
|
|
||||||
const theme = useContext(ThemeContext);
|
|
||||||
return <CallToActionCard theme={theme} {...props} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('CallToActionCard', () => {
|
describe('CallToActionCard', () => {
|
||||||
describe('rendering', () => {
|
describe('rendering', () => {
|
||||||
it('when no message and footer provided', () => {
|
it('when no message and footer provided', () => {
|
||||||
const tree = render(<TestRenderer callToActionElement={<a href="http://dummy.link">Click me</a>} />);
|
const tree = render(<CallToActionCard callToActionElement={<a href="http://dummy.link">Click me</a>} />);
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('when message and no footer provided', () => {
|
it('when message and no footer provided', () => {
|
||||||
const tree = render(
|
const tree = render(
|
||||||
<TestRenderer message="Click button bellow" callToActionElement={<a href="http://dummy.link">Click me</a>} />
|
<CallToActionCard
|
||||||
|
message="Click button bellow"
|
||||||
|
callToActionElement={<a href="http://dummy.link">Click me</a>}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('when message and footer provided', () => {
|
it('when message and footer provided', () => {
|
||||||
const tree = render(
|
const tree = render(
|
||||||
<TestRenderer
|
<CallToActionCard
|
||||||
message="Click button bellow"
|
message="Click button bellow"
|
||||||
footer="footer content"
|
footer="footer content"
|
||||||
callToActionElement={<a href="http://dummy.link">Click me</a>}
|
callToActionElement={<a href="http://dummy.link">Click me</a>}
|
||||||
|
@ -1,17 +1,33 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Themeable } from '../../types/theme';
|
|
||||||
import { GrafanaTheme } from '@grafana/data';
|
import { GrafanaTheme } from '@grafana/data';
|
||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import { stylesFactory } from '../../themes';
|
import { useStyles } from '../../themes/ThemeContext';
|
||||||
|
|
||||||
export interface CallToActionCardProps extends Themeable {
|
export interface CallToActionCardProps {
|
||||||
message?: string | JSX.Element;
|
message?: string | JSX.Element;
|
||||||
callToActionElement: JSX.Element;
|
callToActionElement: JSX.Element;
|
||||||
footer?: string | JSX.Element;
|
footer?: string | JSX.Element;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getCallToActionCardStyles = stylesFactory((theme: GrafanaTheme) => ({
|
export const CallToActionCard: React.FunctionComponent<CallToActionCardProps> = ({
|
||||||
|
message,
|
||||||
|
callToActionElement,
|
||||||
|
footer,
|
||||||
|
className,
|
||||||
|
}) => {
|
||||||
|
const css = useStyles(getStyles);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cx([css.wrapper, className])}>
|
||||||
|
{message && <div className={css.message}>{message}</div>}
|
||||||
|
{callToActionElement}
|
||||||
|
{footer && <div className={css.footer}>{footer}</div>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStyles = (theme: GrafanaTheme) => ({
|
||||||
wrapper: css`
|
wrapper: css`
|
||||||
label: call-to-action-card;
|
label: call-to-action-card;
|
||||||
padding: ${theme.spacing.lg};
|
padding: ${theme.spacing.lg};
|
||||||
@ -30,22 +46,4 @@ const getCallToActionCardStyles = stylesFactory((theme: GrafanaTheme) => ({
|
|||||||
footer: css`
|
footer: css`
|
||||||
margin-top: ${theme.spacing.lg};
|
margin-top: ${theme.spacing.lg};
|
||||||
`,
|
`,
|
||||||
}));
|
});
|
||||||
|
|
||||||
export const CallToActionCard: React.FunctionComponent<CallToActionCardProps> = ({
|
|
||||||
message,
|
|
||||||
callToActionElement,
|
|
||||||
footer,
|
|
||||||
theme,
|
|
||||||
className,
|
|
||||||
}) => {
|
|
||||||
const css = getCallToActionCardStyles(theme);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={cx([css.wrapper, className])}>
|
|
||||||
{message && <div className={css.message}>{message}</div>}
|
|
||||||
{callToActionElement}
|
|
||||||
{footer && <div className={css.footer}>{footer}</div>}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { GlobalStyles, useTheme } from '../../themes';
|
|
||||||
import { RenderFunction } from '../../types';
|
|
||||||
|
|
||||||
const PaddedStory: React.FunctionComponent<{}> = ({ children }) => {
|
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
width: '100%',
|
|
||||||
padding: '20px',
|
|
||||||
display: 'flex',
|
|
||||||
minHeight: '80vh',
|
|
||||||
background: `${theme.v2.palette.background.primary}`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<GlobalStyles />
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const withPaddedStory = (story: RenderFunction) => <PaddedStory>{story()}</PaddedStory>;
|
|
@ -1,20 +1,38 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ThemeContext } from '../../themes/ThemeContext';
|
import { ThemeContext } from '../../themes/ThemeContext';
|
||||||
import { getTheme } from '../../themes/index';
|
import { getTheme, GlobalStyles } from '../../themes/index';
|
||||||
import { GrafanaThemeType } from '@grafana/data';
|
import { GrafanaThemeType } from '@grafana/data';
|
||||||
import { RenderFunction } from '../../types';
|
import { RenderFunction } from '../../types';
|
||||||
import { useDarkMode } from 'storybook-dark-mode';
|
import { useDarkMode } from 'storybook-dark-mode';
|
||||||
|
|
||||||
type SassThemeChangeHandler = (theme: GrafanaThemeType) => void;
|
type SassThemeChangeHandler = (theme: GrafanaThemeType) => void;
|
||||||
|
|
||||||
const ThemeableStory: React.FunctionComponent<{ handleSassThemeChange: SassThemeChangeHandler }> = ({
|
const ThemeableStory: React.FunctionComponent<{ handleSassThemeChange: SassThemeChangeHandler }> = ({
|
||||||
children,
|
children,
|
||||||
handleSassThemeChange,
|
handleSassThemeChange,
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useDarkMode() ? GrafanaThemeType.Dark : GrafanaThemeType.Light;
|
const themeType = useDarkMode() ? GrafanaThemeType.Dark : GrafanaThemeType.Light;
|
||||||
|
|
||||||
handleSassThemeChange(theme);
|
handleSassThemeChange(themeType);
|
||||||
|
|
||||||
return <ThemeContext.Provider value={getTheme(theme)}>{children}</ThemeContext.Provider>;
|
const theme = getTheme(themeType);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeContext.Provider value={theme}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
padding: '20px',
|
||||||
|
display: 'flex',
|
||||||
|
minHeight: '80vh',
|
||||||
|
background: `${theme.v2.palette.background.primary}`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<GlobalStyles />
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</ThemeContext.Provider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Temporary solution. When we update to Storybook V5 we will be able to pass data from decorator to story
|
// Temporary solution. When we update to Storybook V5 we will be able to pass data from decorator to story
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { MouseEvent, useContext } from 'react';
|
import React, { MouseEvent } from 'react';
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { CallToActionCard, Icon, IconName, LinkButton, ThemeContext } from '@grafana/ui';
|
import { CallToActionCard, Icon, IconName, LinkButton } from '@grafana/ui';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
@ -39,8 +39,6 @@ const EmptyListCTA: React.FunctionComponent<Props> = ({
|
|||||||
infoBox,
|
infoBox,
|
||||||
infoBoxTitle,
|
infoBoxTitle,
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useContext(ThemeContext);
|
|
||||||
|
|
||||||
const footer = () => {
|
const footer = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -86,15 +84,7 @@ const EmptyListCTA: React.FunctionComponent<Props> = ({
|
|||||||
</LinkButton>
|
</LinkButton>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return <CallToActionCard className={ctaStyle} message={title} footer={footer()} callToActionElement={ctaElement} />;
|
||||||
<CallToActionCard
|
|
||||||
className={ctaStyle}
|
|
||||||
message={title}
|
|
||||||
footer={footer()}
|
|
||||||
callToActionElement={ctaElement}
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EmptyListCTA;
|
export default EmptyListCTA;
|
||||||
|
@ -35,12 +35,6 @@ export const NoDataSourceCallToAction = () => {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CallToActionCard
|
<CallToActionCard callToActionElement={ctaElement} className={cardClassName} footer={footer} message={message} />
|
||||||
callToActionElement={ctaElement}
|
|
||||||
className={cardClassName}
|
|
||||||
footer={footer}
|
|
||||||
message={message}
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user