Skip to content
This repository was archived by the owner on May 4, 2023. It is now read-only.

Commit bdf3bd4

Browse files
chore: put Code components into their own folder
1 parent 78dd08c commit bdf3bd4

File tree

3 files changed

+340
-0
lines changed

3 files changed

+340
-0
lines changed

src/renderer/components/Code/Code.tsx

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import {
2+
Flex,
3+
LinkBox,
4+
IconButton,
5+
useClipboard,
6+
useColorModeValue,
7+
useToken,
8+
Tooltip,
9+
Text,
10+
Link,
11+
Box,
12+
} from '@chakra-ui/react';
13+
import {
14+
BubbleIcon,
15+
Code as CodigaCode,
16+
CodeContent,
17+
CopyIcon,
18+
useToast,
19+
} from '@codiga/components';
20+
import { useEffect } from 'react';
21+
import useCodeView, { CodeViewsType } from '../../hooks/useCodeView';
22+
import { APP_URL } from '../../lib/config';
23+
import { AssistantRecipeWithStats } from '../../types/assistantTypes';
24+
import { decodeIndent } from '../../utils/codeUtils';
25+
import CodeViewToggler from './CodeViewToggler';
26+
27+
type CodeProps = {
28+
recipe: AssistantRecipeWithStats;
29+
};
30+
31+
export default function Code({ recipe }: CodeProps) {
32+
const toast = useToast();
33+
const [codeView, setCodeView] = useCodeView('preview');
34+
35+
const neutral100 = useToken('colors', 'neutral.100');
36+
const bg = useColorModeValue('white', neutral100);
37+
38+
const code =
39+
codeView === 'preview'
40+
? decodeIndent(recipe?.presentableFormat)
41+
: decodeIndent(recipe?.code);
42+
const imports = recipe?.imports?.join('\n');
43+
const codeForCopy = imports ? `${imports}\n${code}` : code;
44+
45+
const { hasCopied, onCopy } = useClipboard(codeForCopy);
46+
47+
useEffect(() => {
48+
if (hasCopied) {
49+
toast({ status: 'success', description: 'Snippet copied' });
50+
}
51+
}, [hasCopied, toast]);
52+
53+
const commentsCount = Number(recipe.commentsCount);
54+
const lines = code.split('\n').length;
55+
const lineMaxDigits = lines.toString().length;
56+
const minWidth = lineMaxDigits < 3 ? '2.7em' : `${lineMaxDigits}.25em`;
57+
58+
return (
59+
<Flex
60+
position="relative"
61+
flex={1}
62+
h="full"
63+
w="full"
64+
overflowX="auto"
65+
overflowY="scroll"
66+
>
67+
<Box
68+
position="absolute"
69+
top="0"
70+
left="0"
71+
minHeight="full"
72+
minWidth="full"
73+
h="full"
74+
w="full"
75+
>
76+
<LinkBox
77+
as="article"
78+
w="full"
79+
minH="full"
80+
overflow="hidden"
81+
borderWidth="1px"
82+
borderStyle="solid"
83+
borderColor="neutral.50"
84+
_dark={{
85+
borderColor: 'base.onyx',
86+
}}
87+
>
88+
<CodigaCode
89+
border={0}
90+
borderRadius={0}
91+
pt="space_48"
92+
pos="relative"
93+
sx={{
94+
'code[class*="language-"] > span:first-child > .linenumber:first-child':
95+
{
96+
paddingTop: '0.5em !important',
97+
},
98+
'code[class*="language-"] .linenumber': {
99+
border: '0 !important',
100+
background: 'transparent !important',
101+
fontStyle: 'normal !important',
102+
},
103+
}}
104+
>
105+
<Flex
106+
pos="absolute"
107+
alignItems="center"
108+
gridGap="space_8"
109+
top="space_8"
110+
right="space_8"
111+
zIndex="docked"
112+
>
113+
<CodeViewToggler
114+
inputProps={{
115+
value: codeView,
116+
onChange: (value) => setCodeView(value as CodeViewsType),
117+
}}
118+
/>
119+
120+
<Tooltip label="Copy Snippet">
121+
<IconButton
122+
variant="ghost"
123+
h="32px"
124+
minW="32px"
125+
p="space_8"
126+
icon={<CopyIcon />}
127+
onClick={onCopy}
128+
aria-label="Copy Snippet"
129+
/>
130+
</Tooltip>
131+
132+
<Tooltip label="Comment on Snippet">
133+
<IconButton
134+
as={Link}
135+
isExternal
136+
href={`${APP_URL}/assistant/snippet/${recipe.id}/view`}
137+
variant="ghost"
138+
h="32px"
139+
minW="32px"
140+
p="space_8"
141+
icon={
142+
<Flex gridGap="space_4" alignItems="center">
143+
<BubbleIcon />
144+
<Text as="span" size="xs" lineHeight="16px">
145+
{commentsCount}
146+
</Text>
147+
</Flex>
148+
}
149+
aria-label="Comment on Snippet"
150+
/>
151+
</Tooltip>
152+
</Flex>
153+
154+
<CodeContent
155+
customStyle={{
156+
background: bg,
157+
overflowX: 'auto',
158+
}}
159+
codeTagProps={{
160+
style: {
161+
display: 'block',
162+
height: '100%',
163+
fontSize: '14px',
164+
},
165+
}}
166+
lineNumberStyle={{ minWidth }}
167+
language={recipe.language?.toLocaleLowerCase()}
168+
>
169+
{code}
170+
</CodeContent>
171+
</CodigaCode>
172+
</LinkBox>
173+
</Box>
174+
</Flex>
175+
);
176+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { Flex, Skeleton, VStack } from '@chakra-ui/react';
2+
3+
export default function CodeLoading() {
4+
return (
5+
<Flex
6+
flex={1}
7+
pos="relative"
8+
overflow="scroll"
9+
h="full"
10+
border="1px"
11+
borderColor="neutral.50"
12+
_dark={{
13+
borderColor: 'base.onyx',
14+
}}
15+
>
16+
<Flex
17+
pos="absolute"
18+
alignItems="center"
19+
gridGap="space_8"
20+
top="space_8"
21+
right="space_8"
22+
zIndex="docked"
23+
>
24+
<Skeleton h="28px" w="100px" />
25+
<Skeleton h="32px" w="32px" />
26+
<Skeleton h="32px" w="43px" />
27+
</Flex>
28+
29+
<VStack
30+
p="space_16"
31+
pt="space_56"
32+
w="full"
33+
spacing="space_8"
34+
alignItems="flex-start"
35+
>
36+
<Skeleton h="16px" w="60%" />
37+
<Skeleton h="16px" w="40%" />
38+
<Skeleton h="16px" w="0%" />
39+
<Skeleton h="16px" w="30%" />
40+
<Skeleton h="16px" w="40%" />
41+
<Skeleton h="16px" w="60%" />
42+
<Skeleton h="16px" w="70%" />
43+
<Skeleton h="16px" w="80%" />
44+
<Skeleton h="16px" w="75%" />
45+
<Skeleton h="16px" w="65%" />
46+
<Skeleton h="16px" w="50%" />
47+
<Skeleton h="16px" w="60%" />
48+
<Skeleton h="16px" w="50%" />
49+
<Skeleton h="16px" w="30%" />
50+
<Skeleton h="16px" w="20%" />
51+
</VStack>
52+
</Flex>
53+
);
54+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import {
2+
Box,
3+
BoxProps,
4+
useRadio,
5+
useRadioGroup,
6+
UseRadioGroupProps,
7+
UseRadioProps,
8+
} from '@chakra-ui/react';
9+
10+
const RadioButton = ({
11+
children,
12+
inputProps,
13+
...props
14+
}: BoxProps & { inputProps: UseRadioProps }) => {
15+
const { getInputProps, getCheckboxProps } = useRadio(inputProps);
16+
17+
const input = getInputProps();
18+
const checkbox = getCheckboxProps();
19+
20+
return (
21+
<Box
22+
as="label"
23+
sx={{
24+
_first: {
25+
'& div': {
26+
borderLeftRadius: 'sm',
27+
},
28+
},
29+
_last: {
30+
'& div': {
31+
borderRightRadius: 'sm',
32+
},
33+
},
34+
}}
35+
pos="relative"
36+
{...props}
37+
>
38+
<input {...input} />
39+
<Box
40+
{...checkbox}
41+
cursor="pointer"
42+
px="space_8"
43+
py="space_4"
44+
fontSize="12px"
45+
lineHeight="20px"
46+
textTransform="capitalize"
47+
color="neutral.100"
48+
bg="neutral.0"
49+
tabIndex={0}
50+
_checked={{
51+
bg: 'neutral.50',
52+
}}
53+
_focus={{
54+
boxShadow: 'outline',
55+
}}
56+
_focusVisible={{
57+
boxShadow: 'outline',
58+
outline: 0,
59+
}}
60+
_dark={{
61+
color: 'neutral.0',
62+
bg: 'neutral.100',
63+
_checked: {
64+
bg: 'base.onyx',
65+
},
66+
}}
67+
>
68+
{children}
69+
</Box>
70+
</Box>
71+
);
72+
};
73+
74+
const CodeViewToggler = ({
75+
inputProps,
76+
...props
77+
}: BoxProps & { inputProps: UseRadioGroupProps }) => {
78+
const options = ['raw', 'preview'];
79+
80+
const { getRootProps, getRadioProps } = useRadioGroup({
81+
name: 'code-view',
82+
...inputProps,
83+
});
84+
85+
const group = getRootProps();
86+
87+
return (
88+
<Box
89+
{...props}
90+
{...group}
91+
borderRadius="base"
92+
borderWidth="1px"
93+
borderStyle="solid"
94+
borderColor="neutral.50"
95+
_dark={{ borderColor: 'base.onyx' }}
96+
>
97+
{options.map((value) => {
98+
const radio = getRadioProps({ value });
99+
100+
return (
101+
<RadioButton key={value} inputProps={radio}>
102+
{value}
103+
</RadioButton>
104+
);
105+
})}
106+
</Box>
107+
);
108+
};
109+
110+
export default CodeViewToggler;

0 commit comments

Comments
 (0)