storyFile.tsx 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import type {ComponentProps} from 'react';
  2. import styled from '@emotion/styled';
  3. import {LinkButton} from 'sentry/components/button';
  4. import {CopyToClipboardButton} from 'sentry/components/copyToClipboardButton';
  5. import TextOverflow from 'sentry/components/textOverflow';
  6. import {IconGithub} from 'sentry/icons';
  7. import {t} from 'sentry/locale';
  8. import {space} from 'sentry/styles/space';
  9. import type {ResolvedStoryModule} from 'sentry/views/stories/types';
  10. interface Props extends ComponentProps<'div'> {
  11. filename: string;
  12. resolved: ResolvedStoryModule;
  13. }
  14. export default function StoryFile({filename, resolved, style}: Props) {
  15. const {default: DefaultExport, ...otherExports} = resolved;
  16. const otherEntries = Object.entries(otherExports);
  17. const githubViewUrl = `https://github.com/getsentry/sentry/blob/master/static/${filename}`;
  18. const githubEditUrl = `https://github.com/getsentry/sentry/edit/master/static/${filename}`;
  19. return (
  20. <FlexColumn style={style}>
  21. <FlexRow style={{justifyContent: 'space-between'}}>
  22. <FlexRow style={{alignItems: 'center', gap: space(1)}}>
  23. <Header>
  24. <TextOverflow>{filename}</TextOverflow>
  25. </Header>
  26. <CopyToClipboardButton size="xs" iconSize="xs" text={filename} />
  27. </FlexRow>
  28. <FlexRow style={{alignItems: 'center', gap: space(1)}}>
  29. <LinkButton
  30. href={githubViewUrl}
  31. external
  32. icon={<IconGithub />}
  33. size="xs"
  34. aria-label={t('View on GitHub')}
  35. >
  36. {t('View')}
  37. </LinkButton>
  38. <LinkButton
  39. href={githubEditUrl}
  40. external
  41. icon={<IconGithub />}
  42. size="xs"
  43. aria-label={t('Edit on GitHub')}
  44. >
  45. {t('Edit')}
  46. </LinkButton>
  47. </FlexRow>
  48. </FlexRow>
  49. <StoryArea>
  50. {DefaultExport ? <DefaultExport /> : null}
  51. {otherEntries.map(([field, Component]) => (
  52. <Component key={field} />
  53. ))}
  54. </StoryArea>
  55. </FlexColumn>
  56. );
  57. }
  58. const FlexRow = styled('div')`
  59. display: flex;
  60. flex-direction: row;
  61. flex-wrap: wrap;
  62. gap: var(--stories-grid-space);
  63. align-content: flex-start;
  64. `;
  65. const FlexColumn = styled('section')`
  66. display: flex;
  67. flex-direction: column;
  68. gap: var(--stories-grid-space);
  69. max-height: 100%;
  70. `;
  71. const StoryArea = styled('div')`
  72. display: flex;
  73. flex-direction: column;
  74. gap: ${space(4)};
  75. `;
  76. const Header = styled('h2')`
  77. font-family: ${p => p.theme.text.familyMono};
  78. font-size: ${p => p.theme.fontSizeMedium};
  79. font-weight: ${p => p.theme.fontWeightNormal};
  80. margin: 0;
  81. `;