aboutsummaryrefslogtreecommitdiffhomepage
path: root/frontend/app/components/Gaming
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-03-04 22:55:01 +0900
committernsfisis <nsfisis@gmail.com>2025-03-08 10:12:44 +0900
commit1e6df136d8202c8adf65948527f4c3e7583b338c (patch)
tree7c82476f6bbbc71d72ab7e71e39559eca197fd95 /frontend/app/components/Gaming
parent54316868c3bec1ff9b04643dfe6c13cf56bf3246 (diff)
downloadphperkaigi-2025-albatross-1e6df136d8202c8adf65948527f4c3e7583b338c.tar.gz
phperkaigi-2025-albatross-1e6df136d8202c8adf65948527f4c3e7583b338c.tar.zst
phperkaigi-2025-albatross-1e6df136d8202c8adf65948527f4c3e7583b338c.zip
websocket to polling
Diffstat (limited to 'frontend/app/components/Gaming')
-rw-r--r--frontend/app/components/Gaming/CodeBlock.tsx31
-rw-r--r--frontend/app/components/Gaming/ExecStatusIndicatorIcon.tsx11
-rw-r--r--frontend/app/components/Gaming/SubmitResult.tsx34
3 files changed, 31 insertions, 45 deletions
diff --git a/frontend/app/components/Gaming/CodeBlock.tsx b/frontend/app/components/Gaming/CodeBlock.tsx
index b7d45c0..0a9a2e5 100644
--- a/frontend/app/components/Gaming/CodeBlock.tsx
+++ b/frontend/app/components/Gaming/CodeBlock.tsx
@@ -1,8 +1,5 @@
-import Prism, { highlight, languages } from "prismjs";
-import "prismjs/components/prism-swift";
-import "prismjs/themes/prism.min.css";
-
-Prism.manual = true;
+import { useEffect, useState } from "react";
+import { codeToHtml } from "shiki";
type Props = {
code: string;
@@ -10,11 +7,31 @@ type Props = {
};
export default function CodeBlock({ code, language }: Props) {
- const highlighted = highlight(code, languages[language]!, language);
+ const [highlightedCode, setHighlightedCode] = useState<string | null>(null);
+
+ useEffect(() => {
+ let isMounted = true;
+
+ (async () => {
+ const highlighted = await codeToHtml(code, {
+ lang: language,
+ theme: "github-light",
+ });
+ if (isMounted) {
+ setHighlightedCode(highlighted);
+ }
+ })();
+
+ return () => {
+ isMounted = false;
+ };
+ }, [code, language]);
return (
<pre className="h-full w-full p-2 bg-gray-50 rounded-lg border border-gray-300 whitespace-pre-wrap break-words">
- <code dangerouslySetInnerHTML={{ __html: highlighted }} />
+ {highlightedCode === null ? null : (
+ <code dangerouslySetInnerHTML={{ __html: highlightedCode }} />
+ )}
</pre>
);
}
diff --git a/frontend/app/components/Gaming/ExecStatusIndicatorIcon.tsx b/frontend/app/components/Gaming/ExecStatusIndicatorIcon.tsx
index a717a48..44d28ad 100644
--- a/frontend/app/components/Gaming/ExecStatusIndicatorIcon.tsx
+++ b/frontend/app/components/Gaming/ExecStatusIndicatorIcon.tsx
@@ -1,20 +1,19 @@
import {
- faBan,
faCircle,
faCircleCheck,
faCircleExclamation,
faRotate,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import type { ExecResultStatus } from "../../types/ExecResult";
+import type { components } from "../../api/schema";
type Props = {
- status: ExecResultStatus;
+ status: components["schemas"]["ExecutionStatus"];
};
export default function ExecStatusIndicatorIcon({ status }: Props) {
switch (status) {
- case "waiting_submission":
+ case "none":
return (
<FontAwesomeIcon icon={faCircle} fixedWidth className="text-gray-400" />
);
@@ -35,10 +34,6 @@ export default function ExecStatusIndicatorIcon({ status }: Props) {
className="text-sky-500"
/>
);
- case "canceled":
- return (
- <FontAwesomeIcon icon={faBan} fixedWidth className="text-gray-400" />
- );
default:
return (
<FontAwesomeIcon
diff --git a/frontend/app/components/Gaming/SubmitResult.tsx b/frontend/app/components/Gaming/SubmitResult.tsx
index c626910..a78c79e 100644
--- a/frontend/app/components/Gaming/SubmitResult.tsx
+++ b/frontend/app/components/Gaming/SubmitResult.tsx
@@ -1,47 +1,21 @@
import React from "react";
-import type { SubmitResult } from "../../types/SubmitResult";
-import BorderedContainer from "../BorderedContainer";
+import type { components } from "../../api/schema";
import SubmitStatusLabel from "../SubmitStatusLabel";
-import ExecStatusIndicatorIcon from "./ExecStatusIndicatorIcon";
type Props = {
- result: SubmitResult;
+ status: components["schemas"]["ExecutionStatus"];
submitButton?: React.ReactNode;
};
-export default function SubmitResult({ result, submitButton }: Props) {
+export default function SubmitResult({ status, submitButton }: Props) {
return (
<div className="flex flex-col gap-2">
<div className="flex">
{submitButton}
<div className="grow font-bold text-xl text-center">
- <SubmitStatusLabel status={result.status} />
+ <SubmitStatusLabel status={status} />
</div>
</div>
- <ul className="flex flex-col gap-4">
- {result.execResults.map((r) => (
- <li key={r.testcase_id ?? -1}>
- <BorderedContainer>
- <div className="flex flex-col gap-2">
- <div className="flex gap-2">
- <div className="my-auto">
- <ExecStatusIndicatorIcon status={r.status} />
- </div>
- <div className="font-semibold">{r.label}</div>
- </div>
- {r.stdout + r.stderr && (
- <pre className="overflow-y-hidden max-h-96 p-2 bg-gray-50 rounded-lg border border-gray-300 whitespace-pre-wrap break-words">
- <code>
- {r.stdout}
- {r.stderr}
- </code>
- </pre>
- )}
- </div>
- </BorderedContainer>
- </li>
- ))}
- </ul>
</div>
);
}