@xcpcio/board-app 0.30.0 → 0.31.1
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-1cb5a052.js → Board-ce0a2c6c.js} +3 -3
- package/dist/assets/DataSourceInput.vue_vue_type_script_setup_true_lang-b87eba77.js +1 -0
- package/dist/assets/{TheInput.vue_vue_type_script_setup_true_lang-bd490116.js → TheInput.vue_vue_type_script_setup_true_lang-079f8c80.js} +1 -1
- package/dist/assets/{_...all_-b2ba251c.js → _...all_-019b03b8.js} +1 -1
- package/dist/assets/{_name_-abd07bc1.js → _name_-6a3b59a1.js} +1 -1
- package/dist/assets/{about-64b5108b.js → about-f9061b17.js} +1 -1
- package/dist/assets/board-6d208112.js +1 -0
- package/dist/assets/{board-layout-1eaf73df.js → board-layout-5590c53f.js} +1 -1
- package/dist/assets/{en-644e039f.js → en-06ebe6c4.js} +1 -1
- package/dist/assets/{headless-e800ef5b.js → headless-94485ccd.js} +1 -1
- package/dist/assets/{home-2a74cabc.js → home-e847177d.js} +1 -1
- package/dist/assets/index-3735f4c2.js +1 -0
- package/dist/assets/index-4b46c3f4.js +1 -0
- package/dist/assets/index-622de38d.css +1 -0
- package/dist/assets/{index-6578287f.js → index-7a9bcf50.js} +43 -43
- package/dist/assets/{index-184e36da.css → index-d429549a.css} +1 -1
- package/dist/assets/{index-layout-a0249ba4.js → index-layout-3f26f613.js} +1 -1
- package/dist/assets/{test-c0da21d8.js → test-24dab276.js} +1 -1
- package/dist/assets/{useQueryBoardData-3b8a91d5.js → useQueryBoardData-b6644ecd.js} +1 -1
- package/dist/assets/{user-69e7d90e.js → user-7a10fa8c.js} +1 -1
- package/dist/assets/{virtual_pwa-register-7796129c.js → virtual_pwa-register-41acaeb8.js} +1 -1
- package/dist/assets/{zh-CN-44b801f0.js → zh-CN-582540fd.js} +1 -1
- package/dist/index.html +3 -3
- package/dist/sw.js +1 -1
- package/package.json +3 -3
- package/src/auto-imports.d.ts +3 -0
- package/src/components/Balloon.vue +2 -1
- package/src/components/Countdown.vue +132 -0
- package/src/components/CustomCountdown.vue +25 -0
- package/src/components/board/TeamAwards.vue +49 -19
- package/src/components/board/TeamInfoModal.vue +0 -3
- package/src/components/board/Utility.vue +17 -0
- package/src/components.d.ts +2 -0
- package/src/composables/constant.ts +1 -0
- package/src/pages/countdown/index.vue +10 -0
- package/src/pages/index.vue +13 -6
- package/dist/assets/DataSourceInput.vue_vue_type_script_setup_true_lang-c6907218.js +0 -1
- package/dist/assets/board-85ce205a.js +0 -1
- package/dist/assets/index-78001918.js +0 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { createContest } from "@xcpcio/core";
|
|
3
|
+
import type { Contest } from "@xcpcio/core";
|
|
4
|
+
import { ContestState } from "@xcpcio/types";
|
|
5
|
+
import type { Contest as IContest } from "@xcpcio/types";
|
|
6
|
+
|
|
7
|
+
const props = defineProps<{
|
|
8
|
+
dataSourceUrl: string,
|
|
9
|
+
}>();
|
|
10
|
+
|
|
11
|
+
const { t } = useI18n();
|
|
12
|
+
const title = useTitle(COUNTDOWN_TITLE_SUFFIX);
|
|
13
|
+
|
|
14
|
+
const now = ref(new Date());
|
|
15
|
+
const contest = ref({} as Contest);
|
|
16
|
+
const firstLoaded = ref(false);
|
|
17
|
+
|
|
18
|
+
const { data, isError, error } = useQueryBoardData(props.dataSourceUrl, now);
|
|
19
|
+
watch(data, async () => {
|
|
20
|
+
if (data.value === null || data.value === undefined) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
contest.value = createContest(data.value?.contest as IContest);
|
|
25
|
+
title.value = `${contest.value.name} | ${COUNTDOWN_TITLE_SUFFIX}`;
|
|
26
|
+
|
|
27
|
+
firstLoaded.value = true;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const setNowIntervalId = setInterval(() => {
|
|
31
|
+
now.value = new Date();
|
|
32
|
+
}, 1000);
|
|
33
|
+
|
|
34
|
+
onUnmounted(() => {
|
|
35
|
+
clearInterval(setNowIntervalId);
|
|
36
|
+
});
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<template>
|
|
40
|
+
<div
|
|
41
|
+
class="background"
|
|
42
|
+
text-gray-200
|
|
43
|
+
w-screen
|
|
44
|
+
h-screen
|
|
45
|
+
>
|
|
46
|
+
<div v-if="!firstLoaded">
|
|
47
|
+
<div
|
|
48
|
+
flex flex-col
|
|
49
|
+
justify-center items-center
|
|
50
|
+
w-screen h-screen
|
|
51
|
+
text-xl italic
|
|
52
|
+
>
|
|
53
|
+
<div>
|
|
54
|
+
{{ t("common.loading") }}...
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<div v-if="isError">
|
|
58
|
+
{{ error }}
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<div
|
|
64
|
+
v-else
|
|
65
|
+
>
|
|
66
|
+
<div
|
|
67
|
+
flex flex-col
|
|
68
|
+
items-center justify-center
|
|
69
|
+
font-mono
|
|
70
|
+
>
|
|
71
|
+
<div
|
|
72
|
+
mt-20
|
|
73
|
+
text-5xl
|
|
74
|
+
>
|
|
75
|
+
{{ contest.name }}
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<div
|
|
79
|
+
mt-20
|
|
80
|
+
text-6xl
|
|
81
|
+
:class="[contest.getContestState(now).toString()]"
|
|
82
|
+
>
|
|
83
|
+
{{ contest.getContestState(now) }}
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div
|
|
87
|
+
mt-20
|
|
88
|
+
class="text-[320px]"
|
|
89
|
+
:class="[contest.getContestState(now).toString()]"
|
|
90
|
+
>
|
|
91
|
+
<div
|
|
92
|
+
v-if="contest.getContestState(now) === ContestState.PENDING"
|
|
93
|
+
>
|
|
94
|
+
{{ contest.getContestPendingTime(now) }}
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
<div
|
|
98
|
+
v-else
|
|
99
|
+
>
|
|
100
|
+
{{ contest.getContestElapsedTime(now) }}
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
</template>
|
|
107
|
+
|
|
108
|
+
<style scoped>
|
|
109
|
+
.background {
|
|
110
|
+
background-color: #333443;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.PENDING {
|
|
114
|
+
color: #3bb4f2;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.RUNNING {
|
|
118
|
+
color: rgb(94, 185, 94);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.FROZEN {
|
|
122
|
+
color: #dd514c;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.FINISHED {
|
|
126
|
+
color: #0e90d2;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.PAUSED {
|
|
130
|
+
color: #3bb4f2;
|
|
131
|
+
}
|
|
132
|
+
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { getDataSourceUrl } from "~/composables/query";
|
|
3
|
+
|
|
4
|
+
const dataSourceUrl = getDataSourceUrl();
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<div
|
|
9
|
+
v-if="dataSourceUrl.length === 0"
|
|
10
|
+
>
|
|
11
|
+
<div
|
|
12
|
+
mt-20
|
|
13
|
+
>
|
|
14
|
+
<DataSourceInput />
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div
|
|
19
|
+
v-if="dataSourceUrl.length > 0"
|
|
20
|
+
>
|
|
21
|
+
<Countdown
|
|
22
|
+
:data-source-url="dataSourceUrl"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
</template>
|
|
@@ -53,6 +53,28 @@ const medal = computed((): Medal | null => {
|
|
|
53
53
|
|
|
54
54
|
return null;
|
|
55
55
|
});
|
|
56
|
+
|
|
57
|
+
const place = computed(() => {
|
|
58
|
+
let r = team.value.rank;
|
|
59
|
+
|
|
60
|
+
if (rank.value.contest.organization) {
|
|
61
|
+
r = team.value.organizationRank;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (r === 1) {
|
|
65
|
+
return "1st Place";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (r === 2) {
|
|
69
|
+
return "2nd Place";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (r === 3) {
|
|
73
|
+
return "3rd Place";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return "";
|
|
77
|
+
});
|
|
56
78
|
</script>
|
|
57
79
|
|
|
58
80
|
<template>
|
|
@@ -61,31 +83,39 @@ const medal = computed((): Medal | null => {
|
|
|
61
83
|
text-xl
|
|
62
84
|
font-mono font-semibold italic
|
|
63
85
|
flex flex-col gap-2
|
|
64
|
-
justify-center
|
|
86
|
+
justify-center items-center
|
|
65
87
|
>
|
|
66
|
-
<div>
|
|
67
|
-
Team Rank: {{ team.rank }}
|
|
68
|
-
</div>
|
|
69
|
-
|
|
70
88
|
<div
|
|
71
|
-
|
|
89
|
+
flex flex-col
|
|
90
|
+
items-start
|
|
91
|
+
gap-y-2
|
|
72
92
|
>
|
|
73
|
-
|
|
74
|
-
|
|
93
|
+
<div
|
|
94
|
+
v-if="medal"
|
|
95
|
+
>
|
|
96
|
+
{{ medal.text }} Medalist
|
|
97
|
+
</div>
|
|
75
98
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
<div>
|
|
81
|
-
First Solved Problem {{ firstSolvedProblems }}
|
|
99
|
+
<div
|
|
100
|
+
v-if="place.length > 0"
|
|
101
|
+
>
|
|
102
|
+
{{ place }}
|
|
82
103
|
</div>
|
|
83
|
-
</div>
|
|
84
104
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
105
|
+
<div
|
|
106
|
+
v-if="firstSolvedProblems.length"
|
|
107
|
+
flex flex-col gap-2
|
|
108
|
+
>
|
|
109
|
+
<div>
|
|
110
|
+
First Solved Problem {{ firstSolvedProblems }}
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<div
|
|
115
|
+
v-if="team.solvedProblemNum > 0"
|
|
116
|
+
>
|
|
117
|
+
Solved {{ team.solvedProblemNum }} {{ team.solvedProblemNum > 1 ? 'Problems' : 'Problem' }}
|
|
118
|
+
</div>
|
|
89
119
|
</div>
|
|
90
120
|
</div>
|
|
91
121
|
</template>
|
|
@@ -15,6 +15,10 @@ const resolverUrl = computed(() => {
|
|
|
15
15
|
function goBalloon() {
|
|
16
16
|
router.push(`/balloon/?data-source=${route.path}`);
|
|
17
17
|
}
|
|
18
|
+
|
|
19
|
+
function goCountdown() {
|
|
20
|
+
router.push(`/countdown/?data-source=${route.path}`);
|
|
21
|
+
}
|
|
18
22
|
</script>
|
|
19
23
|
|
|
20
24
|
<template>
|
|
@@ -39,6 +43,19 @@ function goBalloon() {
|
|
|
39
43
|
{{ t('type_menu.balloon') }}
|
|
40
44
|
</button>
|
|
41
45
|
|
|
46
|
+
<button
|
|
47
|
+
btn
|
|
48
|
+
title="Countdown"
|
|
49
|
+
@click="goCountdown"
|
|
50
|
+
>
|
|
51
|
+
{{ t('type_menu.countdown') }}
|
|
52
|
+
</button>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<div
|
|
56
|
+
w-full
|
|
57
|
+
flex mt-4 gap-4
|
|
58
|
+
>
|
|
42
59
|
<button
|
|
43
60
|
btn
|
|
44
61
|
title="Submissions"
|
package/src/components.d.ts
CHANGED
|
@@ -15,8 +15,10 @@ declare module 'vue' {
|
|
|
15
15
|
BottomStatistics: typeof import('./components/board/BottomStatistics.vue')['default']
|
|
16
16
|
ContestIndexUI: typeof import('./components/ContestIndexUI.vue')['default']
|
|
17
17
|
ContestStateBadge: typeof import('./components/board/ContestStateBadge.vue')['default']
|
|
18
|
+
Countdown: typeof import('./components/Countdown.vue')['default']
|
|
18
19
|
CustomBalloon: typeof import('./components/CustomBalloon.vue')['default']
|
|
19
20
|
CustomBoard: typeof import('./components/CustomBoard.vue')['default']
|
|
21
|
+
CustomCountdown: typeof import('./components/CustomCountdown.vue')['default']
|
|
20
22
|
DataSourceInput: typeof import('./components/DataSourceInput.vue')['default']
|
|
21
23
|
Export: typeof import('./components/board/Export.vue')['default']
|
|
22
24
|
Footer: typeof import('./components/Footer.vue')['default']
|
package/src/pages/index.vue
CHANGED
|
@@ -79,15 +79,22 @@ watch(searchText, () => {
|
|
|
79
79
|
>
|
|
80
80
|
<div>
|
|
81
81
|
<div
|
|
82
|
-
v-if="isFetching"
|
|
82
|
+
v-if="isFetching || error"
|
|
83
|
+
mt-4 mb-4
|
|
83
84
|
class="sm:w-[1000px] lg:w-screen"
|
|
84
|
-
flex justify-center
|
|
85
|
+
flex justify-center items-center
|
|
85
86
|
>
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
<div
|
|
88
|
+
v-if="isFetching"
|
|
89
|
+
>
|
|
90
|
+
{{ t("common.loading") }}...
|
|
91
|
+
</div>
|
|
88
92
|
|
|
89
|
-
|
|
90
|
-
|
|
93
|
+
<div
|
|
94
|
+
v-if="error"
|
|
95
|
+
>
|
|
96
|
+
{{ error }}
|
|
97
|
+
</div>
|
|
91
98
|
</div>
|
|
92
99
|
|
|
93
100
|
<div
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{_}from"./TheInput.vue_vue_type_script_setup_true_lang-bd490116.js";import{H as p,g as f,q as h,i as g,I as S,D as b,j as o,o as v,c as y,d as t,b as x,E as U,G as V,t as l,l as w}from"./index-6578287f.js";function D(){return p("data-source","",{transform:String})}const I={key:0,class:"flex flex-col items-center"},R={"w-128":""},k=t("div",{"py-2":""},null,-1),B=["disabled"],u="Data Source URL",E=f({__name:"DataSourceInput",setup(C){const{t:r}=h(),a=D(),e=g(a.value),c=S(),d=b();function s(){d.push(`${c.fullPath}/?data-source=${e.value.trim()}`)}return(K,n)=>{const i=_;return o(a).length===0?(v(),y("div",I,[t("div",R,[x(i,{modelValue:o(e),"onUpdate:modelValue":n[0]||(n[0]=m=>U(e)?e.value=m:null),"w-full":"",placeholder:u,autocomplete:"false",onKeydown:V(s,["enter"])},null,8,["modelValue","onKeydown"]),t("label",{class:"hidden",for:"input"},l(u))]),k,t("div",null,[t("button",{"m-3":"","text-sm":"",btn:"",disabled:o(e).length===0,onClick:s},l(o(r)("button.go")),9,B)])])):w("",!0)}}});export{E as _,D as g};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{_ as p}from"./Board-1cb5a052.js";import{g as l,_ as d}from"./DataSourceInput.vue_vue_type_script_setup_true_lang-c6907218.js";import{g as f,o as t,c as n,b as a,j as r,l as i,F as g,a as B,A as k,C as c}from"./index-6578287f.js";import"./useQueryBoardData-3b8a91d5.js";import"./TheInput.vue_vue_type_script_setup_true_lang-bd490116.js";const C={key:0},h=f({__name:"CustomBoard",setup(_){const o=l();return(e,b)=>{const m=d,u=p;return t(),n(g,null,[a(m),r(o).length>0?(t(),n("div",C,[a(u,{"data-source-url":r(o)},null,8,["data-source-url"])])):i("",!0)],64)}}}),s={};function x(_,o){const e=h;return t(),k(e)}typeof c=="function"&&c(s);const U=B(s,[["render",x]]);export{U as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{g as C,h as w,i as u,u as V,o,c as n,j as t,n as E,d as s,k as S,t as p,l as g,m as F,p as R,B as I,q as A,w as O,s as q,v as M,x as Q,y as X,F as N,z as G,A as H,R as J,b as $,a as K,C as j}from"./index-6578287f.js";import{u as P}from"./useQueryBoardData-3b8a91d5.js";import{g as W,_ as Y}from"./DataSourceInput.vue_vue_type_script_setup_true_lang-c6907218.js";import"./TheInput.vue_vue_type_script_setup_true_lang-bd490116.js";const Z={flex:"","flex-1":"","flex-col":"","justify-center":"","items-start":""},ee={class:"resolver-team-name",truncate:"","overflow-hidden":""},te=s("div",{flex:"","flex-row":"","text-sm":"","items-start":"","gap-x-2":""},null,-1),oe={"w-32":"",flex:"","flex-shrink-0":"","flex-row":"","justify-start":"","items-center":""},ne=C({__name:"BalloonBlock",props:{index:null,balloon:null},setup(f){const a=f,_=w(()=>a.index),r=w(()=>a.balloon),c=u(null),i=V(c);function x(e){return[e.location,e.organization,e.name].filter(d=>d).join(" - ")}function v(e){return typeof e=="string"?e:F&&(e!=null&&e.dark)?e.dark:e.light}return(e,b)=>{var d,l,h,k;return o(),n("div",{ref_key:"el",ref:c,"h-24":""},[t(i)?(o(),n("div",{key:0,"h-24":"",flex:"","flex-row":"","gap-x-4":"","font-mono":"","text-4xl":"",class:E([t(_)%2===0?"bg-resolver-bg-zero":"bg-resolver-bg-one"])},[s("div",{"w-20":"",flex:"","flex-shrink-0":"","justify-center":"","items-center":"",style:S({backgroundColor:v(((l=(d=t(r).problem)==null?void 0:d.balloonColor)==null?void 0:l.background_color)??"rgba(0, 0, 0, 0.5)")})},[s("div",{style:S({color:v(((k=(h=t(r).problem)==null?void 0:h.balloonColor)==null?void 0:k.color)??"#fff")})},p(t(r).problem.label),5)],4),s("div",Z,[s("div",ee,p(x(t(r).team)),1),te]),s("div",oe,p(t(r).submission.timestampToMinute),1)],2)):g("",!0)],512)}}}),se={class:"bg-[#323443]","text-gray-200":""},ae={key:0},le={flex:"","flex-col":"","justify-center":"","items-center":"","w-screen":"","h-screen":"","text-xl":"",italic:""},re={key:0},ce={key:1},ie={flex:"","flex-col":"","justify-between":""},ue=C({__name:"Balloon",props:{dataSourceUrl:null},setup(f){const a=f,_=R(I),{t:r}=A(),c=u(!1),i=u({}),x=u([]),v=u([]),e=u({}),b=u(new Date);function d(){const m=new J(i.value,x.value,v.value);m.buildBalloons(),e.value=m}const{data:l,isError:h,error:k}=P(a.dataSourceUrl,b);O(l,async()=>{var m,B,y;l.value===null||l.value===void 0||(i.value=q((m=l.value)==null?void 0:m.contest),_.value=`${i.value.name} | ${I}`,x.value=M((B=l.value)==null?void 0:B.teams),v.value=Q((y=l.value)==null?void 0:y.submissions),d(),c.value=!0)});const U=w(()=>e.value.balloons),z=setInterval(()=>{b.value=new Date},1e3);return X(()=>{clearInterval(z)}),(m,B)=>{const y=ne;return o(),n("div",se,[t(c)?(o(),n("div",ce,[s("div",ie,[(o(!0),n(N,null,G(t(U),(D,L)=>(o(),H(y,{key:D.key,index:L,balloon:D},null,8,["index","balloon"]))),128))])])):(o(),n("div",ae,[s("div",le,[s("div",null,p(t(r)("common.loading"))+"... ",1),t(h)?(o(),n("div",re,p(t(k)),1)):g("",!0)])]))])}}}),_e={key:0},de={"mt-20":""},me={key:1},fe=C({__name:"CustomBalloon",setup(f){const a=W();return(_,r)=>{const c=Y,i=ue;return o(),n(N,null,[t(a).length===0?(o(),n("div",_e,[s("div",de,[$(c)])])):g("",!0),t(a).length>0?(o(),n("div",me,[$(i,{"data-source-url":t(a)},null,8,["data-source-url"])])):g("",!0)],64)}}}),T={};function ve(f,a){const _=fe;return o(),n("div",null,[$(_)])}typeof j=="function"&&j(T);const ke=K(T,[["render",ve]]);export{ke as default};
|