From 147bdbef067fae4cebed10f4e648cfa9b4f1706f Mon Sep 17 00:00:00 2001 From: youznn Date: Mon, 23 Sep 2024 15:09:22 +0900 Subject: [PATCH 1/5] fix(fe): fix input and ouput description to katexcontent --- .../frontend/components/EditorDescription.tsx | 322 +----------------- 1 file changed, 10 insertions(+), 312 deletions(-) diff --git a/apps/frontend/components/EditorDescription.tsx b/apps/frontend/components/EditorDescription.tsx index b13056c3b2..9138764854 100644 --- a/apps/frontend/components/EditorDescription.tsx +++ b/apps/frontend/components/EditorDescription.tsx @@ -8,54 +8,12 @@ import { AccordionTrigger } from '@/components/ui/accordion' import { Badge } from '@/components/ui/badge' -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogTrigger -} from '@/components/ui/dialog' import { convertToLetter } from '@/lib/utils' -import CopyIcon from '@/public/24_copy.svg' -import compileIcon from '@/public/compileVersion.svg' -import copyIcon from '@/public/copy.svg' -import copyCompleteIcon from '@/public/copyComplete.svg' import type { ContestProblem, ProblemDetail } from '@/types/type' import type { Level } from '@/types/type' -import { motion } from 'framer-motion' import { sanitize } from 'isomorphic-dompurify' -import { FileText } from 'lucide-react' -import Image from 'next/image' -import { useState } from 'react' -import useCopyToClipboard from 'react-use/lib/useCopyToClipboard' -import { toast } from 'sonner' -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger -} from './ui/tooltip' - -const useCopy = () => { - const [, copyToClipboard] = useCopyToClipboard() - - // copiedID is used to show the checkmark icon when the user copies the input/output - const [copiedID, setCopiedID] = useState('') - const [timeoutID, setTimeoutID] = useState(null) - - const copy = (value: string, id: string) => { - copyToClipboard(value) - setCopiedID(id) - - // Clear the timeout if it's already set - // This will prevent the previous setTimeout from executing - timeoutID && clearTimeout(timeoutID) - const timeout = setTimeout(() => setCopiedID(''), 2000) - setTimeoutID(timeout) - } - - return { copiedID, copy } -} +import EditorSampleField from './EditorSampleField' +import ReferenceDialog from './ReferenceDialog' export function EditorDescription({ problem, @@ -66,8 +24,6 @@ export function EditorDescription({ contestProblems?: ContestProblem[] isContest?: boolean }) { - const { copiedID, copy } = useCopy() - const level = problem.difficulty const levelNumber = level.slice(-1) return ( @@ -92,174 +48,21 @@ export function EditorDescription({

Input

-
+
+ +

Output

-
+
+ +

- -
- {problem.problemTestcase.map(({ id, input, output }, index) => { - const whitespaceStyle = - 'color: rgb(53, 129, 250); min-width: 0.5em; display: inline-block;' - const changedInput = input - .replaceAll(/ /g, ``) - .replaceAll(/\n/g, `\n`) - .replaceAll(/\t/g, ``) - const changedOutput = output - .replaceAll(/ /g, ``) - .replaceAll(/\n/g, `\n`) - .replaceAll(/\t/g, ``) - return ( -
-

Sample

- -
-
-
-

- Input {index + 1} -

- - - - {copiedID == `input-${id}` ? ( - copy - ) : ( - - { - copy(input + '\n\n', `input-${id}`) // add newline to the end for easy testing - toast('Successfully copied', { - unstyled: true, - closeButton: false, - icon: copy, - style: { backgroundColor: '#f0f8ff' }, - classNames: { - toast: - 'inline-flex items-center py-2 px-3 rounded gap-2', - title: 'text-primary font-medium' - } - }) - }} - className="cursor-pointer transition-opacity hover:opacity-60" - src={copyIcon} - alt="copy" - width={24} - /> - - )} - - -

Copy

-
-
-
-
-
-
-                  
-
- -
-
-

- Output {index + 1} -

- - - - {copiedID == `output-${id}` ? ( - copy - ) : ( - - { - copy(output + '\n\n', `output-${id}`) // add newline to the end for easy testing - toast('Successfully copied', { - unstyled: true, - closeButton: false, - icon: copy, - style: { backgroundColor: '#f0f8ff' }, - classNames: { - toast: - 'inline-flex items-center py-2 px-3 rounded gap-2', - title: 'text-primary font-medium' - } - }) - }} - className="cursor-pointer transition-opacity hover:opacity-60" - src={copyIcon} - alt="copy" - width={24} - /> - - )} - - -

Copy

-
-
-
-
-
-
-                  
-
-
-
- ) - })} -
+
@@ -295,112 +98,7 @@ export function EditorDescription({
- - - compile - - - - - Compiler Version Document - - -
- - - - - - - - - - - - - - - - - - - - - - - - - -
LanguageCompiler Version Document
C -
- - - - gcc 13.2.0 -
-
- - - - c11 -
-
C++ -
- - - - g++ 13.2.0 -
-
- - - - c++ 14 -
-
Java -
- - - - openjdk 17.0.11 -
-
Python -
- - - - python 3.12.3 -
-
-
-
-
+
) From 592646b100c01d3c95e2de8c3ff891fc1702d257 Mon Sep 17 00:00:00 2001 From: youznn Date: Mon, 23 Sep 2024 15:11:04 +0900 Subject: [PATCH 2/5] refactor(fe): separate components --- .../frontend/components/EditorSampleField.tsx | 181 ++++++++++++++++++ apps/frontend/components/ReferenceDialog.tsx | 115 +++++++++++ 2 files changed, 296 insertions(+) create mode 100644 apps/frontend/components/EditorSampleField.tsx create mode 100644 apps/frontend/components/ReferenceDialog.tsx diff --git a/apps/frontend/components/EditorSampleField.tsx b/apps/frontend/components/EditorSampleField.tsx new file mode 100644 index 0000000000..ea78d17642 --- /dev/null +++ b/apps/frontend/components/EditorSampleField.tsx @@ -0,0 +1,181 @@ +import CopyIcon from '@/public/24_copy.svg' +import copyIcon from '@/public/copy.svg' +import copyCompleteIcon from '@/public/copyComplete.svg' +import type { ProblemDetail } from '@/types/type' +import { motion } from 'framer-motion' +import { sanitize } from 'isomorphic-dompurify' +import Image from 'next/image' +import { useState } from 'react' +import { useCopyToClipboard } from 'react-use' +import { toast } from 'sonner' +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger +} from './ui/tooltip' + +interface EditorSampleFieldProps { + problemTestCase: ProblemDetail['problemTestcase'] +} + +const useCopy = () => { + const [, copyToClipboard] = useCopyToClipboard() + + // copiedID is used to show the checkmark icon when the user copies the input/output + const [copiedID, setCopiedID] = useState('') + const [timeoutID, setTimeoutID] = useState(null) + + const copy = (value: string, id: string) => { + copyToClipboard(value) + setCopiedID(id) + + // Clear the timeout if it's already set + // This will prevent the previous setTimeout from executing + // eslint-disable-next-line @typescript-eslint/no-unused-expressions + timeoutID && clearTimeout(timeoutID) + const timeout = setTimeout(() => setCopiedID(''), 2000) + setTimeoutID(timeout) + } + + return { copiedID, copy } +} + +export default function EditorSampleField({ + problemTestCase +}: EditorSampleFieldProps) { + const { copiedID, copy } = useCopy() + return problemTestCase.map(({ id, input, output }, index) => { + const whitespaceStyle = + 'color: rgb(53, 129, 250); min-width: 0.5em; display: inline-block;' + const changedInput = input + .replaceAll(/ /g, ``) + .replaceAll(/\n/g, `\n`) + .replaceAll(/\t/g, ``) + const changedOutput = output + .replaceAll(/ /g, ``) + .replaceAll(/\n/g, `\n`) + .replaceAll(/\t/g, ``) + return ( +
+

Sample

+ +
+
+
+

+ Input {index + 1} +

+ + + + {copiedID == `input-${id}` ? ( + copy + ) : ( + + { + copy(input + '\n\n', `input-${id}`) // add newline to the end for easy testing + toast('Successfully copied', { + unstyled: true, + closeButton: false, + icon: copy, + style: { backgroundColor: '#f0f8ff' }, + classNames: { + toast: + 'inline-flex items-center py-2 px-3 rounded gap-2', + title: 'text-primary font-medium' + } + }) + }} + className="cursor-pointer transition-opacity hover:opacity-60" + src={copyIcon} + alt="copy" + width={24} + /> + + )} + + +

Copy

+
+
+
+
+
+
+            
+
+ +
+
+

+ Output {index + 1} +

+ + + + {copiedID == `output-${id}` ? ( + copy + ) : ( + + { + copy(output + '\n\n', `output-${id}`) // add newline to the end for easy testing + toast('Successfully copied', { + unstyled: true, + closeButton: false, + icon: copy, + style: { backgroundColor: '#f0f8ff' }, + classNames: { + toast: + 'inline-flex items-center py-2 px-3 rounded gap-2', + title: 'text-primary font-medium' + } + }) + }} + className="cursor-pointer transition-opacity hover:opacity-60" + src={copyIcon} + alt="copy" + width={24} + /> + + )} + + +

Copy

+
+
+
+
+
+
+            
+
+
+
+ ) + }) +} diff --git a/apps/frontend/components/ReferenceDialog.tsx b/apps/frontend/components/ReferenceDialog.tsx new file mode 100644 index 0000000000..e8785803a8 --- /dev/null +++ b/apps/frontend/components/ReferenceDialog.tsx @@ -0,0 +1,115 @@ +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger +} from '@/components/ui/dialog' +import compileIcon from '@/public/compileVersion.svg' +import { FileText } from 'lucide-react' +import Image from 'next/image' + +export default function ReferenceDialog() { + return ( + + + compile + + + + + Compiler Version Document + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
LanguageCompiler Version Document
C +
+ + + + gcc 13.2.0 +
+
+ + + + c11 +
+
C++ +
+ + + + g++ 13.2.0 +
+
+ + + + c++ 14 +
+
Java +
+ + + + openjdk 17.0.11 +
+
Python +
+ + + + python 3.12.3 +
+
+
+
+
+ ) +} From a7bb988221b7a0246baf232bdbf1e3f6236865ef Mon Sep 17 00:00:00 2001 From: youznn Date: Mon, 23 Sep 2024 15:15:09 +0900 Subject: [PATCH 3/5] chore(fe): add use client --- apps/frontend/components/EditorSampleField.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/frontend/components/EditorSampleField.tsx b/apps/frontend/components/EditorSampleField.tsx index ea78d17642..2d2f19c58e 100644 --- a/apps/frontend/components/EditorSampleField.tsx +++ b/apps/frontend/components/EditorSampleField.tsx @@ -1,3 +1,5 @@ +'use client' + import CopyIcon from '@/public/24_copy.svg' import copyIcon from '@/public/copy.svg' import copyCompleteIcon from '@/public/copyComplete.svg' From 737814c81313445a2dafd2279288cfa9971df5a9 Mon Sep 17 00:00:00 2001 From: youznn Date: Mon, 7 Oct 2024 11:00:07 +0900 Subject: [PATCH 4/5] refactor(fe): replace timeout with useRef --- apps/frontend/components/EditorDescription.tsx | 16 ++++++++-------- apps/frontend/components/EditorSampleField.tsx | 14 +++++++++----- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/apps/frontend/components/EditorDescription.tsx b/apps/frontend/components/EditorDescription.tsx index 9138764854..49b758f61d 100644 --- a/apps/frontend/components/EditorDescription.tsx +++ b/apps/frontend/components/EditorDescription.tsx @@ -67,15 +67,15 @@ export function EditorDescription({
-
-

Time Limit

-

Memory Limit

-

Source

+
+

Time Limit

+

Memory Limit

+

Source

-
-

{problem.timeLimit} ms

-

{problem.memoryLimit} MB

-

{problem.source}

+
+

{problem.timeLimit} ms

+

{problem.memoryLimit} MB

+

{problem.source}

diff --git a/apps/frontend/components/EditorSampleField.tsx b/apps/frontend/components/EditorSampleField.tsx index 2d2f19c58e..795d76fe8a 100644 --- a/apps/frontend/components/EditorSampleField.tsx +++ b/apps/frontend/components/EditorSampleField.tsx @@ -8,6 +8,7 @@ import { motion } from 'framer-motion' import { sanitize } from 'isomorphic-dompurify' import Image from 'next/image' import { useState } from 'react' +import { useRef } from 'react' import { useCopyToClipboard } from 'react-use' import { toast } from 'sonner' import { @@ -26,7 +27,7 @@ const useCopy = () => { // copiedID is used to show the checkmark icon when the user copies the input/output const [copiedID, setCopiedID] = useState('') - const [timeoutID, setTimeoutID] = useState(null) + const timeoutIDRef = useRef(null) const copy = (value: string, id: string) => { copyToClipboard(value) @@ -34,10 +35,13 @@ const useCopy = () => { // Clear the timeout if it's already set // This will prevent the previous setTimeout from executing - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - timeoutID && clearTimeout(timeoutID) - const timeout = setTimeout(() => setCopiedID(''), 2000) - setTimeoutID(timeout) + if (timeoutIDRef.current) { + clearTimeout(timeoutIDRef.current) + } + timeoutIDRef.current = setTimeout(() => { + setCopiedID('') + timeoutIDRef.current = null + }, 2000) } return { copiedID, copy } From 627aae092e5a982e49ceaaba43bd077eb138e0da Mon Sep 17 00:00:00 2001 From: youznn Date: Mon, 7 Oct 2024 11:29:22 +0900 Subject: [PATCH 5/5] refactor(fe): saperate button component --- .../frontend/components/EditorSampleField.tsx | 153 ++++++++---------- 1 file changed, 71 insertions(+), 82 deletions(-) diff --git a/apps/frontend/components/EditorSampleField.tsx b/apps/frontend/components/EditorSampleField.tsx index 795d76fe8a..be3c2530b9 100644 --- a/apps/frontend/components/EditorSampleField.tsx +++ b/apps/frontend/components/EditorSampleField.tsx @@ -72,47 +72,13 @@ export default function EditorSampleField({

Input {index + 1}

- - - - {copiedID == `input-${id}` ? ( - copy - ) : ( - - { - copy(input + '\n\n', `input-${id}`) // add newline to the end for easy testing - toast('Successfully copied', { - unstyled: true, - closeButton: false, - icon: copy, - style: { backgroundColor: '#f0f8ff' }, - classNames: { - toast: - 'inline-flex items-center py-2 px-3 rounded gap-2', - title: 'text-primary font-medium' - } - }) - }} - className="cursor-pointer transition-opacity hover:opacity-60" - src={copyIcon} - alt="copy" - width={24} - /> - - )} - - -

Copy

-
-
-
+
                 Output {index + 1}
               
-              
-                
-                  
-                    {copiedID == `output-${id}` ? (
-                      copy
-                    ) : (
-                      
-                         {
-                            copy(output + '\n\n', `output-${id}`) // add newline to the end for easy testing
-                            toast('Successfully copied', {
-                              unstyled: true,
-                              closeButton: false,
-                              icon: copy,
-                              style: { backgroundColor: '#f0f8ff' },
-                              classNames: {
-                                toast:
-                                  'inline-flex items-center py-2 px-3 rounded gap-2',
-                                title: 'text-primary font-medium'
-                              }
-                            })
-                          }}
-                          className="cursor-pointer transition-opacity hover:opacity-60"
-                          src={copyIcon}
-                          alt="copy"
-                          width={24}
-                        />
-                      
-                    )}
-                  
-                  
-                    

Copy

-
-
-
+
 void
+}) {
+  return (
+    
+      
+        
+          {copiedID == `${title}-${id}` ? (
+            copy
+          ) : (
+            
+               {
+                  copy(content + '\n\n', `${title}-${id}`) // add newline to the end for easy testing
+                  toast('Successfully copied', {
+                    unstyled: true,
+                    closeButton: false,
+                    icon: copy,
+                    style: { backgroundColor: '#f0f8ff' },
+                    classNames: {
+                      toast: 'inline-flex items-center py-2 px-3 rounded gap-2',
+                      title: 'text-primary font-medium'
+                    }
+                  })
+                }}
+                className="cursor-pointer transition-opacity hover:opacity-60"
+                src={copyIcon}
+                alt="copy"
+                width={24}
+              />
+            
+          )}
+        
+        
+          

Copy

+
+
+
+ ) +}