diff --git a/code/ui/.storybook/main.ts b/code/ui/.storybook/main.ts
index 23a70dc16661..541b0f2c69e1 100644
--- a/code/ui/.storybook/main.ts
+++ b/code/ui/.storybook/main.ts
@@ -50,6 +50,7 @@ const config: StorybookConfig = {
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-storysource',
+ '@storybook/addon-designs',
],
framework: {
name: '@storybook/react-vite',
diff --git a/code/ui/components/src/clipboard/ClipboardCode.tsx b/code/ui/components/src/clipboard/ClipboardCode.tsx
new file mode 100644
index 000000000000..577a6674f5d4
--- /dev/null
+++ b/code/ui/components/src/clipboard/ClipboardCode.tsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import { color, styled, typography } from '@storybook/theming';
+
+const Code = styled.pre`
+ line-height: 18px;
+ padding: 11px 1rem;
+ white-space: pre-wrap;
+ background: rgba(0, 0, 0, 0.05);
+ color: ${color.darkest};
+ border-radius: 3px;
+ margin: 1rem 0;
+ width: 100%;
+ display: block;
+ overflow: hidden;
+ font-family: ${typography.fonts.mono};
+ font-size: ${typography.size.s2 - 1}px;
+`;
+
+interface ClipboardCodeProps {
+ code: string;
+}
+
+export const ClipboardCode = ({ code, ...props }: ClipboardCodeProps) => (
+
+ {code}
+
+);
diff --git a/code/ui/components/src/index.ts b/code/ui/components/src/index.ts
index c654094f1b61..292a9c7067dd 100644
--- a/code/ui/components/src/index.ts
+++ b/code/ui/components/src/index.ts
@@ -26,7 +26,6 @@ export { Span } from './typography/elements/Span';
export { Table } from './typography/elements/Table';
export { TT } from './typography/elements/TT';
export { UL } from './typography/elements/UL';
-
export { Badge } from './Badge/Badge';
// Typography
@@ -85,6 +84,8 @@ export * from './typography/ResetWrapper';
export { withReset, codeCommon } from './typography/lib/common';
+export { ClipboardCode } from './clipboard/ClipboardCode';
+
// eslint-disable-next-line prefer-destructuring
export const components = typography.components;
diff --git a/code/ui/manager/package.json b/code/ui/manager/package.json
index b23ddccb7d87..4674a01f8345 100644
--- a/code/ui/manager/package.json
+++ b/code/ui/manager/package.json
@@ -51,6 +51,7 @@
},
"devDependencies": {
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
+ "@storybook/addon-designs": "^7.0.0",
"@storybook/addons": "7.1.0-beta.2",
"@storybook/api": "7.1.0-beta.2",
"@storybook/channel-postmessage": "7.1.0-beta.2",
diff --git a/code/ui/manager/src/globals/exports.ts b/code/ui/manager/src/globals/exports.ts
index 0e8fa703c97a..473867f750c0 100644
--- a/code/ui/manager/src/globals/exports.ts
+++ b/code/ui/manager/src/globals/exports.ts
@@ -54,6 +54,7 @@ export default {
'Bar',
'Blockquote',
'Button',
+ 'ClipboardCode',
'Code',
'DL',
'Div',
diff --git a/code/ui/manager/src/settings/about.stories.jsx b/code/ui/manager/src/settings/about.stories.jsx
deleted file mode 100644
index 7bb06a45ad0b..000000000000
--- a/code/ui/manager/src/settings/about.stories.jsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import React from 'react';
-import { actions as createActions } from '@storybook/addon-actions';
-
-import { AboutScreen } from './about';
-
-const info = {
- plain: `- upgrade webpack & babel to latest\n- new addParameters and third argument to .add to pass data to addons\n- added the ability to theme storybook\n- improved ui for mobile devices\n- improved performance of addon-knobs`,
-};
-
-export default {
- component: AboutScreen,
- title: 'Settings/AboutScreen',
- decorators: [
- (storyFn) => (
-
- {storyFn()}
-
- ),
- ],
-};
-
-const actions = createActions('onClose');
-
-export const UpToDate = () => (
-
-);
-
-export const OldVersionRaceCondition = () => (
-
-);
-
-export const NewVersionRequired = () => (
-
-);
-
-export const FailedToFetchNewVersion = () => (
-
-);
diff --git a/code/ui/manager/src/settings/about.stories.tsx b/code/ui/manager/src/settings/about.stories.tsx
new file mode 100644
index 000000000000..67fcabcf6667
--- /dev/null
+++ b/code/ui/manager/src/settings/about.stories.tsx
@@ -0,0 +1,39 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import React from 'react';
+import { AboutScreen } from './about';
+
+const meta = {
+ component: AboutScreen,
+ title: 'Settings/AboutScreen',
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+} satisfies Meta;
+
+export default meta;
+
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ current: {
+ version: '7.0.1',
+ },
+ },
+ parameters: {
+ design: {
+ type: 'figma',
+ url: 'https://www.figma.com/file/ur4kydUbRqdDyfoZWzdiIw/Storybook-app?type=design&node-id=9564-120444&mode=design&t=0TPINZFpwgFQFQeX-4',
+ },
+ },
+};
diff --git a/code/ui/manager/src/settings/about.tsx b/code/ui/manager/src/settings/about.tsx
index fccd4ee15111..cdb0db8c2a73 100644
--- a/code/ui/manager/src/settings/about.tsx
+++ b/code/ui/manager/src/settings/about.tsx
@@ -1,114 +1,159 @@
+/* eslint-disable no-nested-ternary */
import type { FC } from 'react';
-import React from 'react';
-import semver from 'semver';
+import React, { useState } from 'react';
import { styled } from '@storybook/theming';
import type { State } from '@storybook/manager-api';
-import { StorybookIcon, SyntaxHighlighter, DocumentWrapper } from '@storybook/components';
-
-import SettingsFooter from './SettingsFooter';
+import { Button as BaseButton, Icons, Link, StorybookIcon } from '@storybook/components';
const Header = styled.header(({ theme }) => ({
- marginBottom: 20,
- fontSize: theme.typography.size.m3,
+ marginBottom: 32,
+ fontSize: theme.typography.size.l2,
color: theme.base === 'light' ? theme.color.darkest : theme.color.lightest,
fontWeight: theme.typography.weight.bold,
alignItems: 'center',
display: 'flex',
'> svg': {
- height: 32,
+ height: 48,
width: 'auto',
marginRight: 8,
},
}));
-const UpdateMessage = styled.div<{ status: 'positive' | 'negative' | string }>(
- ({ status, theme }) => {
- if (status === 'positive') {
- return { background: theme.background.positive, color: theme.color.positiveText };
- }
- if (status === 'negative') {
- return { background: theme.background.negative, color: theme.color.negativeText };
- }
- return {
- background: theme.base === 'light' ? '#EAF3FC' : theme.color.darkest,
- color: theme.base === 'light' ? theme.color.darkest : theme.defaultText,
- };
- },
+const Container = styled.div({
+ display: `flex`,
+ alignItems: 'center',
+ justifyContent: 'center',
+ height: 'calc(100% - 40px)',
+ flexDirection: 'column',
+});
- ({ theme }) => ({
- fontWeight: theme.typography.weight.bold,
+const UpgradeBlock = styled.div(({ theme }) => {
+ return {
+ border: '1px solid',
+ borderRadius: 5,
+ padding: 20,
+ margin: 20,
+ maxWidth: 400,
+ borderColor: theme.appBorderColor,
fontSize: theme.typography.size.s2,
- padding: '10px 20px',
- marginBottom: 24,
- borderRadius: theme.appBorderRadius,
- border: `1px solid ${theme.appBorderColor}`,
- textAlign: 'center',
- })
-);
+ };
+});
-const Upgrade = styled.div(({ theme }) => ({
- marginTop: 20,
- borderTop: `1px solid ${theme.appBorderColor}`,
+const Code = styled.pre(({ theme }) => ({
+ background: theme.base === 'light' ? 'rgba(0, 0, 0, 0.05)' : theme.appBorderColor,
+ fontSize: theme.typography.size.s2 - 1,
+ margin: '4px 0 16px',
}));
-const Container = styled.div({
- padding: `3rem 20px`,
- maxWidth: 600,
- margin: '0 auto',
-});
+const Footer = styled.div(({ theme }) => ({
+ marginBottom: 24,
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ color: theme.base === 'light' ? theme.color.dark : theme.color.lightest,
+ fontWeight: theme.typography.weight.regular,
+ fontSize: theme.typography.size.s2,
+}));
-const AboutScreen: FC<{
- latest: State['versions']['latest'];
- current: State['versions']['current'];
-}> = ({ latest = null, current }) => {
- const canUpdate = latest && semver.gt(latest.version, current.version);
+const SquareButton = styled(BaseButton)(({ theme }) => ({
+ '&&': {
+ borderRadius: 4,
+ fontSize: '13px',
+ lineHeight: '14px',
+ color: theme.base === 'light' ? theme.color.darker : theme.color.lightest,
+ padding: '9px 12px',
+ svg: {
+ marginRight: 6,
+ },
+ },
+}));
+
+const TabButton = styled(BaseButton)<{ active: boolean }>(({ theme, active }) => ({
+ '&&': {
+ padding: 2,
+ paddingRight: 8,
+ margin: 0,
+ color: active
+ ? theme.color.secondary
+ : theme.base === 'light'
+ ? theme.color.dark
+ : theme.color.lightest,
+ },
+}));
- let updateMessage;
- if (latest) {
- if (canUpdate) {
- updateMessage = (
-
- Storybook {latest.version} is available. Upgrade from {current.version} now.
-
- );
- } else {
- updateMessage = (
- Looking good! You're up to date.
- );
- }
- } else {
- updateMessage = (
-
- Oops! The latest version of Storybook couldn't be fetched.
-
- );
- }
+const StyledLink = styled(Link as any)(({ theme }) => ({
+ '&&': {
+ fontWeight: theme.typography.weight.bold,
+ color: theme.base === 'light' ? theme.color.dark : theme.color.light,
+ },
+ '&:hover': {
+ color: theme.base === 'light' ? theme.color.darkest : theme.color.lightest,
+ },
+}));
+const AboutScreen: FC<{
+ current: State['versions']['current'];
+ onNavigateToWhatsNew?: () => void;
+}> = ({ current, onNavigateToWhatsNew }) => {
+ const [activeTab, setActiveTab] = useState<'npm' | 'pnpm'>('npm');
return (
+
-
- Storybook {current.version}
+ Storybook
+
+ You are on Storybook {current.version}
+ Run the following script to check for updates and upgrade to the latest version.
+
+ setActiveTab('npm')}>
+ npm
+
+ setActiveTab('pnpm')}>
+ pnpm
+
+
- {updateMessage}
+
+ {activeTab === 'npm'
+ ? 'npx storybook@latest upgrade'
+ : 'pnpm dlx storybook@latest upgrade'}
+
+ {onNavigateToWhatsNew && (
+ // eslint-disable-next-line jsx-a11y/anchor-is-valid
+ See what's new in Storybook
+ )}
+
- {canUpdate && (
-
-
-
- Upgrade all Storybook packages to latest:
-
-
- npx storybook@latest upgrade
-
-
-
- )}
+
+
);
};
diff --git a/code/ui/manager/src/settings/about_page.tsx b/code/ui/manager/src/settings/about_page.tsx
index 34640957ad18..e20d89d5362a 100644
--- a/code/ui/manager/src/settings/about_page.tsx
+++ b/code/ui/manager/src/settings/about_page.tsx
@@ -1,7 +1,7 @@
import type { FC } from 'react';
-import React, { Component } from 'react';
+import React, { Component, useCallback } from 'react';
-import { type API, useStorybookApi } from '@storybook/manager-api';
+import { type API, useStorybookApi, useStorybookState } from '@storybook/manager-api';
import { AboutScreen } from './about';
@@ -20,10 +20,19 @@ class NotificationClearer extends Component<{ api: API; notificationId: string }
const AboutPage: FC = () => {
const api = useStorybookApi();
+ const state = useStorybookState();
+ const onNavigateToWhatsNew = useCallback(() => {
+ api.changeSettingsTab('whats-new');
+ }, [api]);
return (
-
+
);
};
diff --git a/code/ui/manager/src/settings/whats_new.tsx b/code/ui/manager/src/settings/whats_new.tsx
index a033f3b7ffe9..4f0b5072259e 100644
--- a/code/ui/manager/src/settings/whats_new.tsx
+++ b/code/ui/manager/src/settings/whats_new.tsx
@@ -37,7 +37,7 @@ const Iframe = styled.iframe<{ isLoaded: boolean }>(
margin: 0,
padding: 0,
width: '100%',
- height: '100%',
+ height: 'calc(100% - 40px)',
},
({ isLoaded }) => ({ visibility: isLoaded ? 'visible' : 'hidden' })
);
diff --git a/code/yarn.lock b/code/yarn.lock
index 381fc4bbd01f..ff6efb4439b5 100644
--- a/code/yarn.lock
+++ b/code/yarn.lock
@@ -2922,6 +2922,27 @@ __metadata:
languageName: node
linkType: hard
+"@figspec/components@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "@figspec/components@npm:1.0.1"
+ dependencies:
+ lit: ^2.1.3
+ checksum: 74e2c4c6959355efc5d89f224b32ed8207c4885b7d4bbdc2c7c9de6e5ef3e5b80a553fc26ca51eac77b03b6414ec645b147ba64211cf1165e2bcce49ced67fc8
+ languageName: node
+ linkType: hard
+
+"@figspec/react@npm:^1.0.0":
+ version: 1.0.3
+ resolution: "@figspec/react@npm:1.0.3"
+ dependencies:
+ "@figspec/components": ^1.0.1
+ "@lit-labs/react": ^1.0.2
+ peerDependencies:
+ react: ^16.14.0 || ^17.0.0 || ^18.0.0
+ checksum: d5bbb79e106f522f5b867d0f55de01391edd1011e3f5d5a966ac07a5fca75f499d1d4d40a6186cf0afdc4fc4b49d808eb5d4fcbaf1784401a1ace2865dbc19be
+ languageName: node
+ linkType: hard
+
"@gar/promisify@npm:^1.1.3":
version: 1.1.3
resolution: "@gar/promisify@npm:1.1.3"
@@ -3912,6 +3933,13 @@ __metadata:
languageName: node
linkType: hard
+"@lit-labs/react@npm:^1.0.2":
+ version: 1.2.1
+ resolution: "@lit-labs/react@npm:1.2.1"
+ checksum: c92364101348400a06c3eb45a6384ca7d47c32765fdcad892827b360d0bad6cef7916f9a17744f2f471a5da3d7d73750767b885fc1521cd5e5e724badb71f014
+ languageName: node
+ linkType: hard
+
"@lit-labs/ssr-dom-shim@npm:^1.0.0, @lit-labs/ssr-dom-shim@npm:^1.1.0":
version: 1.1.1
resolution: "@lit-labs/ssr-dom-shim@npm:1.1.1"
@@ -3919,7 +3947,7 @@ __metadata:
languageName: node
linkType: hard
-"@lit/reactive-element@npm:^1.3.0, @lit/reactive-element@npm:^1.4.0":
+"@lit/reactive-element@npm:^1.3.0, @lit/reactive-element@npm:^1.4.0, @lit/reactive-element@npm:^1.6.0":
version: 1.6.2
resolution: "@lit/reactive-element@npm:1.6.2"
dependencies:
@@ -5237,6 +5265,29 @@ __metadata:
languageName: unknown
linkType: soft
+"@storybook/addon-designs@npm:^7.0.0":
+ version: 7.0.0
+ resolution: "@storybook/addon-designs@npm:7.0.0"
+ dependencies:
+ "@figspec/react": ^1.0.0
+ peerDependencies:
+ "@storybook/addon-docs": ^7.0.0
+ "@storybook/addons": ^7.0.0
+ "@storybook/components": ^7.0.0
+ "@storybook/manager-api": ^7.0.0
+ "@storybook/preview-api": ^7.0.0
+ "@storybook/theming": ^7.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ checksum: 7e532334ddd94051e4ada81fffc75ad17f955e5c1a2b1c03a7c6895000b1bade18906069497e4e8cdad960da650273fd95ca9ed6f5cfaad365c4d60bd640438a
+ languageName: node
+ linkType: hard
+
"@storybook/addon-docs@7.1.0-beta.2, @storybook/addon-docs@workspace:*, @storybook/addon-docs@workspace:addons/docs":
version: 0.0.0-use.local
resolution: "@storybook/addon-docs@workspace:addons/docs"
@@ -6509,6 +6560,7 @@ __metadata:
resolution: "@storybook/manager@workspace:ui/manager"
dependencies:
"@fal-works/esbuild-plugin-global-externals": ^2.1.2
+ "@storybook/addon-designs": ^7.0.0
"@storybook/addons": 7.1.0-beta.2
"@storybook/api": 7.1.0-beta.2
"@storybook/channel-postmessage": 7.1.0-beta.2
@@ -20571,7 +20623,7 @@ __metadata:
languageName: node
linkType: hard
-"lit-element@npm:^3.2.0":
+"lit-element@npm:^3.2.0, lit-element@npm:^3.3.0":
version: 3.3.2
resolution: "lit-element@npm:3.3.2"
dependencies:
@@ -20602,6 +20654,17 @@ __metadata:
languageName: node
linkType: hard
+"lit@npm:^2.1.3":
+ version: 2.7.6
+ resolution: "lit@npm:2.7.6"
+ dependencies:
+ "@lit/reactive-element": ^1.6.0
+ lit-element: ^3.3.0
+ lit-html: ^2.7.0
+ checksum: bfd629c6eff8e6086200d0c0904c7a20a4d1dab21d1016d40cc8591d00d972171537e8466ca4eae8c5f227f2c5d2ef2ab9a9fe3587e024a493c93614c928b6fe
+ languageName: node
+ linkType: hard
+
"load-json-file@npm:6.2.0":
version: 6.2.0
resolution: "load-json-file@npm:6.2.0"