fbredius/storybook

View on GitHub
lib/ui/src/settings/about.tsx

Summary

Maintainability
A
45 mins
Test Coverage
import React, { Fragment, FunctionComponent } from 'react';
import semver from '@storybook/semver';
import { styled } from '@storybook/theming';
import { State } from '@storybook/api';
import Markdown from 'markdown-to-jsx';

import { StorybookIcon, SyntaxHighlighter, Link, DocumentWrapper } from '@storybook/components';

import SettingsFooter from './SettingsFooter';

const Header = styled.header(({ theme }) => ({
  marginBottom: 20,
  fontSize: theme.typography.size.m3,
  fontWeight: theme.typography.weight.black,
  alignItems: 'center',
  display: 'flex',

  '> svg': {
    height: 32,
    width: 'auto',
    marginRight: 8,
  },
}));

const Subheading = styled.span(({ theme }) => ({
  letterSpacing: '0.35em',
  textTransform: 'uppercase',
  fontWeight: theme.typography.weight.black,
  fontSize: theme.typography.size.s2 - 1,
  lineHeight: '24px',
  color: theme.color.mediumdark,
}));

const SubheadingLink = styled(Link)(({ theme }) => ({
  fontSize: theme.typography.size.s1,
}));

const Subheader = styled.div({
  display: 'flex',
  justifyContent: 'space-between',
  alignItems: 'center',
  marginBottom: '.75rem',
});

const UpdateMessage = styled.div<{ status: 'positive' | 'negative' | string }>(
  ({ status, theme }) => {
    if (status === 'positive') {
      return { background: theme.background.positive, color: theme.color.positive };
    }
    if (status === 'negative') {
      return { background: theme.background.negative, color: theme.color.negative };
    }
    return { background: '#EAF3FC', color: theme.color.darkest };
  },

  ({ theme }) => ({
    fontWeight: theme.typography.weight.bold,
    fontSize: theme.typography.size.s2,
    padding: '10px 20px',
    marginBottom: 24,
    borderRadius: theme.appBorderRadius,
    border: `1px solid ${theme.appBorderColor}`,
    textAlign: 'center',
  })
);

const ErrorMessage = styled.div(({ theme }) => ({
  fontWeight: theme.typography.weight.bold,
  textAlign: 'center',
}));

const Upgrade = styled.div(({ theme }) => ({
  marginTop: 20,
  borderTop: `1px solid ${theme.appBorderColor}`,
}));

const Container = styled.div({
  padding: `3rem 20px`,
  maxWidth: 600,
  margin: '0 auto',
});

const AboutScreen: FunctionComponent<{
  latest: State['versions']['latest'];
  current: State['versions']['current'];
}> = ({ latest = null, current }) => {
  const canUpdate = latest && semver.gt(latest.version, current.version);

  let updateMessage;
  if (latest) {
    if (canUpdate) {
      updateMessage = (
        <UpdateMessage status="positive">
          Storybook {latest.version} is available. Upgrade from {current.version} now.
        </UpdateMessage>
      );
    } else {
      updateMessage = (
        <UpdateMessage status="neutral">Looking good! You're up to date.</UpdateMessage>
      );
    }
  } else {
    updateMessage = (
      <UpdateMessage status="negative">
        Oops! The latest version of Storybook couldn't be fetched.
      </UpdateMessage>
    );
  }

  return (
    <Container>
      <Header>
        <StorybookIcon />
        Storybook {current.version}
      </Header>

      {updateMessage}

      {latest ? (
        <Fragment>
          <Subheader>
            <Subheading>{latest.version} Changelog</Subheading>
            <SubheadingLink
              secondary
              href="https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md"
              withArrow
              cancel={false}
              target="_blank"
            >
              Read full changelog
            </SubheadingLink>
          </Subheader>
          <DocumentWrapper>
            <Markdown>{latest.info.plain}</Markdown>
          </DocumentWrapper>
        </Fragment>
      ) : (
        <ErrorMessage>
          <Link
            href="https://github.com/storybookjs/storybook/releases"
            target="_blank"
            withArrow
            secondary
            cancel={false}
          >
            Check Storybook's release history
          </Link>
        </ErrorMessage>
      )}

      {canUpdate && (
        <Upgrade>
          <DocumentWrapper>
            <p>
              <b>Upgrade all Storybook packages to latest:</b>
            </p>
            <SyntaxHighlighter language="bash" copyable padded bordered>
              npx sb upgrade
            </SyntaxHighlighter>
          </DocumentWrapper>
        </Upgrade>
      )}

      <SettingsFooter />
    </Container>
  );
};

export { AboutScreen };