images.stories.tsx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import {useEffect, useState} from 'react';
  2. import styled from '@emotion/styled';
  3. import SizingWindow from 'sentry/components/stories/sizingWindow';
  4. import TextOverflow from 'sentry/components/textOverflow';
  5. import {Tooltip} from 'sentry/components/tooltip';
  6. import storyBook from 'sentry/stories/storyBook';
  7. import {space} from 'sentry/styles/space';
  8. const toCamelCase = function camalize(str: any) {
  9. return str
  10. .toLowerCase()
  11. .replace(/[^a-zA-Z0-9]+(.)/g, (_m: any, chr: any) => chr.toUpperCase());
  12. };
  13. const nameOfFile = (file: string) => {
  14. return file.split('/').at(-1)?.split('.').at(0);
  15. };
  16. function imagesContext() {
  17. const context = require.context('sentry-images', true, /\.(svg|gif|png)$/, 'lazy');
  18. return {
  19. files: () =>
  20. context.keys().map((file: any) => file.replace(/^\.\//, 'sentry-images/')),
  21. importImage: (filename: string) =>
  22. context(filename.replace(/^sentry-images\//, './')),
  23. };
  24. }
  25. function LazyImage({file, module}: {file: string; module: Promise<string>}) {
  26. const [imgSrc, setImgSrc] = useState<string | undefined>(undefined);
  27. useEffect(() => {
  28. module.then(mod => {
  29. setImgSrc(mod);
  30. });
  31. }, [module]);
  32. return (
  33. <SizingWindow>
  34. <img alt={file} src={imgSrc ?? ''} />
  35. </SizingWindow>
  36. );
  37. }
  38. export default storyBook('sentry-image/*', story => {
  39. const context = imagesContext();
  40. const allFiles = context.files();
  41. const spotImages: string[] = [];
  42. const patternImages: string[] = [];
  43. const otherImages: string[] = [];
  44. allFiles.forEach((file: any) => {
  45. if (file.startsWith('sentry-images/spot/')) {
  46. spotImages.push(file);
  47. } else if (file.startsWith('sentry-images/pattern/')) {
  48. patternImages.push(file);
  49. } else {
  50. otherImages.push(file);
  51. }
  52. });
  53. const section = (title: string, images: string[]) => {
  54. story(title, () => (
  55. <Grid>
  56. {images.map(file => (
  57. <GridCell key={file}>
  58. <Tooltip
  59. isHoverable
  60. title={`import ${toCamelCase(nameOfFile(file))} from '${file}';`}
  61. >
  62. <TextOverflow>
  63. <code>{nameOfFile(file)}</code>
  64. </TextOverflow>
  65. <LazyImage file={file} module={context.importImage(file)} />
  66. </Tooltip>
  67. </GridCell>
  68. ))}
  69. </Grid>
  70. ));
  71. };
  72. section('sentry-images/spot/*', spotImages);
  73. section('sentry-images/pattern/*', patternImages);
  74. section('Other', otherImages);
  75. });
  76. const Grid = styled('ul')`
  77. display: grid;
  78. grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  79. grid-template-rows: masonry;
  80. gap: ${space(1)};
  81. align-items: flex-start;
  82. margin: 0;
  83. padding: 0;
  84. & > li {
  85. margin: 0;
  86. padding: 0;
  87. list-style: none;
  88. }
  89. `;
  90. const GridCell = styled('li')`
  91. display: flex;
  92. align-content: flex-start;
  93. `;