Skip to content
This repository was archived by the owner on Aug 18, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"remark-html": "^13.0.1",
"request": "^2.88.2",
"semver": "^7.5.2",
"snarkdown": "^2.0.0",
"unist-util-visit": "^2.0.3",
"use-debounce": "^8.0.4",
"usehooks-ts": "^2.9.1",
Expand Down
102 changes: 47 additions & 55 deletions src/components/basics/Callout/Callout.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,70 +4,62 @@ import { styles } from '@storybook/design-system';

import { Callout } from './Callout';

const { spacing } = styles;

const StoryWrapper = styled.div`
padding: ${spacing.padding.medium}px;
`;

export default {
title: 'Basics/Callout',
component: Callout,
parameters: {
chromatic: { viewports: [320, 900] },
},
decorators: [(story) => <StoryWrapper>{story()}</StoryWrapper>],
};

const { typography, spacing } = styles;

const StoryWrapper = styled.div`
padding: ${spacing.padding.medium}px;
`;

const Title = styled.h1`
font-family: ${typography.type};
font-weight: ${typography.weight.bold};
font-size: ${typography.size.s3}px;
line-height: ${typography.size.m3}px;
`;
export const Default = {
args: {
title: "Hello there, I'm a Callout",
children: `I'm here to bring attention to some important information that you might be interested in.`,
},
};

const BodyText = styled.p`
font-family: ${typography.type};
font-size: ${typography.size.s3}px;
line-height: ${typography.size.m3}px;
margin: 0;
`;
export const Variants = {
args: {
...Default.args,
},
render: (args) => (
<>
<Callout {...args} variant="neutral" title="I'm a neutral Callout" />
<br />
<Callout {...args} variant="positive" title="I'm a positive Callout" />
<br />
<Callout {...args} variant="info" title="I'm an Info Callout" />
<br />
<Callout {...args} variant="warning" title="I'm a warning Callout" />
</>
),
};

const Template = (args) => (
<StoryWrapper>
<Callout {...args}>
<Title>👋 Hello there, I'm a Callout</Title>
<BodyText>
I'm here to bring attention to some important information that you might be interested in.
<br />
You can play with the way I look using the prop controls below 👇
</BodyText>
</Callout>
</StoryWrapper>
);
export const WithEmoji = {
args: {
...Default.args,
icon: '👋',
},
};

export const Default = Template.bind({});
export const WithoutTitle = {
args: {
...WithEmoji.args,
title: undefined,
},
};

export const Variants = () => (
<StoryWrapper>
<Callout variant="neutral">
<Title>I'm a neutral Callout</Title>
<BodyText>
I'm here to bring attention to some important information that you might be interested in
</BodyText>
</Callout>
<br />
<Callout variant="positive">
<Title>I'm a positive Callout</Title>
<BodyText>
I'm here to bring attention to some important information that you might be interested in
</BodyText>
</Callout>
<br />
<Callout variant="selected">
<Title>I'm a selected Callout</Title>
<BodyText>
I'm here to bring attention to some important information that you might be interested in
</BodyText>
</Callout>
</StoryWrapper>
);
export const WithMarkdownTitle = {
args: {
...WithEmoji.args,
title: '`next/font` support',
},
};
82 changes: 76 additions & 6 deletions src/components/basics/Callout/Callout.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
import React from 'react';
import snarkdown from 'snarkdown';

import { rgba } from 'polished';
import { styled } from '@storybook/theming';
import { styles } from '@storybook/design-system';

const { spacing, color, background } = styles;
const { spacing, color, background, typography, breakpoint } = styles;

type Variant = 'neutral' | 'positive' | 'selected';
type Variant = 'neutral' | 'positive' | 'info' | 'warning';

const VARIANT_COLORS: Record<Variant, { background: string; border: string }> = {
neutral: { background: color.mediumlight, border: rgba(color.darker, 0.1) },
positive: { background: background.positive, border: rgba(color.positive, 0.1) },
selected: { background: background.calmBlue, border: rgba(color.selected, 0.1) },
info: { background: background.calmBlue, border: rgba(color.selected, 0.1) },
warning: { background: background.warning, border: rgba(color.warning, 0.1) },
};

const VARIANT_DEFAULT_ICON: Partial<Record<Variant, string>> = {
info: 'ℹ️',
warning: '⚠️',
};

