@xcpcio/board-app 0.6.3 → 0.13.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.
Files changed (112) hide show
  1. package/.eslintrc.json +6 -0
  2. package/LICENSE +1 -1
  3. package/README.md +13 -30
  4. package/cypress.config.ts +14 -0
  5. package/dist/_headers +3 -0
  6. package/dist/about.html +11 -0
  7. package/dist/assets/_...all_-27c7ae93.css +1 -0
  8. package/dist/assets/_...all_-d56798b5.js +3 -0
  9. package/dist/assets/_name_-8eab6137.js +1 -0
  10. package/dist/assets/about-a8cb8700.js +11 -0
  11. package/dist/assets/app-37f77a84.js +65 -0
  12. package/dist/assets/board-layout-deaedfc1.js +1 -0
  13. package/dist/assets/en-caedd340.js +1 -0
  14. package/dist/assets/home-49c336e5.js +1 -0
  15. package/dist/assets/index-a270cacd.css +5 -0
  16. package/dist/assets/index-layout-d65c80ea.js +1 -0
  17. package/dist/assets/test-0a3d6f7a.js +1 -0
  18. package/dist/assets/user-108782a1.js +1 -0
  19. package/dist/assets/virtual_pwa-register-1c1b9161.js +1 -0
  20. package/dist/assets/workbox-window.prod.es5-a7b12eab.js +2 -0
  21. package/dist/assets/zh-CN-86269804.js +1 -0
  22. package/dist/favicon-dark.svg +1 -0
  23. package/dist/favicon.svg +1 -0
  24. package/dist/index.html +1 -171
  25. package/dist/manifest.webmanifest +1 -0
  26. package/dist/pwa-192x192.png +0 -0
  27. package/dist/pwa-512x512.png +0 -0
  28. package/dist/robots.txt +4 -0
  29. package/dist/safari-pinned-tab.svg +41 -0
  30. package/dist/sitemap.xml +1 -0
  31. package/dist/ssr-manifest.json +486 -0
  32. package/dist/sw.js +1 -0
  33. package/dist/test.html +1 -0
  34. package/dist/workbox-b8d87ee1.js +1 -0
  35. package/package.json +94 -50
  36. package/public/_headers +3 -0
  37. package/public/favicon-dark.svg +1 -0
  38. package/public/favicon.svg +1 -0
  39. package/public/pwa-192x192.png +0 -0
  40. package/public/pwa-512x512.png +0 -0
  41. package/public/safari-pinned-tab.svg +41 -0
  42. package/src/App.vue +33 -0
  43. package/src/auto-imports.d.ts +909 -0
  44. package/src/components/ContestIndex.vue +227 -0
  45. package/src/components/Footer.vue +94 -0
  46. package/src/components/GoBack.vue +22 -0
  47. package/src/components/NavBar.vue +152 -0
  48. package/src/components/SearchInput.vue +50 -0
  49. package/src/components/TheCounter.vue +19 -0
  50. package/src/components/TheInput.vue +20 -0
  51. package/src/components/board/Balloon.vue +5 -0
  52. package/src/components/board/Board.vue +396 -0
  53. package/src/components/board/BottomStatistics.vue +159 -0
  54. package/src/components/board/ContestStateBadge.vue +41 -0
  55. package/src/components/board/Export.vue +75 -0
  56. package/src/components/board/Modal.vue +107 -0
  57. package/src/components/board/ModalMenu.vue +64 -0
  58. package/src/components/board/OptionsModal.vue +179 -0
  59. package/src/components/board/Progress.less +442 -0
  60. package/src/components/board/Progress.vue +229 -0
  61. package/src/components/board/SecondLevelMenu.vue +190 -0
  62. package/src/components/board/Standings.less +1162 -0
  63. package/src/components/board/Standings.vue +154 -0
  64. package/src/components/board/StandingsAnnotate.vue +38 -0
  65. package/src/components/board/Statistics.vue +77 -0
  66. package/src/components/board/SubmissionsTable.vue +312 -0
  67. package/src/components/board/SubmissionsTableModal.vue +52 -0
  68. package/src/components/board/TeamAwards.vue +93 -0
  69. package/src/components/board/TeamInfoModal.vue +128 -0
  70. package/src/components/board/TeamProblemBlock.vue +100 -0
  71. package/src/components/board/TeamUI.vue +161 -0
  72. package/src/components/board/Utility.vue +28 -0
  73. package/src/components/icon/GirlIcon.vue +80 -0
  74. package/src/components/icon/RightArrowIcon.vue +26 -0
  75. package/src/components/icon/StarIcon.vue +19 -0
  76. package/src/components/table/TablePagination.vue +108 -0
  77. package/src/components.d.ts +44 -0
  78. package/src/composables/dark.ts +4 -0
  79. package/src/composables/pagination.ts +81 -0
  80. package/src/composables/statistics.ts +280 -0
  81. package/src/composables/useLocalStorage.ts +29 -0
  82. package/src/composables/useQueryBoardData.ts +43 -0
  83. package/src/composables/utils.ts +11 -0
  84. package/src/layouts/board-layout.vue +14 -0
  85. package/src/layouts/default.vue +10 -0
  86. package/src/layouts/home.vue +12 -0
  87. package/src/layouts/index-layout.vue +15 -0
  88. package/src/main.ts +36 -0
  89. package/src/modules/README.md +11 -0
  90. package/src/modules/i18n.ts +52 -0
  91. package/src/modules/nprogress.ts +15 -0
  92. package/src/modules/pinia.ts +18 -0
  93. package/src/modules/pwa.ts +15 -0
  94. package/src/modules/toast.ts +10 -0
  95. package/src/pages/[...all].vue +34 -0
  96. package/src/pages/about.md +21 -0
  97. package/src/pages/hi/[name].vue +50 -0
  98. package/src/pages/index.vue +129 -0
  99. package/src/pages/test.vue +57 -0
  100. package/src/shims.d.ts +16 -0
  101. package/src/stores/user.ts +36 -0
  102. package/src/styles/color.css +51 -0
  103. package/src/styles/main.css +30 -0
  104. package/src/styles/markdown.css +28 -0
  105. package/src/styles/submission-status.css +123 -0
  106. package/src/types.ts +3 -0
  107. package/tsconfig.json +39 -0
  108. package/uno.config.ts +65 -0
  109. package/vite.config.ts +176 -0
  110. package/dist/favicon.ico +0 -0
  111. package/dist/umi.00ae29f6.js +0 -1
  112. package/dist/umi.bd64c248.css +0 -1
