@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.
Files changed (39) hide show
  1. package/dist/assets/{Board-1cb5a052.js → Board-ce0a2c6c.js} +3 -3
  2. package/dist/assets/DataSourceInput.vue_vue_type_script_setup_true_lang-b87eba77.js +1 -0
  3. 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
  4. package/dist/assets/{_...all_-b2ba251c.js → _...all_-019b03b8.js} +1 -1
  5. package/dist/assets/{_name_-abd07bc1.js → _name_-6a3b59a1.js} +1 -1
  6. package/dist/assets/{about-64b5108b.js → about-f9061b17.js} +1 -1
  7. package/dist/assets/board-6d208112.js +1 -0
  8. package/dist/assets/{board-layout-1eaf73df.js → board-layout-5590c53f.js} +1 -1
  9. package/dist/assets/{en-644e039f.js → en-06ebe6c4.js} +1 -1
  10. package/dist/assets/{headless-e800ef5b.js → headless-94485ccd.js} +1 -1
  11. package/dist/assets/{home-2a74cabc.js → home-e847177d.js} +1 -1
  12. package/dist/assets/index-3735f4c2.js +1 -0
  13. package/dist/assets/index-4b46c3f4.js +1 -0
  14. package/dist/assets/index-622de38d.css +1 -0
  15. package/dist/assets/{index-6578287f.js → index-7a9bcf50.js} +43 -43
  16. package/dist/assets/{index-184e36da.css → index-d429549a.css} +1 -1
  17. package/dist/assets/{index-layout-a0249ba4.js → index-layout-3f26f613.js} +1 -1
  18. package/dist/assets/{test-c0da21d8.js → test-24dab276.js} +1 -1
  19. package/dist/assets/{useQueryBoardData-3b8a91d5.js → useQueryBoardData-b6644ecd.js} +1 -1
  20. package/dist/assets/{user-69e7d90e.js → user-7a10fa8c.js} +1 -1
  21. package/dist/assets/{virtual_pwa-register-7796129c.js → virtual_pwa-register-41acaeb8.js} +1 -1
  22. package/dist/assets/{zh-CN-44b801f0.js → zh-CN-582540fd.js} +1 -1
  23. package/dist/index.html +3 -3
  24. package/dist/sw.js +1 -1
  25. package/package.json +3 -3
  26. package/src/auto-imports.d.ts +3 -0
  27. package/src/components/Balloon.vue +2 -1
  28. package/src/components/Countdown.vue +132 -0
  29. package/src/components/CustomCountdown.vue +25 -0
  30. package/src/components/board/TeamAwards.vue +49 -19
  31. package/src/components/board/TeamInfoModal.vue +0 -3
  32. package/src/components/board/Utility.vue +17 -0
  33. package/src/components.d.ts +2 -0
  34. package/src/composables/constant.ts +1 -0
  35. package/src/pages/countdown/index.vue +10 -0
  36. package/src/pages/index.vue +13 -6
  37. package/dist/assets/DataSourceInput.vue_vue_type_script_setup_true_lang-c6907218.js +0 -1
  38. package/dist/assets/board-85ce205a.js +0 -1
  39. 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
- v-if="team.organization && team.organizationRank !== -1"
89
+ flex flex-col
90
+ items-start
91
+ gap-y-2
72
92
  >
73
- {{ rank.contest.organization }} Rank: {{ team.organizationRank }}
74
- </div>
93
+ <div
94
+ v-if="medal"
95
+ >
96
+ {{ medal.text }} Medalist
97
+ </div>
75
98
 
76
- <div
77
- v-if="firstSolvedProblems.length"
78
- flex flex-col gap-2
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
- <div
86
- v-if="medal"
87
- >
88
- {{ medal.text }} Medal
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>
@@ -97,9 +97,6 @@ const types = [TYPE_SUBMISSIONS, TYPE_STATISTICS, TYPE_AWARDS];
97
97
  <div>
98
98
  TeamID: {{ team.id }}
99
99
  </div>
100
- <div>
101
- ddd: f22
102
- </div>
103
100
  </div>
104
101
  </template>
105
102
  </Tooltip>
@@ -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"
@@ -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']
@@ -1,3 +1,4 @@
1
1
  export const TITLE_SUFFIX = "Board - XCPCIO";
2
2
  export const BALLOON_TITLE_SUFFIX = "Balloon - XCPCIO";
3
3
  export const RESOLVER_TITLE_SUFFIX = "Resolver - XCPCIO";
4
+ export const COUNTDOWN_TITLE_SUFFIX = "Countdown - XCPCIO";
@@ -0,0 +1,10 @@
1
+ <template>
2
+ <div>
3
+ <CustomCountdown />
4
+ </div>
5
+ </template>
6
+
7
+ <route lang="yaml">
8
+ meta:
9
+ layout: headless
10
+ </route>
@@ -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
- {{ t("common.loading") }}...
87
- </div>
87
+ <div
88
+ v-if="isFetching"
89
+ >
90
+ {{ t("common.loading") }}...
91
+ </div>
88
92
 
89
- <div v-if="error">
90
- {{ error }}
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};