Skip to content

Commit aba1089

Browse files
authored
Merge pull request #1823 from AtCoder-NoviSteps/#1822
🎨 Simplify UI in contest table (#1822)
2 parents 01a8530 + 0040622 commit aba1089

File tree

5 files changed

+99
-74
lines changed

5 files changed

+99
-74
lines changed

src/lib/components/GradeLabel.svelte

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@
66
taskGrade: TaskGrade | string;
77
defaultPadding?: number;
88
defaultWidth?: number;
9+
reducedWidth?: number;
910
}
1011
11-
let { taskGrade, defaultPadding = 1, defaultWidth = 10 }: Props = $props();
12+
let { taskGrade, defaultPadding = 1, defaultWidth = 10, reducedWidth = 8 }: Props = $props();
1213
1314
let grade = $derived(getTaskGradeLabel(taskGrade));
1415
let gradeColor = $derived(getTaskGradeColor(taskGrade));
1516
</script>
1617

1718
<div class="rounded-lg border-2 border-white">
1819
<div
19-
class="p-{defaultPadding} w-8 xs:w-{defaultWidth} text-sm xs:text-md text-center rounded-md {toWhiteTextIfNeeds(
20+
class="p-{defaultPadding} w-{reducedWidth} xs:w-{defaultWidth} text-sm xs:text-md text-center rounded-md {toWhiteTextIfNeeds(
2021
grade,
2122
)} {gradeColor}"
2223
>