@@ -0,0 +1,442 @@
1
+ /* ==========================================================================
2
+ Component: Progress
3
+ ============================================================================ */
4
+ /* Progress bar animation */
5
+ @-webkit-keyframes progress-bar-stripes {
6
+ from {
7
+ background-position: 36px 0;
8
+ }
9
+
10
+ to {
11
+ background-position: 0 0;
12
+ }
13
+ }
14
+
15
+ @keyframes progress-bar-stripes {
16
+ from {
17
+ background-position: 36px 0;
18
+ }
19
+
20
+ to {
21
+ background-position: 0 0;
22
+ }
23
+ }
24
+
25
+ /* Progress container */
26
+ .am-progress {
27
+ // overflow: hidden;
28
+ // margin-bottom: 2rem;
29
+ height: 1rem;
30
+ background-color: #f5f5f5;
31
+ border-radius: 0;
32
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
33
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
34
+ }
35
+
36
+ /* Progress bar */
37
+ .am-progress-bar {
38
+ float: left;
39
+ width: 0;
40
+ height: 100%;
41
+ font-size: 1.2rem;
42
+ line-height: 2rem;
43
+ color: #fff;
44
+ text-align: center;
45
+ background-color: #0e90d2;
46
+ -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
47
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
48
+ -webkit-transition: width 0.6s ease;
49
+ transition: width 0.6s ease;
50
+ }
51
+
52
+ .am-progress-striped .am-progress-bar {
53
+ background-image: -webkit-gradient(
54
+ linear,
55
+ 0 100%,
56
+ 100% 0,
57
+ color-stop(0.25, rgba(255, 255, 255, 0.15)),
58
+ color-stop(0.25, transparent),
59
+ color-stop(0.5, transparent),
60
+ color-stop(0.5, rgba(255, 255, 255, 0.15)),
61
+ color-stop(0.75, rgba(255, 255, 255, 0.15)),
62
+ color-stop(0.75, transparent),
63
+ to(transparent)
64
+ );
65
+ background-image: -webkit-linear-gradient(
66
+ 45deg,
67
+ rgba(255, 255, 255, 0.15) 25%,
68
+ transparent 25%,
69
+ transparent 50%,
70
+ rgba(255, 255, 255, 0.15) 50%,
71
+ rgba(255, 255, 255, 0.15) 75%,
72
+ transparent 75%,
73
+ transparent
74
+ );
75
+ background-image: linear-gradient(
76
+ 45deg,
77
+ rgba(255, 255, 255, 0.15) 25%,
78
+ transparent 25%,
79
+ transparent 50%,
80
+ rgba(255, 255, 255, 0.15) 50%,
81
+ rgba(255, 255, 255, 0.15) 75%,
82
+ transparent 75%,
83
+ transparent
84
+ );
85
+ -webkit-background-size: 36px 36px;
86
+ background-size: 36px 36px;
87
+ }
88
+
89
+ .am-progress.am-active .am-progress-bar {
90
+ -webkit-animation: progress-bar-stripes 2s linear infinite;
91
+ animation: progress-bar-stripes 2s linear infinite;
92
+ }
93
+
94
+ .am-progress-bar[aria-valuenow='1'],
95
+ .am-progress-bar[aria-valuenow='2'] {
96
+ min-width: 30px;
97
+ }
98
+
99
+ .am-progress-bar[aria-valuenow='0'] {
100
+ color: #999999;
101
+ min-width: 30px;
102
+ background: none;
103
+ -webkit-box-shadow: none;
104
+ box-shadow: none;
105
+ }
106
+
107
+ .am-progress-bar-secondary {
108
+ background-color: #3bb4f2;
109
+ }
110
+
111
+ .am-progress-striped .am-progress-bar-secondary {
112
+ background-image: -webkit-gradient(
113
+ linear,
114
+ 0 100%,
115
+ 100% 0,
116
+ color-stop(0.25, rgba(255, 255, 255, 0.15)),
117
+ color-stop(0.25, transparent),
118
+ color-stop(0.5, transparent),
119
+ color-stop(0.5, rgba(255, 255, 255, 0.15)),
120
+ color-stop(0.75, rgba(255, 255, 255, 0.15)),
121
+ color-stop(0.75, transparent),
122
+ to(transparent)
123
+ );
124
+ background-image: -webkit-linear-gradient(
125
+ 45deg,
126
+ rgba(255, 255, 255, 0.15) 25%,
127
+ transparent 25%,
128
+ transparent 50%,
129
+ rgba(255, 255, 255, 0.15) 50%,
130
+ rgba(255, 255, 255, 0.15) 75%,
131
+ transparent 75%,
132
+ transparent
133
+ );
134
+ background-image: linear-gradient(
135
+ 45deg,
136
+ rgba(255, 255, 255, 0.15) 25%,
137
+ transparent 25%,
138
+ transparent 50%,
139
+ rgba(255, 255, 255, 0.15) 50%,
140
+ rgba(255, 255, 255, 0.15) 75%,
141
+ transparent 75%,
142
+ transparent
143
+ );
144
+ }
145
+
146
+ .am-progress-bar-success {
147
+ background-color: #5eb95e;
148
+ }
149
+
150
+ .am-progress-striped .am-progress-bar-success {
151
+ background-image: -webkit-gradient(
152
+ linear,
153
+ 0 100%,
154
+ 100% 0,
155
+ color-stop(0.25, rgba(255, 255, 255, 0.15)),
156
+ color-stop(0.25, transparent),
157
+ color-stop(0.5, transparent),
158
+ color-stop(0.5, rgba(255, 255, 255, 0.15)),
159
+ color-stop(0.75, rgba(255, 255, 255, 0.15)),
160
+ color-stop(0.75, transparent),
161
+ to(transparent)
162
+ );
163
+ background-image: -webkit-linear-gradient(
164
+ 45deg,
165
+ rgba(255, 255, 255, 0.15) 25%,
166
+ transparent 25%,
167
+ transparent 50%,
168
+ rgba(255, 255, 255, 0.15) 50%,
169
+ rgba(255, 255, 255, 0.15) 75%,
170
+ transparent 75%,
171
+ transparent
172
+ );
173
+ background-image: linear-gradient(
174
+ 45deg,
175
+ rgba(255, 255, 255, 0.15) 25%,
176
+ transparent 25%,
177
+ transparent 50%,
178
+ rgba(255, 255, 255, 0.15) 50%,
179
+ rgba(255, 255, 255, 0.15) 75%,
180
+ transparent 75%,
181
+ transparent
182
+ );
183
+ }
184
+
185
+ .am-progress-bar-warning {
186
+ background-color: #f37b1d;
187
+ }
188
+
189
+ .am-progress-striped .am-progress-bar-warning {
190
+ background-image: -webkit-gradient(
191
+ linear,
192
+ 0 100%,
193
+ 100% 0,
194
+ color-stop(0.25, rgba(255, 255, 255, 0.15)),
195
+ color-stop(0.25, transparent),
196
+ color-stop(0.5, transparent),
197
+ color-stop(0.5, rgba(255, 255, 255, 0.15)),
198
+ color-stop(0.75, rgba(255, 255, 255, 0.15)),
199
+ color-stop(0.75, transparent),
200
+ to(transparent)
201
+ );
202
+ background-image: -webkit-linear-gradient(
203
+ 45deg,
204
+ rgba(255, 255, 255, 0.15) 25%,
205
+ transparent 25%,
206
+ transparent 50%,
207
+ rgba(255, 255, 255, 0.15) 50%,
208
+ rgba(255, 255, 255, 0.15) 75%,
209
+ transparent 75%,
210
+ transparent
211
+ );
212
+ background-image: linear-gradient(
213
+ 45deg,
214
+ rgba(255, 255, 255, 0.15) 25%,
215
+ transparent 25%,
216
+ transparent 50%,
217
+ rgba(255, 255, 255, 0.15) 50%,
218
+ rgba(255, 255, 255, 0.15) 75%,
219
+ transparent 75%,
220
+ transparent
221
+ );
222
+ }
223
+
224
+ .am-progress-bar-danger {
225
+ background-color: #dd514c;
226
+ }
227
+
228
+ .am-progress-striped .am-progress-bar-danger {
229
+ background-image: -webkit-gradient(
230
+ linear,
231
+ 0 100%,
232
+ 100% 0,
233
+ color-stop(0.25, rgba(255, 255, 255, 0.15)),
234
+ color-stop(0.25, transparent),
235
+ color-stop(0.5, transparent),
236
+ color-stop(0.5, rgba(255, 255, 255, 0.15)),
237
+ color-stop(0.75, rgba(255, 255, 255, 0.15)),
238
+ color-stop(0.75, transparent),
239
+ to(transparent)
240
+ );
241
+ background-image: -webkit-linear-gradient(
242
+ 45deg,
243
+ rgba(255, 255, 255, 0.15) 25%,
244
+ transparent 25%,
245
+ transparent 50%,
246
+ rgba(255, 255, 255, 0.15) 50%,
247
+ rgba(255, 255, 255, 0.15) 75%,
248
+ transparent 75%,
249
+ transparent
250
+ );
251
+ background-image: linear-gradient(
252
+ 45deg,
253
+ rgba(255, 255, 255, 0.15) 25%,
254
+ transparent 25%,
255
+ transparent 50%,
256
+ rgba(255, 255, 255, 0.15) 50%,
257
+ rgba(255, 255, 255, 0.15) 75%,
258
+ transparent 75%,
259
+ transparent
260
+ );
261
+ }
262
+
263
+ .am-progress-xs {
264
+ height: 0.6rem;
265
+ }
266
+
267
+ .am-progress-sm {
268
+ height: 1.2rem;
269
+ }
270
+
271
+ .am-progress-cursor {
272
+ position: absolute;
273
+ left: 50%;
274
+ bottom: -4px;
275
+ cursor: pointer;
276
+ }
277
+
278
+ /* ==========================================================================
279
+ Component: Label
280
+ ============================================================================ */
281
+ .label {
282
+ box-sizing: inherit;
283
+ display: inline-block;
284
+ background-image: none;
285
+ text-transform: none;
286
+ font-weight: bold;
287
+ border: 0 solid transparent;
288
+ transition: background 0.1s ease;
289
+ margin-right: 5px;
290
+ padding: 0.4em !important;
291
+ line-height: 1em;
292
+ text-align: center;
293
+ border-radius: 500rem;
294
+ font-size: 0.78571429rem;
295
+ min-width: 0;
296
+ min-height: 0;
297
+ overflow: hidden;
298
+ width: 1px;
299
+ height: 1px;
300
+ vertical-align: baseline;
301
+ color: #ffffff;
302
+ }
303
+
304
+ /* ==========================================================================
305
+ State Color
306
+ ============================================================================ */
307
+ .PENDING {
308
+ background-color: #3bb4f2;
309
+ border-color: #3bb4f2;
310
+ }
311
+
312
+ .RUNNING {
313
+ background-color: rgb(94, 185, 94);
314
+ border-color: rgb(94, 185, 94);
315
+ }
316
+
317
+ .FROZEN {
318
+ background-color: #dd514c;
319
+ border-color: #dd514c;
320
+ }
321
+
322
+ .FINISHED {
323
+ background-color: #0e90d2;
324
+ border-color: #0e90d2;
325
+ }
326
+
327
+ .PAUSED {
328
+ background-color: #3bb4f2;
329
+ border-color: #3bb4f2;
330
+ }
331
+
332
+ /* ==========================================================================
333
+ Component: Tooltip
334
+ ============================================================================ */
335
+ .tooltip {
336
+ position: absolute;
337
+ z-index: 1070;
338
+ display: block;
339
+ font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
340
+ Helvetica Neue, Arial, sans-serif;
341
+ font-style: normal;
342
+ font-weight: 400;
343
+ letter-spacing: normal;
344
+ line-break: auto;
345
+ line-height: 1.5;
346
+ text-align: left;
347
+ text-align: start;
348
+ text-decoration: none;
349
+ text-shadow: none;
350
+ text-transform: none;
351
+ white-space: normal;
352
+ word-break: normal;
353
+ word-spacing: normal;
354
+ font-size: 0.875rem;
355
+ word-wrap: break-word;
356
+ opacity: 0;
357
+ }
358
+
359
+ .tooltip.in {
360
+ opacity: 0.9;
361
+ }
362
+
363
+ .tooltip.bs-tether-element-attached-bottom,
364
+ .tooltip.tooltip-top {
365
+ padding: 5px 0;
366
+ margin-top: -3px;
367
+ }
368
+
369
+ .tooltip.bs-tether-element-attached-bottom .tooltip-inner:before,
370
+ .tooltip.tooltip-top .tooltip-inner:before {
371
+ bottom: 0;
372
+ left: 50%;
373
+ margin-left: -5px;
374
+ content: '';
375
+ border-width: 5px 5px 0;
376
+ border-top-color: #000;
377
+ }
378
+
379
+ .tooltip.bs-tether-element-attached-left,
380
+ .tooltip.tooltip-right {
381
+ padding: 0 5px;
382
+ margin-left: 3px;
383
+ }
384
+
385
+ .tooltip.bs-tether-element-attached-left .tooltip-inner:before,
386
+ .tooltip.tooltip-right .tooltip-inner:before {
387
+ top: 50%;
388
+ left: 0;
389
+ margin-top: -5px;
390
+ content: '';
391
+ border-width: 5px 5px 5px 0;
392
+ border-right-color: #000;
393
+ }
394
+
395
+ .tooltip.bs-tether-element-attached-top,
396
+ .tooltip.tooltip-bottom {
397
+ padding: 5px 0;
398
+ margin-top: 3px;
399
+ }
400
+
401
+ .tooltip.bs-tether-element-attached-top .tooltip-inner:before,
402
+ .tooltip.tooltip-bottom .tooltip-inner:before {
403
+ top: 0;
404
+ left: 50%;
405
+ margin-left: -5px;
406
+ content: '';
407
+ border-width: 0 5px 5px;
408
+ border-bottom-color: #000;
409
+ }
410
+
411
+ .tooltip.bs-tether-element-attached-right,
412
+ .tooltip.tooltip-left {
413
+ padding: 0 5px;
414
+ margin-left: -3px;
415
+ }
416
+
417
+ .tooltip.bs-tether-element-attached-right .tooltip-inner:before,
418
+ .tooltip.tooltip-left .tooltip-inner:before {
419
+ top: 50%;
420
+ right: 0;
421
+ margin-top: -5px;
422
+ content: '';
423
+ border-width: 5px 0 5px 5px;
424
+ border-left-color: #000;
425
+ }
426
+
427
+ .tooltip-inner {
428
+ max-width: 200px;
429
+ padding: 3px 8px;
430
+ color: #fff;
431
+ text-align: center;
432
+ background-color: #000;
433
+ border-radius: 0.25rem;
434
+ }
435
+
436
+ .tooltip-inner:before {
437
+ position: absolute;
438
+ width: 0;
439
+ height: 0;
440
+ border-color: transparent;
441
+ border-style: solid;
442
+ }
@@ -0,0 +1,229 @@
1
+ <script setup lang="ts">
2
+ import { ContestState } from "@xcpcio/types";
3
+ import { useRouteQuery } from "@vueuse/router";
4
+ import type { Rank, RankOptions } from "@xcpcio/core";
5
+ import { createDayJS, getTimeDiff } from "@xcpcio/core";
6
+
7
+ const props = defineProps<{
8
+ width: number,
9
+ state: ContestState,
10
+ needScroll?: boolean,
11
+ rank?: Rank,
12
+ rankOptions?: RankOptions,
13
+ elapsedTime?: string,
14
+ }>();
15
+ const emit = defineEmits(["update:rank-options"]);
16
+
17
+ const rankOptions = computed({
18
+ get() {
19
+ return props!.rankOptions;
20
+ },
21
+ set(value) {
22
+ emit("update:rank-options", value);
23
+ },
24
+ });
25
+
26
+ const barClass = computed(() => {
27
+ switch (props.state) {
28
+ case ContestState.PENDING:
29
+ return "am-progress-bar-secondary";
30
+ case ContestState.RUNNING:
31
+ return "am-progress-bar-success";
32
+ case ContestState.FROZEN:
33
+ return "am-progress-bar-danger";
34
+ case ContestState.FINISHED:
35
+ return "am-progress-bar-primary";
36
+ }
37
+ });
38
+
39
+ const pauseUpdate = ref(false);
40
+ const isDragging = ref(false);
41
+ const dragWidth = ref(0);
42
+ const barWidth = ref(props.width);
43
+ const barWidthPX = ref(0);
44
+ const progressRatio = useRouteQuery("progress-ratio", -1, { transform: Number });
45
+
46
+ const scroll = ref<HTMLElement>(null as unknown as HTMLElement);
47
+ const mask = ref<HTMLElement>(null as unknown as HTMLElement);
48
+ const bar = ref<HTMLElement>(null as unknown as HTMLElement);
49
+ const tooltip = ref<HTMLElement>(null as unknown as HTMLElement);
50
+ const tooltipInner = ref<HTMLElement>(null as unknown as HTMLElement);
51
+
52
+ function startDrag(event: MouseEvent) {
53
+ isDragging.value = true;
54
+ const leftVal = event.clientX - bar.value.offsetLeft;
55
+
56
+ const updateProgress = (event: MouseEvent) => {
57
+ if (!isDragging.value) {
58
+ return;
59
+ }
60
+
61
+ pauseUpdate.value = true;
62
+
63
+ let barLeft = event.clientX - leftVal;
64
+ barLeft = Math.max(barLeft, 0);
65
+ barLeft = Math.min(barLeft, scroll.value.offsetWidth - bar.value.offsetWidth);
66
+
67
+ const maskWidth
68
+ = scroll.value.offsetWidth * Number.parseInt(mask.value.style?.width) * 0.01;
69
+
70
+ // When dragging beyond the current time bar,
71
+ // then automatic updating resumes
72
+ if (barLeft >= maskWidth) {
73
+ barLeft = maskWidth;
74
+ pauseUpdate.value = false;
75
+ }
76
+
77
+ let width = 0;
78
+ if (barLeft > 0) {
79
+ width = Math.round((barLeft + bar.value.offsetWidth) / (scroll.value.offsetWidth) * 10000);
80
+ }
81
+
82
+ if (width > 10000) {
83
+ width = 10000;
84
+ }
85
+
86
+ if (width === 10000) {
87
+ pauseUpdate.value = false;
88
+ }
89
+
90
+ window.getSelection()?.removeAllRanges();
91
+
92
+ dragWidth.value = width;
93
+
94
+ barWidthPX.value = barLeft;
95
+ barWidth.value = width * 0.01;
96
+ };
97
+
98
+ const stopDrag = () => {
99
+ document.removeEventListener("mouseup", stopDrag);
100
+ document.removeEventListener("mousemove", updateProgress);
101
+
102
+ isDragging.value = false;
103
+
104
+ if (pauseUpdate.value === true) {
105
+ progressRatio.value = dragWidth.value;
106
+ rankOptions.value?.setWidth(dragWidth.value, props.rank!.contest);
107
+ } else {
108
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
109
+ // @ts-expect-error
110
+ progressRatio.value = undefined;
111
+ rankOptions.value?.disableFilterSubmissionByTimestamp();
112
+ }
113
+ };
114
+
115
+ document.addEventListener("mousemove", updateProgress);
116
+ document.addEventListener("mouseup", stopDrag);
117
+ }
118
+
119
+ function getTimeScroll() {
120
+ const startTime = props.rank!.contest.startTime;
121
+ const endTime = props.rank!.contest.endTime;
122
+
123
+ const gap = endTime.unix() - startTime.unix();
124
+ const target = Math.floor(gap * barWidth.value * 0.01);
125
+
126
+ const now = createDayJS();
127
+ const limit = Math.max(0, Math.min(now.unix(), endTime.unix()) - startTime.unix());
128
+
129
+ return getTimeDiff(Math.min(target, limit));
130
+ }
131
+
132
+ function elapsedTime() {
133
+ if (pauseUpdate.value === true) {
134
+ return getTimeScroll();
135
+ }
136
+
137
+ return props.elapsedTime;
138
+ }
139
+
140
+ function barWidthInStyle() {
141
+ if (pauseUpdate.value === true) {
142
+ return `${Math.max(0, barWidthPX.value)}px`;
143
+ }
144
+
145
+ return `max(calc(0%), min(calc(${props.width}%), calc(100% - 10px)))`;
146
+ }
147
+
148
+ onMounted(() => {
149
+ scroll.value.onmouseenter = () => {
150
+ tooltip.value.classList.add("in");
151
+ };
152
+
153
+ scroll.value.onmouseleave = () => {
154
+ tooltip.value.classList.remove("in");
155
+ };
156
+
157
+ if (progressRatio.value !== -1) {
158
+ pauseUpdate.value = true;
159
+ dragWidth.value = Math.max(0, Math.min(10000, progressRatio.value));
160
+
161
+ barWidth.value = dragWidth.value * 0.01;
162
+ barWidthPX.value = barWidth.value * 0.01 * scroll.value.offsetWidth - bar.value.offsetWidth;
163
+
164
+ rankOptions.value?.setWidth(progressRatio.value, props.rank!.contest);
165
+ } else {
166
+ rankOptions.value?.disableFilterSubmissionByTimestamp();
167
+ }
168
+ });
169
+
170
+ onUnmounted(() => {});
171
+ </script>
172
+
173
+ <template>
174
+ <div
175
+ ref="scroll"
176
+ class="am-progress am-progress-striped am-active"
177
+ w-full
178
+ :style="{
179
+ position: 'relative',
180
+ }"
181
+ >
182
+ <div
183
+ ref="mask"
184
+ class="am-progress-bar"
185
+ :class="[barClass]"
186
+ :style="{
187
+ width: `${props.width}%`,
188
+ }"
189
+ >
190
+ <template v-if="props.needScroll">
191
+ <div
192
+ ref="tooltip"
193
+ class="tooltip tooltip-top"
194
+ :style="{
195
+ marginLeft: '-32px',
196
+ bottom: '22px',
197
+ left: barWidthInStyle(),
198
+ }"
199
+ >
200
+ <div
201
+ ref="tooltipInner"
202
+ class="tooltip-inner"
203
+ >
204
+ {{ elapsedTime() }}
205
+ </div>
206
+ </div>
207
+
208
+ <div
209
+ ref="bar"
210
+ class="am-progress-bar am-progress-cursor am-progress-scroll-size z-999"
211
+ :class="[barClass]"
212
+ :style="{
213
+ left: barWidthInStyle(),
214
+ }"
215
+ @mousedown="startDrag"
216
+ />
217
+ </template>
218
+ </div>
219
+ </div>
220
+ </template>
221
+
222
+ <style scoped lang="less">
223
+ @import "./Progress.less";
224
+
225
+ .am-progress-scroll-size {
226
+ width: 10px;
227
+ height: 25px;
228
+ }
229
+ </style>