Public scoreboard stopwatch feature
All checks were successful
CI / scan_ruby (push) Successful in 21s
CI / scan_js (push) Successful in 14s
CI / lint (push) Successful in 14s
CI / test (push) Successful in 36s

#10
This commit is contained in:
sto
2025-12-09 10:10:54 +01:00
parent ee250b96ad
commit cce090587a
19 changed files with 167 additions and 8 deletions

View File

@@ -7,6 +7,9 @@
li.nav-item
a.nav-link class=active_page(contest_puzzles_path(@contest)) href=contest_puzzles_path(@contest)
= t("puzzles.plural").capitalize
li.nav-item
a.nav-link class=active_page("/contests/#{@contest.id}/stopwatch") href="/contests/#{@contest.id}/stopwatch"
= t("contests.nav.stopwatch").capitalize
li.nav-item
a.nav-link class=active_page(contest_messages_path(@contest)) href=contest_messages_path(@contest)
= t("messages.plural").capitalize

View File

@@ -8,6 +8,9 @@
thead
tr
th
- if @contest.show_stopwatch
.stopwatch id="display-time" style="font-size: 60px; font-weight: 400;"
= render "stopwatch_js"
th
th
th

View File

@@ -1,5 +1,5 @@
.row
.mt-3.col-6.d-flex.flex-column style="height: calc(100vh - 250px)"
.mt-3.col-6.d-flex.flex-column style="height: calc(100vh - 310px)"
.d-flex.flex-column style="overflow-y: auto"
table.table.table-striped.table-hover
thead

View File

@@ -3,14 +3,14 @@ css:
.row
- if @puzzles.size > 0
.d-flex.flex-column.justify-content-center.mb-5
.d-flex.flex-column.justify-content-center.mb-2
= image_tag(@puzzles[0].image, style: "max-height: 200px; object-fit: contain") if @puzzles[0].image.attached?
.mt-2.fs-6 style="text-align: center"
=> "#{@puzzles[0].name} -"
= "#{@puzzles[0].brand} #{@puzzles[0].pieces}p"
.row
.mt-3.d-flex.flex-column style="height: calc(100vh - 250px)"
.mt-3.d-flex.flex-column
.d-flex.flex-column style="overflow-y: auto"
table.table.table-striped.table-hover
thead

View File

@@ -0,0 +1,22 @@
javascript:
startTime = #{@contest.start_time.present? ? @contest.start_time.to_i : "null"};
pauseTime = #{@contest.pause_time.present? ? @contest.pause_time.to_i : "null"};
function updateTime() {
const displayTimeEl = document.getElementById('display-time');
if (displayTimeEl) {
if (startTime) {
let s = Math.floor((Date.now() - 1000 * startTime) / 1000);
if (pauseTime) s = Math.floor(pauseTime - startTime);
let ss = s % 60;
let mm = Math.floor(s / 60) % 60;
let hh = Math.floor(s / 3600);
displayTimeEl.innerHTML = `${hh < 10 ? `0${hh}` : hh}:${mm < 10 ? `0${mm}` : mm}:${ss < 10 ? `0${ss}` : ss}`;
setTimeout(updateTime, 1000);
} else {
displayTimeEl.innerHTML = '00:00:00';
}
} else {
setTimeout(updateTime, 20);
}
}
setTimeout(updateTime, 1);

View File

@@ -3,12 +3,16 @@ css:
.mobile-single { display: block !important; }
.desktop-single { display: none; }
#scoreboard-switches { display: none; }
.stopwatch { font-size: 50px !important; }
}
- if @contest.puzzles.size < 2
= render "selectors"
turbo-frame id="scoreboard"
- if @contest.show_stopwatch
.stopwatch id="display-time" style="font-size: 60px; font-weight: 400; margin-bottom: 0; text-align: center;"
= render "stopwatch_js"
a.btn.btn-primary href="" id="refresh-button" style="display: none;"
.mobile-single style="display: none;"
= render "scoreboard_mobile_single"

View File

@@ -6,6 +6,11 @@
.form-check.form-switch
= form.check_box :public, class: "form-check-input"
= form.label :public
.row.mt-2
.col
.form-check.form-switch
= form.check_box :show_stopwatch, class: "form-check-input"
= form.label :show_stopwatch
.row.mt-3
.col
.form-floating

View File

@@ -0,0 +1,16 @@
.row
.col
.alert.alert-primary
= t("contests.stopwatch.info")
h1.mt-3 id="display-time" style="font-size: 80px;"
= render "stopwatch_js"
.row.mt-3
.col.d-flex
- if !@contest.start_time.present?
= button_to t("helpers.buttons.stopwatch_start"), "/contests/#{@contest.id}/stopwatch_start", method: :post, class: "btn btn-primary"
- if @contest.pause_time.present?
= button_to t("helpers.buttons.stopwatch_continue"), "/contests/#{@contest.id}/stopwatch_continue", method: :post, class: "btn btn-primary"
- if @contest.start_time.present? && !@contest.pause_time.present?
= button_to t("helpers.buttons.stopwatch_pause"), "/contests/#{@contest.id}/stopwatch_pause", method: :post, class: "btn btn-primary"
- if @contest.start_time.present?
= button_to t("helpers.buttons.stopwatch_reset"), "/contests/#{@contest.id}/stopwatch_reset", method: :post, class: "ms-3 btn btn-warning"