src/lib/components/TaskTables/TaskTable.svelte

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@
6464
}
6565
6666
function getBodyCellClasses(contestId: string, taskIndex: string): string {
67-
const baseClasses = 'w-1/2 xs:w-1/3 sm:w-1/4 md:w-1/5 lg:w-1/6 px-1 py-1 border';
67+
const baseClasses =
68+
'w-1/2 xs:w-1/3 sm:w-1/4 md:w-1/5 lg:w-1/6 px-1 py-1 border hover:brightness-125 transition-all';
6869
const backgroundColor = getBackgroundColor(taskTable[contestId][taskIndex]);
6970
7071
return `${baseClasses} ${backgroundColor}`;
@@ -100,50 +101,56 @@
100101
</Heading>
101102

102103
<!-- TODO: ページネーションを実装 -->
104+
<!-- TODO: ヘッダーを固定できるようにする。-->
105+
<!-- HACK: Flowbite と tailwindcss の相性が悪いのかもしれない。tailwindcss のクラス指定、raw HTML & CSS を試したが、いずれも実現できず。 -->
103106
<!-- See: -->
104107
<!-- https://github.com/kenkoooo/AtCoderProblems/blob/master/atcoder-problems-frontend/src/pages/TablePage/AtCoderRegularTable.tsx -->
105108
<!-- https://github.com/birdou/atcoder-blogs/blob/main/app/atcoder-blogs-frontend/src/pages/BlogTablePage/BlogTablePage.tsx -->
106-
<div class="container w-full overflow-auto border rounded-md">
107-
<Table shadow id="task-table" class="text-md table-fixed" aria-label="Task table">
108-
<TableHead class="text-sm bg-gray-100">
109-
<TableHeadCell class="w-full xl:w-16 px-2 text-center border" scope="col">
110-
Round
111-
</TableHeadCell>
112-
113-
{#if taskTableHeaderIds.length}
114-
{#each taskTableHeaderIds as taskTableHeaderId}
115-
<TableHeadCell class="text-center border" scope="col">{taskTableHeaderId}</TableHeadCell>
116-
{/each}
117-
{/if}
118-
</TableHead>
119-
120-
<TableBody class="divide-y">
121-
{#if contestIds.length && taskTableHeaderIds.length}
122-
{#each contestIds as contestId}
123-
<TableBodyRow class="flex flex-wrap xl:table-row">
124-
<TableBodyCell class="w-full xl:w-16 truncate px-2 py-2 text-center border">
125-
{getContestRoundLabel(provider, contestId)}
126-
</TableBodyCell>
127-
128-
{#each taskTableHeaderIds as taskTableHeaderId}
129-
<TableBodyCell
130-
id={contestId + '-' + taskTableHeaderId}
131-
class={getBodyCellClasses(contestId, taskTableHeaderId)}
132-
>
133-
{#if taskTable[contestId][taskTableHeaderId]}
134-
<TaskTableBodyCell
135-
taskResult={taskTable[contestId][taskTableHeaderId]}
136-
{isLoggedIn}
137-
onClick={() => openModal(taskTable[contestId][taskTableHeaderId])}
138-
/>
139-
{/if}
109+
<!-- https://tailwindcss.com/docs/position#sticky-positioning-elements -->
110+
<div class="container w-full overflow-hidden rounded-md border border-gray-100 shadow-sm">
111+
<div class="w-full overflow-auto">
112+
<Table id="task-table" class="text-md table-fixed w-full" aria-label="Task table">
113+
<TableHead class="text-sm bg-gray-100">
114+
<TableHeadCell class="w-full xl:w-16 px-2 text-center border" scope="col">
115+
Round
116+
</TableHeadCell>
117+
118+
{#if taskTableHeaderIds.length}
119+
{#each taskTableHeaderIds as taskTableHeaderId}
120+
<TableHeadCell class="text-center border" scope="col">{taskTableHeaderId}</TableHeadCell
121+
>
122+
{/each}
123+
{/if}
124+
</TableHead>
125+
126+
<TableBody class="divide-y">
127+
{#if contestIds.length && taskTableHeaderIds.length}
128+
{#each contestIds as contestId}
129+
<TableBodyRow class="flex flex-wrap xl:table-row">
130+
<TableBodyCell class="w-full xl:w-16 truncate px-2 py-2 text-center border">
131+
{getContestRoundLabel(provider, contestId)}
140132
</TableBodyCell>
141-
{/each}
142-
</TableBodyRow>
143-
{/each}
144-
{/if}
145-
</TableBody>
146-
</Table>
133+
134+
{#each taskTableHeaderIds as taskTableHeaderId}
135+
<TableBodyCell
136+
id={contestId + '-' + taskTableHeaderId}
137+
class={getBodyCellClasses(contestId, taskTableHeaderId)}
138+
>
139+
{#if taskTable[contestId][taskTableHeaderId]}
140+
<TaskTableBodyCell
141+
taskResult={taskTable[contestId][taskTableHeaderId]}
142+
{isLoggedIn}
143+
onClick={() => openModal(taskTable[contestId][taskTableHeaderId])}
144+
/>
145+
{/if}
146+
</TableBodyCell>
147+
{/each}
148+
</TableBodyRow>
149+
{/each}
150+
{/if}
151+
</TableBody>
152+
</Table>
153+
</div>
147154
</div>
148155

149156
<UpdatingModal bind:this={updatingModal} {isLoggedIn} />
Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
<script lang="ts">
2+
import EllipsisVertical from 'lucide-svelte/icons/ellipsis-vertical';
3+
24
import type { TaskResult } from '$lib/types/task';
35
46
import ExternalLinkWrapper from '$lib/components/ExternalLinkWrapper.svelte';
57
import GradeLabel from '$lib/components/GradeLabel.svelte';
6-
import IconForUpdating from '$lib/components/SubmissionStatus/IconForUpdating.svelte';
78
8-
import { getTaskUrl } from '$lib/utils/task';
9+
import { getTaskUrl, removeTaskIndexFromTitle } from '$lib/utils/task';
910
1011
interface Props {
1112
taskResult: TaskResult;
@@ -16,35 +17,48 @@
1617
let { taskResult, isLoggedIn, onClick }: Props = $props();
1718
</script>
1819

19-
<!-- Task title and an external link -->
20-
<div class="text-left text-md sm:text-lg">
21-
<ExternalLinkWrapper
22-
url={getTaskUrl(taskResult.contest_id, taskResult.task_id)}
23-
description={taskResult.title}
24-
textSize="xs:text-md"
25-
textColorInDarkMode="dark:text-gray-300"
26-
textOverflow="min-w-[60px] max-w-[120px]"
27-
iconSize={0}
28-
/>
20+
<div class="flex items-center w-full space-x-1 text-left text-sm sm:text-md">
21+
{@render taskGradeLabel(taskResult)}
22+
23+
<div class="flex justify-between w-full min-w-0">
24+
{@render taskTitleAndExternalLink(taskResult)}
25+
26+
{#if isLoggedIn}
27+
{@render submissionUpdaterAndLinksOfTaskDetailPage(onClick, taskResult)}
28+
{/if}
29+
</div>
2930
</div>
3031

31-
<div class="flex items-center justify-between py-1">
32-
<!-- Task grade -->
33-
<GradeLabel taskGrade={taskResult.grade} defaultPadding={0.25} defaultWidth={8} />
32+
{#snippet taskGradeLabel(taskResult: TaskResult)}
33+
<div class="flex-shrink-0">
34+
<GradeLabel
35+
taskGrade={taskResult.grade}
36+
defaultPadding={0.25}
37+
defaultWidth={6}
38+
reducedWidth={6}
39+
/>
40+
</div>
41+
{/snippet}
42+
43+
{#snippet taskTitleAndExternalLink(taskResult: TaskResult)}
44+
<div class="max-w-[calc(100%-2rem)] truncate">
45+
<ExternalLinkWrapper
46+
url={getTaskUrl(taskResult.contest_id, taskResult.task_id)}
47+
description={removeTaskIndexFromTitle(taskResult.title, taskResult.task_table_index)}
48+
textSize="xs:text-md"
49+
textColorInDarkMode="dark:text-gray-300"
50+
iconSize={0}
51+
/>
52+
</div>
53+
{/snippet}
3454

35-
<!-- Submission updater and links of task detail page -->
36-
<!-- TODO: 当たり判定をグレードのアイコンまで広げる -->
55+
{#snippet submissionUpdaterAndLinksOfTaskDetailPage(onClick: () => void, taskResult: TaskResult)}
3756
<button
3857
type="button"
39-
class="mx-2 w-8 text-center"
58+
class="flex-shrink-0 w-6 ml-auto"
4059
onclick={onClick}
4160
aria-label="Update submission for {taskResult.title}"
4261
>
43-
<IconForUpdating {isLoggedIn} />
62+
<EllipsisVertical class="w-4 h-4 mx-auto" />
4463
</button>
45-
46-
<!-- TODO: Add link of detailed page. -->
47-
<div class="flex-1 text-center text-sm dark:text-gray-300 max-w-[32px]">
48-
{'詳細'}
49-
</div>
50-
</div>
64+
{/snippet}

src/lib/utils/contest_table_provider.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,12 @@ class ABCLatest20RoundsProvider extends ContestTableProviderBase {
118118
class ABC319OnwardsProvider extends ContestTableProviderBase {
119119
protected setFilterCondition(): (taskResult: TaskResult) => boolean {
120120
return (taskResult: TaskResult) => {
121+
if (classifyContest(taskResult.contest_id) !== this.contestType) {
122+
return false;
123+
}
124+
121125
const contestRound = parseContestRound(taskResult.contest_id, 'abc');
122-
return contestRound >= 319;
126+
return contestRound >= 319 && contestRound <= 999;
123127
};
124128
}
125129

@@ -145,6 +149,10 @@ class ABC319OnwardsProvider extends ContestTableProviderBase {
145149
class ABC212ToABC318Provider extends ContestTableProviderBase {
146150
protected setFilterCondition(): (taskResult: TaskResult) => boolean {
147151
return (taskResult: TaskResult) => {
152+
if (classifyContest(taskResult.contest_id) !== this.contestType) {
153+
return false;
154+
}
155+
148156
const contestRound = parseContestRound(taskResult.contest_id, 'abc');
149157
return contestRound >= 212 && contestRound <= 318;
150158
};

src/routes/problems/+page.svelte

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,5 @@
5050
<!-- <TabItemWrapper title="Tags">
5151
<div class="m-4">Comming Soon.</div>
5252
</TabItemWrapper> -->
53-
54-
<!-- Latest -->
55-
<!-- <TabItemWrapper title="Latest">
56-
<div class="m-4">Comming Soon.</div>
57-
</TabItemWrapper> -->
5853
</Tabs>
5954
</div>

0 commit comments

Comments
 (0)