1import { css } from '@emotion/react';
2import { breakpoints, spacing } from '@expo/styleguide-base';
3import { PropsWithChildren } from 'react';
4
5import { Snippet } from '~/ui/components/Snippet/Snippet';
6import { SnippetContent } from '~/ui/components/Snippet/SnippetContent';
7import { SnippetHeader } from '~/ui/components/Snippet/SnippetHeader';
8
9const MDX_CLASS_NAME_TO_TAB_NAME: Record<string, string> = {
10  'language-swift': 'Swift',
11  'language-kotlin': 'Kotlin',
12  'language-javascript': 'JavaScript',
13  'language-typescript': 'TypeScript',
14  'language-json': 'JSON',
15  'language-ruby': 'Ruby',
16  'language-groovy': 'Gradle',
17};
18
19type Props = PropsWithChildren<{
20  tabs?: string[];
21  connected?: boolean;
22}>;
23
24export function CodeBlocksTable({ children, tabs, connected = true, ...rest }: Props) {
25  const childrenArray = Array.isArray(children) ? children : [children];
26  const codeBlocks = childrenArray.filter(
27    ({ props }) =>
28      props.children.props.className && props.children.props.className.startsWith('language-')
29  );
30  const tabNames =
31    tabs ||
32    codeBlocks.map(child => {
33      const className = child.props.children.props.className;
34      return MDX_CLASS_NAME_TO_TAB_NAME[className] || className.replace('language-', '');
35    });
36
37  return (
38    <div css={[codeBlocksWrapperStyle, connected && codeBlockConnectedWrapperStyle]} {...rest}>
39      {codeBlocks.map((codeBlock, index) => (
40        <Snippet key={index} css={snippetWrapperStyle}>
41          <SnippetHeader title={tabNames[index]} />
42          <SnippetContent className="p-0">{codeBlock}</SnippetContent>
43        </Snippet>
44      ))}
45    </div>
46  );
47}
48
49const codeBlocksWrapperStyle = css({
50  display: 'grid',
51  gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)',
52  gap: spacing[4],
53  gridAutoRows: '1fr',
54
55  pre: {
56    border: 0,
57    margin: 0,
58    gridTemplateRows: 'minmax(100px, 1fr)',
59    height: '100%',
60  },
61
62  [`@media screen and (max-width: ${breakpoints.large}px)`]: {
63    gridTemplateColumns: 'minmax(0, 1fr)',
64    gridAutoRows: 'auto',
65  },
66});
67
68const codeBlockConnectedWrapperStyle = css({
69  [`@media screen and (min-width: ${breakpoints.large}px)`]: {
70    gridGap: 0,
71
72    '> div:nth-of-type(odd)': {
73      '> div': {
74        borderRight: 0,
75        borderTopRightRadius: 0,
76        borderBottomRightRadius: 0,
77      },
78    },
79
80    '> div:nth-of-type(even)': {
81      '> div': {
82        borderTopLeftRadius: 0,
83        borderBottomLeftRadius: 0,
84      },
85    },
86  },
87});
88
89const snippetWrapperStyle = css({
90  [`@media screen and (max-width: ${breakpoints.large}px)`]: {
91    marginBottom: 0,
92
93    '&:last-of-type': {
94      marginBottom: spacing[4],
95    },
96  },
97});
98