aboutsummaryrefslogtreecommitdiffhomepage
path: root/frontend/app
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/app')
-rw-r--r--frontend/app/api/schema.d.ts2
-rw-r--r--frontend/app/components/Gaming/CodePopover.tsx43
-rw-r--r--frontend/app/components/Gaming/RankingTable.tsx5
-rw-r--r--frontend/app/routes/dashboard.tsx19
4 files changed, 50 insertions, 19 deletions
diff --git a/frontend/app/api/schema.d.ts b/frontend/app/api/schema.d.ts
index 6f69292..af454e8 100644
--- a/frontend/app/api/schema.d.ts
+++ b/frontend/app/api/schema.d.ts
@@ -211,6 +211,8 @@ export interface components {
score: number;
/** @example 946684800 */
submitted_at: number;
+ /** @example echo 'hello world'; */
+ code: string | null;
};
};
responses: {
diff --git a/frontend/app/components/Gaming/CodePopover.tsx b/frontend/app/components/Gaming/CodePopover.tsx
new file mode 100644
index 0000000..a574a77
--- /dev/null
+++ b/frontend/app/components/Gaming/CodePopover.tsx
@@ -0,0 +1,43 @@
+import { Popover } from "@base-ui-components/react/popover";
+import { faCode, faXmark } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { calcCodeSize } from "../../states/play";
+import BorderedContainer from "../BorderedContainer";
+import CodeBlock from "../Gaming/CodeBlock";
+
+type Props = {
+ code: string;
+};
+
+export default function CodePopover({ code }: Props) {
+ const codeSize = calcCodeSize(code);
+
+ return (
+ <Popover.Root>
+ <Popover.Trigger>
+ <FontAwesomeIcon icon={faCode} fixedWidth />
+ </Popover.Trigger>
+ <Popover.Portal>
+ <Popover.Positioner>
+ <Popover.Popup>
+ <BorderedContainer className="grow flex flex-col gap-4">
+ <div className="flex flex-row gap-2 items-center">
+ <div className="grow font-semibold text-lg">
+ コードサイズ: {codeSize}
+ </div>
+ <Popover.Close className="p-1 bg-gray-50 border-1 border-gray-300 rounded-sm">
+ <FontAwesomeIcon
+ icon={faXmark}
+ fixedWidth
+ className="text-gray-500"
+ />
+ </Popover.Close>
+ </div>
+ <CodeBlock code={code} language="php" />
+ </BorderedContainer>
+ </Popover.Popup>
+ </Popover.Positioner>
+ </Popover.Portal>
+ </Popover.Root>
+ );
+}
diff --git a/frontend/app/components/Gaming/RankingTable.tsx b/frontend/app/components/Gaming/RankingTable.tsx
index a1e41f5..38d5200 100644
--- a/frontend/app/components/Gaming/RankingTable.tsx
+++ b/frontend/app/components/Gaming/RankingTable.tsx
@@ -1,6 +1,7 @@
import { useAtomValue } from "jotai";
import React from "react";
import { rankingAtom } from "../../states/watch";
+import CodePopover from "./CodePopover";
function TableHeaderCell({ children }: { children: React.ReactNode }) {
return (
@@ -40,6 +41,7 @@ export default function RankingTable() {
<TableHeaderCell>プレイヤー</TableHeaderCell>
<TableHeaderCell>スコア</TableHeaderCell>
<TableHeaderCell>提出時刻</TableHeaderCell>
+ <TableHeaderCell>コード</TableHeaderCell>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-300">
@@ -54,6 +56,9 @@ export default function RankingTable() {
<TableBodyCell>
{formatUnixTimestamp(entry.submitted_at)}
</TableBodyCell>
+ <TableBodyCell>
+ {entry.code && <CodePopover code={entry.code} />}
+ </TableBodyCell>
</tr>
))}
</tbody>
diff --git a/frontend/app/routes/dashboard.tsx b/frontend/app/routes/dashboard.tsx
index d0fea47..b7bfb01 100644
--- a/frontend/app/routes/dashboard.tsx
+++ b/frontend/app/routes/dashboard.tsx
@@ -24,8 +24,6 @@ export async function loader({ request }: LoaderFunctionArgs) {
export default function Dashboard() {
const { user, games } = useLoaderData<typeof loader>()!;
- const isOnlineQualifyingOpen = new Date() < new Date(2025, 2, 21, 16, 30);
-
return (
<div className="p-6 bg-gray-100 min-h-screen flex flex-col items-center gap-4">
{user.icon_path && (
@@ -36,23 +34,6 @@ export default function Dashboard() {
/>
)}
<h1 className="text-3xl font-bold text-gray-800">{user.display_name}</h1>
- {isOnlineQualifyingOpen && (
- <BorderedContainerWithCaption caption="オンライン予選開催中 (3/21 決勝当日まで)">
- <p className="text-gray-900 max-w-prose">
- 現在オンライン予選を開催中です。
- 予選問題2問を両方解いたプレイヤーのうち合計スコアが最も小さい2名が、3/21
- (金) の PHPerKaigi day0 に実施される決勝戦への進出枠を獲得します。
- 当日は、会場の Track A まで是非お越しください!
- </p>
- <p className="text-gray-600 max-w-prose">
- ※ 当日会場 Track A
- にいらっしゃらない場合、次点のスコアを獲得されている方が自動的に決勝進出となります。
- </p>
- <p className="text-gray-600 max-w-prose">
- ※ 決勝に参加する予定のない方でも、プレイしていただくことは可能です。
- </p>
- </BorderedContainerWithCaption>
- )}
<BorderedContainerWithCaption caption="試合一覧">
<div className="px-4">
{games.length === 0 ? (