diff --git a/.dockerignore b/.dockerignore
index fb33dda..5b8e2cb 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -2,8 +2,6 @@
.gitignore
node_modules
**/node_modules
-frontend/dist
-bin
backend/data
data
*.db
diff --git a/Dockerfile b/Dockerfile
index e7c8a5b..5db38a9 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,26 +1,18 @@
# syntax=docker/dockerfile:1.7
-FROM --platform=$BUILDPLATFORM node:20-alpine AS frontend-builder
-WORKDIR /app/frontend
-COPY frontend/package.json frontend/pnpm-lock.yaml ./
-RUN corepack enable && pnpm install --frozen-lockfile
-COPY frontend/ ./
-RUN pnpm build
-
-FROM --platform=$BUILDPLATFORM golang:1.24 AS backend-builder
-WORKDIR /app/backend
-COPY backend/go.mod backend/go.sum ./
-RUN go mod download
-COPY backend/ ./
-COPY --from=frontend-builder /app/frontend/dist ./web
-ARG TARGETARCH
-RUN CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH:-amd64} go build -trimpath -ldflags="-s -w" -o /out/shooting-event .
+# FROM --platform=$BUILDPLATFORM golang:1.24 AS backend-builder
+# WORKDIR /app/backend
+# COPY backend/go.mod backend/go.sum ./
+# RUN go mod download
+# COPY backend/ ./
+# ARG TARGETARCH
+# RUN CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH:-amd64} go build -trimpath -ldflags="-s -w" -o /out/shooting-event .
FROM --platform=$TARGETPLATFORM alpine:3.21
RUN addgroup -S app && adduser -S app -G app && apk add --no-cache ca-certificates
WORKDIR /app
-COPY --from=backend-builder /out/shooting-event /app/shooting-event
-COPY --from=backend-builder /app/backend/web /app/web
+COPY bin/shooting-event-amd64 /app/shooting-event
+COPY frontend/dist /app/web
RUN mkdir -p /app/data && chown -R app:app /app
USER app
ENV PORT=8080
diff --git a/Makefile b/Makefile
index ca61f9a..d195a20 100644
--- a/Makefile
+++ b/Makefile
@@ -36,6 +36,9 @@ build-backend:
mkdir -p bin
cd backend && $(GO) build -o ../bin/shooting-event .
+build-backend-amd64:
+ mkdir -p bin
+ cd backend && GOARCH=amd64 GOOS=linux $(GO) build -o ../bin/shooting-event-amd64 .
build: build-frontend
rm -rf backend/web
mkdir -p backend/web
diff --git a/frontend/src/components/LiveModePanel.vue b/frontend/src/components/LiveModePanel.vue
index 580d79a..0380102 100644
--- a/frontend/src/components/LiveModePanel.vue
+++ b/frontend/src/components/LiveModePanel.vue
@@ -132,9 +132,13 @@
- | {{ row.rank }} |
+
+
+ {{ row.rank }}
+ {{ prelimOverallHintLabel(row) }}
+
+ |
![]()
@@ -270,7 +274,12 @@
- | {{ row.rank }} |
+
+
+ {{ row.rank }}
+ {{ finalOverallHintLabel(row) }}
+
+ |
![]()
@@ -387,6 +396,8 @@ const props = defineProps({
})
const finalistIds = computed(() => new Set((props.finalists || []).map((row) => row.playerId)))
+const prelimTieIds = computed(() => new Set((props.prelimTieRows || []).map((row) => row.playerId)))
+const finalTieIds = computed(() => new Set((props.finalTieRows || []).map((row) => row.playerId)))
const activeView = computed(() => props.liveSettings.activeView || 'group_live')
const listPageIndex = ref(0)
const tieGroupIndex = ref(0)
@@ -488,6 +499,25 @@ function isFinalist(playerId) {
return finalistIds.value.has(playerId)
}
+function isPrelimTiePlayer(playerId) {
+ return prelimTieIds.value.has(playerId)
+}
+
+function isFinalTiePlayer(playerId) {
+ return finalTieIds.value.has(playerId)
+}
+
+function prelimOverallHintLabel(row) {
+ if (isPrelimTiePlayer(row.playerId)) return props.t('labels.tieBreak')
+ if (isFinalist(row.playerId)) return props.t('labels.finalist')
+ return ''
+}
+
+function finalOverallHintLabel(row) {
+ if (isFinalTiePlayer(row.playerId)) return props.t('labels.tieBreak')
+ return ''
+}
+
watch(
() =>
`${activeView.value}|${rotationIntervalSec.value}|${rotationPlayerCount.value}|${props.prelimTieRows.length}|${props.preliminaryRows.length}|${props.finalOverallRows.length}|${props.finalTieRows.length}`,
diff --git a/frontend/src/constants/i18n.js b/frontend/src/constants/i18n.js
index a10fa2d..0fbccd3 100644
--- a/frontend/src/constants/i18n.js
+++ b/frontend/src/constants/i18n.js
@@ -24,6 +24,7 @@ export const I18N = {
allPlayers: 'جميع اللاعبين',
top12: 'أفضل 12 متأهل',
finalist: 'متأهل',
+ tieBreak: 'كسر تعادل',
notFinalist: 'غير متأهل',
noPlayers: 'لا يوجد لاعبين بعد',
noFinalists: 'لا يوجد متأهلون بعد',
@@ -224,6 +225,7 @@ export const I18N = {
allPlayers: 'All players',
top12: 'Top 12 finalists',
finalist: 'Finalist',
+ tieBreak: 'Tie-break',
notFinalist: 'Not finalist',
noPlayers: 'No players yet',
noFinalists: 'No finalists yet',
diff --git a/frontend/src/style.css b/frontend/src/style.css
index 3b7a23c..dfdd9a2 100644
--- a/frontend/src/style.css
+++ b/frontend/src/style.css
@@ -1514,6 +1514,7 @@ select.name-input {
.live-footer-slot {
display: flex;
align-items: center;
+ min-height: 56px;
}
.live-footer-slot.left {
@@ -1529,18 +1530,13 @@ select.name-input {
}
.live-footer-logo {
- max-width: min(35vw, 200px);
padding: 8px 6px;
width: auto;
- height: auto;
+ height: 60px;
object-fit: contain;
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.28));
}
-.live-footer-slot.right .live-footer-logo {
- max-width: min(45vw, 280px);
-}
-
.live-tie-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
@@ -1897,8 +1893,20 @@ select.name-input {
background: #0d1931;
}
-.live-screen-card .qualified-row {
- background: rgba(0, 140, 168, 0.16);
+.live-rank-cell {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 6px;
+}
+
+.live-rank-hint {
+ color: rgba(255, 255, 255, 0.74);
+ font-size: 11px;
+ font-weight: 700;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ white-space: nowrap;
}
.live-podium {
@@ -2901,11 +2909,7 @@ select.name-input {
}
.live-footer-logo {
- max-height: 36px;
- }
-
- .live-footer-slot.right .live-footer-logo {
- max-width: min(40vw, 150px);
+ max-width: min(34vw, 150px);
}
.live-tie-grid {
| |