Skip to content

Commit 7ed719b

Browse files
committed
PEER-219: Add Attempt Details UI final touches
Signed-off-by: SeeuSim <[email protected]>
1 parent 8089688 commit 7ed719b

File tree

7 files changed

+364
-12
lines changed

7 files changed

+364
-12
lines changed

frontend/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"react-katex": "^3.0.1",
4949
"react-markdown": "^9.0.1",
5050
"react-router-dom": "^6.26.2",
51+
"react-syntax-highlighter": "^15.6.1",
5152
"rehype-katex": "^7.0.1",
5253
"remark-gfm": "^4.0.0",
5354
"remark-math": "^6.0.0",
@@ -68,6 +69,7 @@
6869
"@types/node": "^22.5.5",
6970
"@types/react": "^18.3.3",
7071
"@types/react-dom": "^18.3.0",
72+
"@types/react-syntax-highlighter": "^15.5.13",
7173
"@types/ws": "^8.5.12",
7274
"@vitejs/plugin-react-swc": "^3.5.0",
7375
"autoprefixer": "^10.4.20",
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Check, Copy } from 'lucide-react';
2+
import { FC, useState } from 'react';
3+
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
4+
import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
5+
6+
import { Button } from '@/components/ui/button';
7+
8+
type ICodeProps = {
9+
code: string;
10+
language: string;
11+
};
12+
13+
const defaultCopyCodeText = 'Copy Code';
14+
15+
export const CodeViewer: FC<ICodeProps> = ({ code, language }) => {
16+
const [copyCodeText, setCopyCodeText] = useState('Copy Code');
17+
18+
const onCopy = () => {
19+
navigator.clipboard.writeText(code);
20+
setCopyCodeText('Copied!');
21+
setTimeout(() => {
22+
setCopyCodeText(defaultCopyCodeText);
23+
}, 3000);
24+
};
25+
26+
return (
27+
<div className='flex size-full flex-col overflow-y-auto rounded-md'>
28+
<div className='bg-muted-foreground text-muted dark:bg-muted dark:text-muted-foreground flex w-full items-center justify-between px-3 py-2'>
29+
<span className='text-sm font-medium'>{language}</span>
30+
<Button
31+
variant='secondary'
32+
size='sm'
33+
onClick={onCopy}
34+
className='border-border dark:text-muted-foreground text-muted hover:text-primary dark:hover:bg-primary/10 group flex items-center gap-2 bg-inherit disabled:cursor-not-allowed'
35+
>
36+
<span>{copyCodeText}</span>
37+
{copyCodeText === defaultCopyCodeText ? (
38+
<Copy className='size-3' />
39+
) : (
40+
<Check className='size-3 text-green-400 group-hover:text-green-700' />
41+
)}
42+
</Button>
43+
</div>
44+
<SyntaxHighlighter
45+
customStyle={{
46+
borderRadius: '0 0 0.3em 0.3em',
47+
margin: 0,
48+
minHeight: '100px',
49+
}}
50+
PreTag='div'
51+
style={oneDark}
52+
language={language}
53+
>
54+
{code}
55+
</SyntaxHighlighter>
56+
</div>
57+
);
58+
};

frontend/src/components/blocks/interview/question-attempts/attempt-details/main.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
} from '@/components/ui/dialog';
1212
import { IQuestionAttempt } from '@/types/question-types';
1313

14+
import { CodeViewer } from './code-viewer';
15+
1416
type AttemptDetailsPaneProps = {
1517
triggerText: string;
1618
} & IQuestionAttempt;
@@ -29,14 +31,18 @@ export const AttemptDetailsDialog: FC<PropsWithChildren<AttemptDetailsPaneProps>
2931
) : (
3032
<DialogTrigger>{triggerText}</DialogTrigger>
3133
)}
32-
<DialogContent>
34+
<DialogContent className='border-border text-primary'>
3335
<DialogHeader>
34-
<DialogTitle>
36+
<DialogTitle className=''>
3537
Attempt&nbsp;<span className='font-mono'>{attemptId}</span>
3638
</DialogTitle>
3739
</DialogHeader>
38-
<DialogDescription />
39-
<DialogFooter />
40+
<DialogDescription>
41+
<CodeViewer {...{ code, language }} />
42+
</DialogDescription>
43+
<DialogFooter>
44+
<span className='font-base text-sm'>Attempted at: {triggerText}</span>
45+
</DialogFooter>
4046
</DialogContent>
4147
</Dialog>
4248
);

frontend/src/components/blocks/interview/question-attempts/table.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ export function QuestionAttemptsTable<TValue>({
7474

7575
return (
7676
<div className='relative flex max-h-full w-full grow flex-col'>
77-
<div className='flex items-center py-4'>
77+
<div className='flex items-center pb-4 pt-2'>
7878
<div className='flex flex-col gap-1'>
79-
<label className='text-sm font-medium'>Filter by Language</label>
79+
<label className='ml-0.5 text-sm font-medium'>Filter by Language</label>
8080
<ComboboxMulti
8181
setValuesCallback={setLanguages}
8282
options={Array.from(new Set(data.map((v) => v.language))).map((v) => ({
@@ -116,7 +116,7 @@ export function QuestionAttemptsTable<TValue>({
116116
</TableHeader>
117117
</Table>
118118
</div>
119-
<ScrollArea className='size-full overflow-x-auto border-x'>
119+
<ScrollArea className='border-border size-full overflow-x-auto border-x'>
120120
<Table>
121121
<TableBody>
122122
{!isError && table.getRowModel().rows?.length ? (
@@ -139,9 +139,9 @@ export function QuestionAttemptsTable<TValue>({
139139
</TableBody>
140140
</Table>
141141
</ScrollArea>
142-
<div className='sticky bottom-0 rounded-b-md border'>
142+
<div className='border-border sticky bottom-0 rounded-b-md border'>
143143
<Table>
144-
<TableFooter>
144+
<TableFooter className='border-t-border'>
145145
<TableRow>
146146
<TableCell colSpan={columns.length}>
147147
<Pagination className='flex items-center justify-end space-x-2 p-2'>

frontend/src/components/ui/combobox.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,14 @@ export const ComboboxMulti = React.forwardRef<
5454
<ChevronsUpDown className='ml-2 size-4 shrink-0 opacity-50' />
5555
</Button>
5656
</PopoverTrigger>
57-
<PopoverContent ref={ref} className={cn('w-[200px] p-0', className)} {...props}>
57+
<PopoverContent
58+
ref={ref}
59+
className={cn('w-[200px] p-0 border-secondary-foreground/40', className)}
60+
{...props}
61+
>
5862
<Command>
5963
<CommandInput placeholder={placeholderText} />
60-
<CommandList>
64+
<CommandList className=''>
6165
<CommandEmpty>{noOptionsText}</CommandEmpty>
6266
<CommandGroup>
6367
{options.map((option) => (

frontend/src/components/ui/command.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ const CommandInput = React.forwardRef<
3939
React.ElementRef<typeof CommandPrimitive.Input>,
4040
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
4141
>(({ className, ...props }, ref) => (
42-
<div className='flex items-center border-b px-3' cmdk-input-wrapper=''>
42+
<div
43+
className='border-secondary-foreground/40 flex items-center border-b px-3'
44+
cmdk-input-wrapper=''
45+
>
4346
<MagnifyingGlassIcon className='mr-2 size-4 shrink-0 opacity-50' />
4447
<CommandPrimitive.Input
4548
ref={ref}

0 commit comments

Comments
 (0)