export interface CalloutProps {
interface CalloutContainerProps {
variant: Variant;
}
export const Callout = styled.div<CalloutProps>`
const CalloutContainer = styled.div<CalloutContainerProps>`
padding: ${spacing.padding.medium}px;
border-radius: ${spacing.borderRadius.small}px;
display: flex;
flex-direction: row;

${({ variant }) => `
background: ${VARIANT_COLORS[variant].background};
Expand All @@ -30,6 +40,66 @@ export const Callout = styled.div<CalloutProps>`
}
`;

Callout.defaultProps = {
CalloutContainer.defaultProps = {
variant: 'neutral',
};

const CalloutIcon = styled.span`
@media (min-width: ${breakpoint}px) {
margin-right: ${spacing.padding.small}px;
flex: 0 0 auto;
font-size: ${typography.size.m2}px;
display: inline-block;
}
display: none;
`;

CalloutIcon.defaultProps = {
'aria-hidden': true,
};

const CalloutContent = styled.div`
display: flex;
flex-direction: column;
flex: 1;
justify-content: center;
`;

const CalloutTitle = styled.span`
font-family: ${typography.type};
font-weight: ${typography.weight.bold};
font-size: ${typography.size.s3}px;
line-height: ${typography.size.m3}px;
display: block;

code {
color: inherit;
}
`;

const CalloutBodyText = styled.p`
font-family: ${typography.type};
font-size: ${typography.size.s3}px;
line-height: ${typography.size.m3}px;
margin: 0;
`;

export interface CalloutProps extends CalloutContainerProps {
title?: string;
icon?: string;
children: string;
}

export const Callout = ({ title, icon, children, variant, ...props }: CalloutProps) => {
const appliedIcon = icon ?? VARIANT_DEFAULT_ICON[variant];

return (
<CalloutContainer variant={variant} {...props}>
{appliedIcon && <CalloutIcon>{appliedIcon}</CalloutIcon>}
<CalloutContent>
{title && <CalloutTitle dangerouslySetInnerHTML={{ __html: snarkdown(title) }} />}
<CalloutBodyText>{children}</CalloutBodyText>
</CalloutContent>
</CalloutContainer>
);
};
14 changes: 3 additions & 11 deletions src/components/screens/DocsScreen/DocsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { graphql } from 'gatsby';
import { CodeSnippets } from './CodeSnippets';
import { frameworkSupportsFeature, FrameworkSupportTable } from './FrameworkSupportTable';
import { SocialGraph } from '../../basics';
import { Callout } from '../../basics/Callout';
import { Pre } from '../../basics/Pre';
import GatsbyLinkWrapper from '../../basics/GatsbyLinkWrapper';
import useSiteMetadata from '../../lib/useSiteMetadata';
Expand All @@ -36,14 +37,6 @@ const MDWrapper = styled.main`
flex: 1;
`;

const StyledHighlight = styled(Highlight)`
-webkit-text-size-adjust: none;

> * > *:last-child {
margin-bottom: 0;
}
`;

const NextSubheading = styled(Subheading)`
color: ${color.mediumdark};
font-size: ${typography.size.s2}px;
Expand Down Expand Up @@ -235,11 +228,10 @@ function DocsScreen({ data, pageContext, location }) {
IfRenderer: IfRendererWithCurrentFramework,
YouTubeCallout,
a: LinksWithPrefix,
Callout,
}}
>
<StyledHighlight withHTMLChildren={false}>
<MDXRenderer>{body}</MDXRenderer>
</StyledHighlight>
<MDXRenderer>{body}</MDXRenderer>
</MDXProvider>
</MDWrapper>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import { format } from 'date-fns';
import { rgba } from 'polished';
import { styled } from '@storybook/theming';
import { Link as GatsbyLink } from 'gatsby';
import { MDXProvider } from '@mdx-js/react';
Expand All @@ -18,7 +19,7 @@ import {
import { SubNav, SubNavBreadcrumb, SubNavCTA, SubNavRight } from '@storybook/components-marketing';

import useSiteMetadata from '../../../lib/useSiteMetadata';
import { SocialGraph, Callout, Pre } from '../../../basics';
import { SocialGraph, Pre, Callout } from '../../../basics';
import {
IntegrationsAside,
IntegrationsAsideContainer,
Expand All @@ -32,7 +33,7 @@ import { generateBreadcrumb } from '../../../../util/generate-breadcrumb';
import { generateRecipeGithubIssueLink } from './helpers';
import { CodeSnippets } from './CodeSnippets';

const { color, typography, spacing } = styles;
const { color, background, typography, spacing } = styles;

const SectionLinksContainer = styled.div`
margin-bottom: 30px;
Expand All @@ -59,7 +60,18 @@ const ReadMe = styled.section`
min-width: 0;
`;

const AddonsCallout = styled(Callout)`
const AddonsCallout = styled.div`
padding: ${spacing.padding.medium}px;
border-radius: ${spacing.borderRadius.small}px;
display: flex;
flex-direction: column;

background: ${background.positive};
box-shadow: ${rgba(color.positive, 0.1)} 0 0 0 1px inset;
Comment thread
kylegach marked this conversation as resolved.

&& *:last-child {
margin-bottom: 0px;
}
margin-bottom: 40px;
`;

Expand Down Expand Up @@ -247,7 +259,7 @@ export const RecipesDetailScreen = ({ path, location, pageContext }) => {
</span>
{hasAddons && (
<section>
<AddonsCallout variant="positive">
<AddonsCallout>
<WellTitle id="addon-section">Do it for me automatically</WellTitle>
<WellBody>
The quickest way to integrate Storybook and {displayName} is to use an addon.
Expand All @@ -259,12 +271,13 @@ export const RecipesDetailScreen = ({ path, location, pageContext }) => {
</AddonsCallout>
</section>
)}
<ReadMeContent id="recipe-content-body">
<ReadMeContent id="recipe-section">
<MDXProvider
components={{
pre: Pre,
RecipeHeader,
CodeSnippets,
Callout,
}}
>
<StyledHighlight withHTMLChildren={false}>
Expand Down
Loading