@xcpcio/board-app 0.31.1 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/Board-5815574f.js +3 -0
- package/dist/assets/Board-99a6e425.css +1 -0
- package/dist/assets/{DataSourceInput.vue_vue_type_script_setup_true_lang-b87eba77.js → DataSourceInput.vue_vue_type_script_setup_true_lang-3a011309.js} +1 -1
- package/dist/assets/{TheInput.vue_vue_type_script_setup_true_lang-079f8c80.js → TheInput.vue_vue_type_script_setup_true_lang-c4669f90.js} +1 -1
- package/dist/assets/{_...all_-019b03b8.js → _...all_-9575471a.js} +1 -1
- package/dist/assets/{_name_-6a3b59a1.js → _name_-c49901a2.js} +1 -1
- package/dist/assets/{about-f9061b17.js → about-9ae6988f.js} +1 -1
- package/dist/assets/{board-6d208112.js → board-039c3f4a.js} +1 -1
- package/dist/assets/{board-layout-5590c53f.js → board-layout-b556ae6f.js} +1 -1
- package/dist/assets/{headless-94485ccd.js → headless-c2f93337.js} +1 -1
- package/dist/assets/{home-e847177d.js → home-281261c3.js} +1 -1
- package/dist/assets/index-39ee8a2c.css +1 -0
- package/dist/assets/index-a501b47e.js +1 -0
- package/dist/assets/index-b8d0230b.js +338 -0
- package/dist/assets/index-ca39a150.js +1 -0
- package/dist/assets/{index-d429549a.css → index-e63239d5.css} +1 -1
- package/dist/assets/{index-layout-3f26f613.js → index-layout-7e38f172.js} +1 -1
- package/dist/assets/{test-24dab276.js → test-b15602ea.js} +1 -1
- package/dist/assets/{useQueryBoardData-b6644ecd.js → useQueryBoardData-fc6b78c1.js} +1 -1
- package/dist/assets/{user-7a10fa8c.js → user-5cfcf268.js} +1 -1
- package/dist/assets/{virtual_pwa-register-41acaeb8.js → virtual_pwa-register-7426d7cc.js} +1 -1
- package/dist/index.html +1 -122
- package/dist/sw.js +1 -1
- package/package.json +4 -3
- package/src/auto-imports.d.ts +4 -1
- package/src/components/Balloon.vue +2 -2
- package/src/components/BalloonBlock.vue +3 -14
- package/src/components/Countdown.vue +0 -7
- package/src/components/board/AnimatedSubmissionsModal.vue +144 -0
- package/src/components/board/Board.vue +17 -8
- package/src/components/board/BottomStatistics.vue +2 -2
- package/src/components/board/OptionsModal.vue +30 -0
- package/src/components/board/ProblemBlock.vue +4 -2
- package/src/components/board/SubmissionsTable.vue +2 -4
- package/src/components/board/TeamUI.vue +4 -4
- package/src/components/board/Utility.vue +15 -15
- package/src/components.d.ts +1 -0
- package/src/composables/color.ts +31 -0
- package/src/styles/submission-status-background.css +123 -0
- package/vite.config.ts +16 -0
- package/dist/assets/Board-3c31679a.css +0 -1
- package/dist/assets/Board-ce0a2c6c.js +0 -3
- package/dist/assets/index-3735f4c2.js +0 -1
- package/dist/assets/index-4b46c3f4.js +0 -1
- package/dist/assets/index-622de38d.css +0 -1
- package/dist/assets/index-7a9bcf50.js +0 -205
package/src/auto-imports.d.ts
CHANGED
|
@@ -38,7 +38,6 @@ declare global {
|
|
|
38
38
|
const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch']
|
|
39
39
|
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
|
40
40
|
const defineComponent: typeof import('vue')['defineComponent']
|
|
41
|
-
const downloadSingleFile: typeof import('./composables/utils')['downloadSingleFile']
|
|
42
41
|
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
|
|
43
42
|
const effectScope: typeof import('vue')['effectScope']
|
|
44
43
|
const extendRef: typeof import('@vueuse/core')['extendRef']
|
|
@@ -47,10 +46,12 @@ declare global {
|
|
|
47
46
|
const getDataSourceUrl: typeof import('./composables/query')['getDataSourceUrl']
|
|
48
47
|
const getLocalStorageKeyForFilterOrganizations: typeof import('./composables/useLocalStorage')['getLocalStorageKeyForFilterOrganizations']
|
|
49
48
|
const getLocalStorageKeyForFilterTeams: typeof import('./composables/useLocalStorage')['getLocalStorageKeyForFilterTeams']
|
|
49
|
+
const getMedalColor: typeof import('./composables/color')['getMedalColor']
|
|
50
50
|
const getProblemChart: typeof import('./composables/statistics')['getProblemChart']
|
|
51
51
|
const getSubmitChart: typeof import('./composables/statistics')['getSubmitChart']
|
|
52
52
|
const getTeamChart: typeof import('./composables/statistics')['getTeamChart']
|
|
53
53
|
const getTeamPlaceChart: typeof import('./composables/statistics')['getTeamPlaceChart']
|
|
54
|
+
const getWhiteOrBlackColor: typeof import('./composables/color')['getWhiteOrBlackColor']
|
|
54
55
|
const h: typeof import('vue')['h']
|
|
55
56
|
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
|
|
56
57
|
const inject: typeof import('vue')['inject']
|
|
@@ -357,6 +358,7 @@ declare module 'vue' {
|
|
|
357
358
|
readonly getDataSourceUrl: UnwrapRef<typeof import('./composables/query')['getDataSourceUrl']>
|
|
358
359
|
readonly getLocalStorageKeyForFilterOrganizations: UnwrapRef<typeof import('./composables/useLocalStorage')['getLocalStorageKeyForFilterOrganizations']>
|
|
359
360
|
readonly getLocalStorageKeyForFilterTeams: UnwrapRef<typeof import('./composables/useLocalStorage')['getLocalStorageKeyForFilterTeams']>
|
|
361
|
+
readonly getMedalColor: UnwrapRef<typeof import('./composables/color')['getMedalColor']>
|
|
360
362
|
readonly getProblemChart: UnwrapRef<typeof import('./composables/statistics')['getProblemChart']>
|
|
361
363
|
readonly getSubmitChart: UnwrapRef<typeof import('./composables/statistics')['getSubmitChart']>
|
|
362
364
|
readonly getTeamChart: UnwrapRef<typeof import('./composables/statistics')['getTeamChart']>
|
|
@@ -658,6 +660,7 @@ declare module '@vue/runtime-core' {
|
|
|
658
660
|
readonly getDataSourceUrl: UnwrapRef<typeof import('./composables/query')['getDataSourceUrl']>
|
|
659
661
|
readonly getLocalStorageKeyForFilterOrganizations: UnwrapRef<typeof import('./composables/useLocalStorage')['getLocalStorageKeyForFilterOrganizations']>
|
|
660
662
|
readonly getLocalStorageKeyForFilterTeams: UnwrapRef<typeof import('./composables/useLocalStorage')['getLocalStorageKeyForFilterTeams']>
|
|
663
|
+
readonly getMedalColor: UnwrapRef<typeof import('./composables/color')['getMedalColor']>
|
|
661
664
|
readonly getProblemChart: UnwrapRef<typeof import('./composables/statistics')['getProblemChart']>
|
|
662
665
|
readonly getSubmitChart: UnwrapRef<typeof import('./composables/statistics')['getSubmitChart']>
|
|
663
666
|
readonly getTeamChart: UnwrapRef<typeof import('./composables/statistics')['getTeamChart']>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { Rank, createContest, createSubmissions, createTeams } from "@xcpcio/core";
|
|
2
|
+
import { Balloon, Rank, createContest, createSubmissions, createTeams } from "@xcpcio/core";
|
|
3
3
|
import type { Contest, Submissions, Teams } from "@xcpcio/core";
|
|
4
4
|
import type { Contest as IContest, Submissions as ISubmissions, Teams as ITeams } from "@xcpcio/types";
|
|
5
5
|
|
|
@@ -43,7 +43,7 @@ watch(data, async () => {
|
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
const balloons = computed(() => {
|
|
46
|
-
return rank.value.balloons;
|
|
46
|
+
return rank.value.balloons.sort(Balloon.compare).reverse().slice(0, 256);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
const setNowIntervalId = setInterval(() => {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { Balloon, Team } from "@xcpcio/core";
|
|
3
|
-
import type { ThemeColor } from "@xcpcio/types";
|
|
4
3
|
|
|
5
4
|
const props = defineProps<{
|
|
6
5
|
index: number;
|
|
@@ -18,17 +17,7 @@ function showTeamName(team: Team) {
|
|
|
18
17
|
return sections.filter(s => s).join(" - ");
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
if (typeof c === "string") {
|
|
23
|
-
return c;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (isDark && c?.dark) {
|
|
27
|
-
return c.dark;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return c.light;
|
|
31
|
-
}
|
|
20
|
+
const balloonColor = computed(() => balloon.value.problem.balloonColor);
|
|
32
21
|
</script>
|
|
33
22
|
|
|
34
23
|
<template>
|
|
@@ -47,12 +36,12 @@ function getColor(c: ThemeColor): string {
|
|
|
47
36
|
w-20
|
|
48
37
|
flex flex-shrink-0 justify-center items-center
|
|
49
38
|
:style="{
|
|
50
|
-
backgroundColor:
|
|
39
|
+
backgroundColor: balloonColor.background_color,
|
|
51
40
|
}"
|
|
52
41
|
>
|
|
53
42
|
<div
|
|
54
43
|
:style="{
|
|
55
|
-
color:
|
|
44
|
+
color: balloonColor.color,
|
|
56
45
|
}"
|
|
57
46
|
>
|
|
58
47
|
{{ balloon.problem.label }}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { Problem, Rank, Team } from "@xcpcio/core";
|
|
3
|
+
import { Submission } from "@xcpcio/core";
|
|
4
|
+
import { SubmissionStatusToSimpleString } from "@xcpcio/types";
|
|
5
|
+
|
|
6
|
+
import { getMedalColor } from "~/composables/color";
|
|
7
|
+
|
|
8
|
+
const props = defineProps<{
|
|
9
|
+
rank: Rank,
|
|
10
|
+
}>();
|
|
11
|
+
|
|
12
|
+
interface Item {
|
|
13
|
+
submission: Submission,
|
|
14
|
+
team: Team,
|
|
15
|
+
problem: Problem,
|
|
16
|
+
displayName: string,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const rank = computed(() => props.rank);
|
|
20
|
+
const submissions = computed(() => {
|
|
21
|
+
const ss = rank.value.getSubmissions().sort(Submission.compare).reverse();
|
|
22
|
+
|
|
23
|
+
const res: Item[] = [];
|
|
24
|
+
|
|
25
|
+
let cnt = 0;
|
|
26
|
+
const need = 16;
|
|
27
|
+
for (let i = 0; i < ss.length && cnt < need; i++) {
|
|
28
|
+
const s = ss[i];
|
|
29
|
+
const teamId = s.teamId;
|
|
30
|
+
const problemId = s.problemId;
|
|
31
|
+
|
|
32
|
+
const team = rank.value.teamsMap.get(teamId);
|
|
33
|
+
|
|
34
|
+
if (!team) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (rank.value.filterTeamByOrg(team)) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const problem = rank.value.contest.problemsMap.get(problemId);
|
|
43
|
+
if (!problem) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let displayName = team.name;
|
|
48
|
+
|
|
49
|
+
if (team.organization) {
|
|
50
|
+
displayName = `${team.organization} - ${displayName}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
res.push({
|
|
54
|
+
submission: s,
|
|
55
|
+
team,
|
|
56
|
+
problem,
|
|
57
|
+
displayName,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
++cnt;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return res.reverse();
|
|
64
|
+
});
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<template>
|
|
68
|
+
<div
|
|
69
|
+
absolute fixed z-99
|
|
70
|
+
bottom-4 left-4
|
|
71
|
+
opacity-90
|
|
72
|
+
>
|
|
73
|
+
<div
|
|
74
|
+
flex flex-col
|
|
75
|
+
>
|
|
76
|
+
<div>
|
|
77
|
+
<template
|
|
78
|
+
v-for="s in submissions"
|
|
79
|
+
:key="s.id"
|
|
80
|
+
>
|
|
81
|
+
<div
|
|
82
|
+
w-104
|
|
83
|
+
h-6
|
|
84
|
+
bg-slate-800 text-gray-200
|
|
85
|
+
font-mono
|
|
86
|
+
flex flex-row
|
|
87
|
+
justify-center items-center
|
|
88
|
+
>
|
|
89
|
+
<div
|
|
90
|
+
w-10
|
|
91
|
+
:style="getMedalColor(s.team)"
|
|
92
|
+
flex
|
|
93
|
+
justify-center items-center
|
|
94
|
+
>
|
|
95
|
+
<div>
|
|
96
|
+
{{ s.team.rank }}
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div
|
|
101
|
+
pl-1
|
|
102
|
+
w-80
|
|
103
|
+
truncate
|
|
104
|
+
>
|
|
105
|
+
{{ s.displayName }}
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<div
|
|
109
|
+
w-5
|
|
110
|
+
>
|
|
111
|
+
{{ s.team.solvedProblemNum }}
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<div
|
|
115
|
+
w-8
|
|
116
|
+
border-b-4
|
|
117
|
+
flex justify-center
|
|
118
|
+
:style="{
|
|
119
|
+
borderColor: s.problem.balloonColor.background_color,
|
|
120
|
+
}"
|
|
121
|
+
>
|
|
122
|
+
{{ s.problem.label }}
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<div
|
|
126
|
+
w-10
|
|
127
|
+
flex justify-center
|
|
128
|
+
:class="[s.submission.status]"
|
|
129
|
+
:style="{
|
|
130
|
+
color: '#000',
|
|
131
|
+
}"
|
|
132
|
+
>
|
|
133
|
+
{{ SubmissionStatusToSimpleString[s.submission.status] }}
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
</template>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
</template>
|
|
141
|
+
|
|
142
|
+
<style scoped lang="less">
|
|
143
|
+
@import "../../styles/submission-status-background.css";
|
|
144
|
+
</style>
|
|
@@ -280,7 +280,8 @@ const widthClass = "sm:w-[1260px] xl:w-screen";
|
|
|
280
280
|
<div v-if="!firstLoaded">
|
|
281
281
|
<div
|
|
282
282
|
:class="[wrapperWidthClass]"
|
|
283
|
-
flex flex-col gap-4
|
|
283
|
+
flex flex-col gap-4
|
|
284
|
+
justify-center items-center
|
|
284
285
|
>
|
|
285
286
|
<div>
|
|
286
287
|
{{ t("common.loading") }}...
|
|
@@ -457,14 +458,22 @@ const widthClass = "sm:w-[1260px] xl:w-screen";
|
|
|
457
458
|
</div>
|
|
458
459
|
</div>
|
|
459
460
|
</div>
|
|
460
|
-
</div>
|
|
461
461
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
462
|
+
<div
|
|
463
|
+
v-if="rankOptions.enableAnimatedSubmissions"
|
|
464
|
+
>
|
|
465
|
+
<AnimatedSubmissionsModal
|
|
466
|
+
:rank="rank"
|
|
467
|
+
/>
|
|
468
|
+
</div>
|
|
469
|
+
|
|
470
|
+
<OptionsModal
|
|
471
|
+
v-if="!isHiddenOptionsModal"
|
|
472
|
+
v-model:is-hidden="isHiddenOptionsModal"
|
|
473
|
+
v-model:rank-options="rankOptions"
|
|
474
|
+
:rank="rank"
|
|
475
|
+
/>
|
|
476
|
+
</div>
|
|
468
477
|
</div>
|
|
469
478
|
</template>
|
|
470
479
|
|
|
@@ -54,7 +54,7 @@ function getFirstSolved(p: ProblemStatistics): string {
|
|
|
54
54
|
return "Null";
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
const t =
|
|
57
|
+
const t = p.firstSolveSubmissions[0].timestampToMinute;
|
|
58
58
|
return `${t}`;
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -63,7 +63,7 @@ function getLastSolved(p: ProblemStatistics): string {
|
|
|
63
63
|
return "Null";
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
const t =
|
|
66
|
+
const t = p.lastSolveSubmissions[0].timestampToMinute;
|
|
67
67
|
return `${t}`;
|
|
68
68
|
}
|
|
69
69
|
</script>
|
|
@@ -40,6 +40,8 @@ const title = computed(() => {
|
|
|
40
40
|
return t("type_menu.options");
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
+
const enableAnimatedSubmissions = ref(rankOptions.value.enableAnimatedSubmissions);
|
|
44
|
+
|
|
43
45
|
const orgOptions = computed(() => {
|
|
44
46
|
const res = rank.value.organizations.map((o) => {
|
|
45
47
|
return {
|
|
@@ -93,6 +95,8 @@ function onConfirm() {
|
|
|
93
95
|
localStorage.setItem(localStorageKeyForFilterOrganizations, JSON.stringify(orgSelectedItems.value));
|
|
94
96
|
localStorage.setItem(localStorageKeyForFilterTeams, JSON.stringify(teamsSelectedItems.value));
|
|
95
97
|
|
|
98
|
+
rankOptions.value.enableAnimatedSubmissions = enableAnimatedSubmissions.value;
|
|
99
|
+
|
|
96
100
|
onCancel();
|
|
97
101
|
}
|
|
98
102
|
</script>
|
|
@@ -150,6 +154,32 @@ function onConfirm() {
|
|
|
150
154
|
</div>
|
|
151
155
|
</div>
|
|
152
156
|
|
|
157
|
+
<div
|
|
158
|
+
flex flex-col
|
|
159
|
+
w-full
|
|
160
|
+
>
|
|
161
|
+
<div
|
|
162
|
+
flex
|
|
163
|
+
mb-2
|
|
164
|
+
>
|
|
165
|
+
Feature
|
|
166
|
+
</div>
|
|
167
|
+
|
|
168
|
+
<div
|
|
169
|
+
flex flex-row
|
|
170
|
+
>
|
|
171
|
+
<label class="relative inline-flex items-center cursor-pointer">
|
|
172
|
+
<input
|
|
173
|
+
v-model="enableAnimatedSubmissions"
|
|
174
|
+
type="checkbox"
|
|
175
|
+
class="sr-only peer"
|
|
176
|
+
>
|
|
177
|
+
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600" />
|
|
178
|
+
<span class="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">Animated Submissions</span>
|
|
179
|
+
</label>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
153
183
|
<div
|
|
154
184
|
mt-2
|
|
155
185
|
w-full
|
|
@@ -13,6 +13,8 @@ function onClick() {
|
|
|
13
13
|
|
|
14
14
|
const rank = computed(() => props.rank);
|
|
15
15
|
const problem = computed(() => props.problem);
|
|
16
|
+
|
|
17
|
+
const balloonColor = computed(() => problem.value.balloonColor);
|
|
16
18
|
</script>
|
|
17
19
|
|
|
18
20
|
<template>
|
|
@@ -22,8 +24,8 @@ const problem = computed(() => props.problem);
|
|
|
22
24
|
text-center
|
|
23
25
|
style="width: 3rem;"
|
|
24
26
|
:style="{
|
|
25
|
-
'background-color':
|
|
26
|
-
'color':
|
|
27
|
+
'background-color': balloonColor.background_color,
|
|
28
|
+
'color': balloonColor.color,
|
|
27
29
|
}"
|
|
28
30
|
>
|
|
29
31
|
<div
|
|
@@ -244,11 +244,9 @@ function getProblemLabelColorStyle(s: Submission) {
|
|
|
244
244
|
return undefined;
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
-
const b = p.balloonColor;
|
|
248
|
-
|
|
249
247
|
return {
|
|
250
|
-
backgroundColor:
|
|
251
|
-
color:
|
|
248
|
+
backgroundColor: p.balloonColor.background_color,
|
|
249
|
+
color: p.balloonColor.color,
|
|
252
250
|
};
|
|
253
251
|
}
|
|
254
252
|
</script>
|
|
@@ -21,10 +21,6 @@ const rank = computed(() => props.rank);
|
|
|
21
21
|
const team = computed(() => props.team);
|
|
22
22
|
|
|
23
23
|
function getStandClassName(t: Team, isRankField = false): string {
|
|
24
|
-
if (props.isFilter) {
|
|
25
|
-
return "filter-team";
|
|
26
|
-
}
|
|
27
|
-
|
|
28
24
|
if (isRankField) {
|
|
29
25
|
if (t.awards.includes(MedalType.GOLD)) {
|
|
30
26
|
return "gold";
|
|
@@ -43,6 +39,10 @@ function getStandClassName(t: Team, isRankField = false): string {
|
|
|
43
39
|
}
|
|
44
40
|
}
|
|
45
41
|
|
|
42
|
+
if (props.isFilter) {
|
|
43
|
+
return "filter-team";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
46
|
const solvedProblemIndex = (rank.value.rankStatistics.getTeamSolvedNumIndex(t.solvedProblemNum) - 1) % 2;
|
|
47
47
|
const rankIndex = (t.rank - 1) % 2;
|
|
48
48
|
|
|
@@ -26,15 +26,6 @@ function goCountdown() {
|
|
|
26
26
|
w-full
|
|
27
27
|
flex mt-4 gap-4
|
|
28
28
|
>
|
|
29
|
-
<a
|
|
30
|
-
btn
|
|
31
|
-
:href="resolverUrl"
|
|
32
|
-
target="_blank"
|
|
33
|
-
title="Resolver"
|
|
34
|
-
>
|
|
35
|
-
{{ t("type_menu.resolver") }}
|
|
36
|
-
</a>
|
|
37
|
-
|
|
38
29
|
<button
|
|
39
30
|
btn
|
|
40
31
|
title="Balloon"
|
|
@@ -45,10 +36,10 @@ function goCountdown() {
|
|
|
45
36
|
|
|
46
37
|
<button
|
|
47
38
|
btn
|
|
48
|
-
title="
|
|
49
|
-
|
|
39
|
+
title="Submissions"
|
|
40
|
+
disabled="true"
|
|
50
41
|
>
|
|
51
|
-
{{ t('type_menu.
|
|
42
|
+
{{ t('type_menu.submissions') }}
|
|
52
43
|
</button>
|
|
53
44
|
</div>
|
|
54
45
|
|
|
@@ -56,12 +47,21 @@ function goCountdown() {
|
|
|
56
47
|
w-full
|
|
57
48
|
flex mt-4 gap-4
|
|
58
49
|
>
|
|
50
|
+
<a
|
|
51
|
+
btn
|
|
52
|
+
:href="resolverUrl"
|
|
53
|
+
target="_blank"
|
|
54
|
+
title="Resolver"
|
|
55
|
+
>
|
|
56
|
+
{{ t("type_menu.resolver") }}
|
|
57
|
+
</a>
|
|
58
|
+
|
|
59
59
|
<button
|
|
60
60
|
btn
|
|
61
|
-
title="
|
|
62
|
-
|
|
61
|
+
title="Countdown"
|
|
62
|
+
@click="goCountdown"
|
|
63
63
|
>
|
|
64
|
-
{{ t('type_menu.
|
|
64
|
+
{{ t('type_menu.countdown') }}
|
|
65
65
|
</button>
|
|
66
66
|
</div>
|
|
67
67
|
</template>
|
package/src/components.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export {}
|
|
|
7
7
|
|
|
8
8
|
declare module 'vue' {
|
|
9
9
|
export interface GlobalComponents {
|
|
10
|
+
AnimatedSubmissionsModal: typeof import('./components/board/AnimatedSubmissionsModal.vue')['default']
|
|
10
11
|
Badge: typeof import('./components/board/Badge.vue')['default']
|
|
11
12
|
Balloon: typeof import('./components/Balloon.vue')['default']
|
|
12
13
|
BalloonBlock: typeof import('./components/BalloonBlock.vue')['default']
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { MedalType } from "@xcpcio/core";
|
|
2
|
+
import type { Team } from "@xcpcio/core";
|
|
3
|
+
|
|
4
|
+
export function getMedalColor(team: Team): { backgroundColor: string, color: string } | undefined {
|
|
5
|
+
const color = {
|
|
6
|
+
backgroundColor: "#fff",
|
|
7
|
+
color: "#000",
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
if (team.awards.includes(MedalType.GOLD)) {
|
|
11
|
+
color.backgroundColor = "#fff566";
|
|
12
|
+
return color;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (team.awards.includes(MedalType.SILVER)) {
|
|
16
|
+
color.backgroundColor = "#ffadd2";
|
|
17
|
+
return color;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (team.awards.includes(MedalType.BRONZE)) {
|
|
21
|
+
color.backgroundColor = "#f0c0a0";
|
|
22
|
+
return color;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (team.awards.includes(MedalType.HONORABLE)) {
|
|
26
|
+
color.backgroundColor = "#e6f7ff";
|
|
27
|
+
return color;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
.PENDING {
|
|
2
|
+
background-color: var(--theme-status-pending);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.WAITING {
|
|
6
|
+
background-color: var(--theme-status-waiting);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.PREPARING {
|
|
10
|
+
background-color: var(--theme-status-preparing);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.COMPILING {
|
|
14
|
+
background-color: var(--theme-status-compiling);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.RUNNING {
|
|
18
|
+
background-color: var(--theme-status-running);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.JUDGING {
|
|
22
|
+
background-color: var(--theme-status-running);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.FROZEN {
|
|
26
|
+
background-color: var(--theme-status-pending);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
.ACCEPTED {
|
|
31
|
+
background-color: var(--theme-status-accepted);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.CORRECT {
|
|
35
|
+
background-color: var(--theme-status-accepted);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.PARTIALLY_CORRECT {
|
|
39
|
+
background-color: var(--theme-status-partially-correct);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
.REJECTED {
|
|
44
|
+
background-color: var(--theme-status-wrong-answer);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.WRONG_ANSWER {
|
|
48
|
+
background-color: var(--theme-status-wrong-answer);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
.COMPILATION_ERROR {
|
|
53
|
+
background-color: var(--theme-status-compilation-error);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.PRESENTATION_ERROR {
|
|
57
|
+
background-color: var(--theme-status-compilation-error);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
.RUNTIME_ERROR {
|
|
62
|
+
background-color: var(--theme-status-runtime-error);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.TIME_LIMIT_EXCEEDED {
|
|
66
|
+
background-color: var(--theme-status-time-limit-exceeded);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.MEMORY_LIMIT_EXCEEDED {
|
|
70
|
+
background-color: var(--theme-status-memory-limit-exceeded);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.OUTPUT_LIMIT_EXCEEDED {
|
|
74
|
+
background-color: var(--theme-status-output-limit-exceeded);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.IDLENESS_LIMIT_EXCEEDED {
|
|
78
|
+
background-color: var(--theme-status-output-limit-exceeded);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.HACKED {
|
|
82
|
+
background-color: var(--theme-status-wrong-answer);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.JUDGEMENT_FAILED {
|
|
86
|
+
background-color: var(--theme-status-judgement-failed);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.CONFIGURATION_ERROR {
|
|
90
|
+
background-color: var(--theme-status-configuration-error);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.FILE_ERROR {
|
|
94
|
+
background-color: var(--theme-status-file-error);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.SYSTEM_ERROR {
|
|
98
|
+
background-color: var(--theme-status-system-error);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.CANCELED {
|
|
102
|
+
background-color: var(--theme-status-canceled);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.SKIPPED {
|
|
106
|
+
background-color: var(--theme-status-skipped);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.SECURITY_VIOLATED {
|
|
110
|
+
background-color: var(--theme-status-judgement-failed);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.DENIAL_OF_JUDGEMENT {
|
|
114
|
+
background-color: var(--theme-status-judgement-failed);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.UNKNOWN {
|
|
118
|
+
background-color: var(--theme-status-unknown);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.UNDEFINED {
|
|
122
|
+
background-color: var(--theme-status-undefined);
|
|
123
|
+
}
|
package/vite.config.ts
CHANGED
|
@@ -16,6 +16,7 @@ import Unocss from "unocss/vite";
|
|
|
16
16
|
import Shiki from "markdown-it-shiki";
|
|
17
17
|
import VueMacros from "unplugin-vue-macros/vite";
|
|
18
18
|
import WebfontDownload from "vite-plugin-webfont-dl";
|
|
19
|
+
import { createHtmlPlugin } from "vite-plugin-html";
|
|
19
20
|
|
|
20
21
|
import packageJSON from "./package.json";
|
|
21
22
|
|
|
@@ -138,6 +139,21 @@ export default defineConfig({
|
|
|
138
139
|
|
|
139
140
|
// https://github.com/webfansplz/vite-plugin-vue-devtools
|
|
140
141
|
VueDevTools(),
|
|
142
|
+
|
|
143
|
+
// https://github.com/vbenjs/vite-plugin-html
|
|
144
|
+
createHtmlPlugin({
|
|
145
|
+
minify: {
|
|
146
|
+
collapseWhitespace: true,
|
|
147
|
+
keepClosingSlash: true,
|
|
148
|
+
removeComments: true,
|
|
149
|
+
removeRedundantAttributes: true,
|
|
150
|
+
removeScriptTypeAttributes: true,
|
|
151
|
+
removeStyleLinkTypeAttributes: true,
|
|
152
|
+
useShortDoctype: true,
|
|
153
|
+
minifyCSS: true,
|
|
154
|
+
minifyJS: true,
|
|
155
|
+
},
|
|
156
|
+
}),
|
|
141
157
|
],
|
|
142
158
|
|
|
143
159
|
// https://github.com/vitest-dev/vitest
|