diff --git a/Makefile b/Makefile index d195a20..9f77bd1 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ SHELL := /bin/bash PNPM ?= pnpm GO ?= go CONTAINER_REG ?= repo.ssp-itinfra.com/admin -IMAGE_NAME ?= shooting-event +IMAGE_NAME ?= shooting-event-2 PHOENIX_IMAGE_NAME ?= $(IMAGE_NAME)-phoenix ARCH ?= amd64 BUILD_DATE ?= $(shell date -u +"%Y-%m-%dT%H:%M:%SZ") diff --git a/frontend/src/App.vue b/frontend/src/App.vue index fe885b4..aa6ac75 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -85,7 +85,6 @@ :podium-ordered="podiumOrdered" :player-image="playerImage" :display-name="displayName" - :secondary-name="secondaryName" :score-for="scoreFor" :prelim-total="preliminaryTotalScore" :final-total="finalTotalScore" diff --git a/frontend/src/components/LiveModePanel.vue b/frontend/src/components/LiveModePanel.vue index 15030f3..a020c50 100644 --- a/frontend/src/components/LiveModePanel.vue +++ b/frontend/src/components/LiveModePanel.vue @@ -2,11 +2,6 @@
-
-

{{ t('sections.liveModeTitle') }}

-

{{ t('sections.liveModeSubtitle') }}

-
- @@ -47,7 +42,6 @@

{{ displayName(entry.player) }}

-

{{ secondaryName(entry.player) }}

@@ -93,7 +87,6 @@

{{ displayName(entry.row) }}

-

{{ secondaryName(entry.row) }}

@@ -144,7 +137,6 @@

{{ displayName(row) }}

-

{{ secondaryName(row) }}

@@ -170,8 +162,8 @@
- {{ t('tabs.final') }} - {{ currentFinalGroupLabel }} + {{ currentFinalSeedLabel }} + {{ currentFinalGroupNumber }}
@@ -193,7 +185,6 @@

{{ displayName(entry.row) }}

-

{{ secondaryName(entry.row) }}

@@ -238,7 +229,6 @@

{{ displayName(entry.row) }}

-

{{ secondaryName(entry.row) }}

@@ -284,7 +274,6 @@

{{ displayName(row) }}

-

{{ secondaryName(row) }}

@@ -384,7 +373,6 @@ const props = defineProps({ podiumOrdered: { type: Array, required: true }, playerImage: { type: Function, required: true }, displayName: { type: Function, required: true }, - secondaryName: { type: Function, required: true }, scoreFor: { type: Function, required: true }, prelimTotal: { type: Function, required: true }, finalTotal: { type: Function, required: true }, @@ -479,10 +467,11 @@ const activeViewLabel = computed(() => { return map[activeView.value] || map.group_live }) -const currentFinalGroupLabel = computed(() => { - if (props.liveFinalGroup === 2) return props.t('labels.finalGroup2') - return props.t('labels.finalGroup1') +const currentFinalSeedLabel = computed(() => { + if (props.liveFinalGroup === 2) return props.t('labels.finalGroupSeeds2') + return props.t('labels.finalGroupSeeds1') }) +const currentFinalGroupNumber = computed(() => (props.liveFinalGroup === 2 ? '2' : '1')) const groupClassKey = computed(() => { const code = String(props.liveGroupCode || '').trim().toUpperCase() if (code.startsWith('A')) return 'a' diff --git a/frontend/src/constants/i18n.js b/frontend/src/constants/i18n.js index 664327a..751040c 100644 --- a/frontend/src/constants/i18n.js +++ b/frontend/src/constants/i18n.js @@ -30,6 +30,8 @@ export const I18N = { noFinalists: 'لا يوجد متأهلون بعد', finalGroup1: 'المجموعة النهائية 1 (المراكز 1-6)', finalGroup2: 'المجموعة النهائية 2 (المراكز 7-12)', + finalGroupSeeds1: 'المجموعة النهائية (المراكز 1-6)', + finalGroupSeeds2: 'المجموعة النهائية (المراكز 7-12)', tieSlots: 'عدد المقاعد المتاحة من كسر التعادل', waiting: 'بانتظار النتيجة', viewProofInView: 'إظهار صور إثبات النتيجة في وضع العرض', @@ -232,6 +234,8 @@ export const I18N = { noFinalists: 'No finalists yet', finalGroup1: 'Final Group 1 (Seeds 1-6)', finalGroup2: 'Final Group 2 (Seeds 7-12)', + finalGroupSeeds1: 'Final Group Seeds 1-6', + finalGroupSeeds2: 'Final Group Seeds 7-12', tieSlots: 'Tie-break slots', waiting: 'Waiting', viewProofInView: 'Allow proof images in view mode', diff --git a/frontend/src/style.css b/frontend/src/style.css index ea70549..8d8903a 100644 --- a/frontend/src/style.css +++ b/frontend/src/style.css @@ -63,8 +63,107 @@ body { color: #ffffff; } +.app-shell.mode-live .masthead-main { + align-items: center; + gap: 12px; + padding: 10px clamp(12px, 1.25vw, 24px) 12px; +} + +.app-shell.mode-live .masthead-brand { + gap: 4px; +} + +.app-shell.mode-live .masthead-logo { + width: clamp(220px, 20.5vw, 390px); +} + +.app-shell.mode-live .masthead-subtitle { + margin: 0; + font-size: clamp(10px, 0.72vw, 13px); + line-height: 1.2; + opacity: 0.84; +} + +.app-shell.mode-live .masthead-controls { + min-width: 0; + gap: 6px; +} + +.app-shell.mode-live .control-toggle-row { + gap: 6px; +} + +.app-shell.mode-live .control-toggle-btn { + border-color: rgba(0, 140, 168, 0.42); + background: rgba(255, 255, 255, 0.08); + color: #e9f3ff; + box-shadow: none; + border-radius: 10px; + padding: 5px 9px; + font-size: clamp(11px, 0.78vw, 14px); +} + +.app-shell.mode-live .control-toggle-btn:hover { + background: rgba(255, 255, 255, 0.14); +} + +.app-shell.mode-live .control-toggle-meta { + color: rgba(233, 243, 255, 0.78); + font-size: clamp(10px, 0.68vw, 12px); +} + +.app-shell.mode-live .control-icon-btn { + width: 34px; + height: 34px; + border-radius: 10px; + border-color: rgba(0, 140, 168, 0.42); + background: rgba(255, 255, 255, 0.08); + color: #e9f3ff; + box-shadow: none; +} + +.app-shell.mode-live .control-icon-btn:hover { + background: rgba(255, 255, 255, 0.14); +} + +.app-shell.mode-live .control-icon-btn svg { + width: 16px; + height: 16px; +} + +.app-shell.mode-live .controls-popover { + min-width: 240px; + padding: 8px; + border-color: rgba(0, 140, 168, 0.35); +} + +.app-shell.mode-live .control-label { + font-size: 10px; +} + +.app-shell.mode-live .language-switcher { + border-radius: 10px; +} + +.app-shell.mode-live .lang-btn { + padding: 6px 10px; + font-size: clamp(12px, 0.82vw, 14px); +} + +.app-shell.mode-live .status-row { + gap: 8px; +} + +.app-shell.mode-live .live-badge { + font-size: clamp(10px, 0.72vw, 12px); +} + +.app-shell.mode-live .server-time { + font-size: clamp(10px, 0.72vw, 12px); +} + .app-shell.mode-live .page-content { - padding-top: 18px; + padding: 10px clamp(10px, 1.1vw, 24px) 12px; } .hidden-file-input { @@ -1335,7 +1434,7 @@ select.name-input { .live-mode-shell { position: relative; - min-height: 72vh; + min-height: min(84vh, calc(100vh - 122px)); border-radius: 18px; overflow: hidden; display: grid; @@ -1346,21 +1445,22 @@ select.name-input { } .live-mode-overlay { - min-height: 72vh; - padding: 16px 16px 12px; + min-height: min(84vh, calc(100vh - 122px)); + padding: 14px 14px 10px; background: var(--live-navy); } .live-mode-header h2 { margin: 0; color: var(--live-white); - font-size: clamp(22px, 3vw, 34px); + font-size: clamp(24px, 2.2vw, 44px); letter-spacing: 0.2px; } .live-mode-header p { - margin: 6px 0 12px; + margin: 4px 0 10px; color: rgba(255, 255, 255, 0.78); + font-size: clamp(13px, 1vw, 18px); font-weight: 500; } @@ -1379,7 +1479,7 @@ select.name-input { border-radius: 14px; background: #0d1931; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2); - padding: 10px; + padding: 12px; animation: fade-up 0.32s ease both; } @@ -1389,14 +1489,14 @@ select.name-input { .live-swap-block { display: grid; - gap: 10px; + gap: 8px; } .live-focus-banner { border: 1px solid rgba(0, 140, 168, 0.45); border-radius: 14px; background: #0d1931; - padding: 10px 14px; + padding: 8px 12px; display: grid; gap: 2px; text-align: center; @@ -1404,7 +1504,7 @@ select.name-input { } .live-focus-label { - font-size: 11px; + font-size: clamp(12px, 0.85vw, 16px); font-weight: 800; letter-spacing: 0.9px; color: rgba(255, 255, 255, 0.75); @@ -1413,13 +1513,18 @@ select.name-input { .live-focus-title { font-family: "Bebas Neue", "Cairo", sans-serif; - font-size: clamp(34px, 6vw, 58px); + font-size: clamp(44px, 5.2vw, 92px); line-height: 0.95; letter-spacing: 1.2px; color: #ffffff; text-shadow: 0 3px 12px rgba(0, 0, 0, 0.4); } +.live-focus-banner.focus-final .live-focus-title { + font-size: clamp(30px, 3.4vw, 56px); + letter-spacing: 0.8px; +} + .live-focus-banner.focus-a .live-focus-title, .live-focus-banner.focus-b .live-focus-title, .live-focus-banner.focus-c .live-focus-title, @@ -1434,7 +1539,7 @@ select.name-input { align-items: center; justify-content: space-between; gap: 8px; - margin-bottom: 8px; + margin-bottom: 7px; } .live-head-selection { @@ -1448,7 +1553,7 @@ select.name-input { .live-screen-head h3 { margin: 0; color: var(--live-white); - font-size: 17px; + font-size: clamp(24px, 1.75vw, 34px); } .live-chip-row { @@ -1459,12 +1564,12 @@ select.name-input { } .live-chip { - padding: 4px 8px; + padding: 5px 10px; border-radius: 999px; border: 1px solid rgba(0, 140, 168, 0.45); background: #0d1931; color: rgba(255, 255, 255, 0.86); - font-size: 11px; + font-size: clamp(11px, 0.8vw, 15px); font-weight: 700; letter-spacing: 0.4px; } @@ -1494,7 +1599,7 @@ select.name-input { .live-mode-footer { margin-top: 0; - padding: 10px 12px; + padding: 8px 10px; border-top: 1px solid rgba(0, 140, 168, 0.45); background: #0d1931; display: grid; @@ -1514,7 +1619,7 @@ select.name-input { .live-footer-slot { display: flex; align-items: center; - min-height: 56px; + min-height: 48px; } .live-footer-slot.left { @@ -1530,15 +1635,15 @@ select.name-input { } .live-footer-logo { - padding: 8px 6px; + padding: 6px 6px; width: auto; - height: 60px; + height: clamp(52px, 3.1vw, 72px); object-fit: contain; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.28)); } .live-footer-logo-datwyler { - height: 65px; + height: clamp(56px, 3.45vw, 80px); } .live-tie-grid { display: grid; @@ -1870,6 +1975,11 @@ select.name-input { .live-screen-card .score-table thead th { background: #008ca8; color: #ffffff; + font-size: clamp(19px, 1.32vw, 27px); + padding: clamp(8px, 0.8vh, 11px) 9px; + font-family: Cairo, sans-serif; + font-weight: 800; + line-height: 1.2; } .live-screen-card .score-table { @@ -1880,10 +1990,24 @@ select.name-input { color: #ffffff; border-top-color: rgba(0, 140, 168, 0.24); background: #0d1931; + font-size: clamp(19px, 1.32vw, 27px); + padding: clamp(8px, 0.8vh, 11px) 9px; + font-family: Cairo, sans-serif; + font-weight: 800; + line-height: 1.2; +} + +.live-screen-card .mono, +.live-screen-card .rank { + font-family: inherit; + font-size: inherit; } .live-screen-card .name-main { color: #ffffff; + font-size: clamp(19px, 1.32vw, 27px); + line-height: 1.14; + font-weight: 800; } .live-screen-card .name-sub, @@ -1896,6 +2020,16 @@ select.name-input { background: #0d1931; } +.app-shell.mode-live .live-screen-card .competitor-cell { + gap: clamp(10px, 0.85vw, 16px); +} + +.app-shell.mode-live .live-screen-card .competitor-cell.compact .competitor-image { + width: clamp(56px, 3.4vw, 82px); + height: clamp(56px, 3.4vw, 82px); + border-width: 3px; +} + .live-rank-cell { display: inline-flex; align-items: center; @@ -1905,7 +2039,7 @@ select.name-input { .live-rank-hint { color: rgba(255, 255, 255, 0.74); - font-size: 11px; + font-size: clamp(11px, 0.78vw, 15px); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; @@ -1913,7 +2047,7 @@ select.name-input { } .live-podium { - margin-top: 72px; + margin-top: 52px; min-height: 500px; gap: 22px; padding: 0 18px; @@ -1956,8 +2090,8 @@ select.name-input { } .podium-live-card .podium-img { - width: 150px; - height: 150px; + width: 164px; + height: 164px; border-width: 6px; border-color: rgba(0, 140, 168, 0.82); background: #0d1931; @@ -1976,14 +2110,14 @@ select.name-input { } .podium-live-card .podium-col.pos-1 .podium-img { - width: 210px; - height: 210px; + width: 228px; + height: 228px; border-width: 7px; } .podium-live-card .podium-name { color: #f2f8ff; - font-size: clamp(19px, 1.8vw, 24px); + font-size: clamp(22px, 1.7vw, 30px); width: calc(100% - 20px); max-width: calc(100% - 20px); text-align: center; @@ -2002,7 +2136,7 @@ select.name-input { } .podium-live-card .podium-col.pos-1 .podium-name { - font-size: clamp(22px, 2.2vw, 30px); + font-size: clamp(25px, 2.05vw, 36px); -webkit-line-clamp: 3; line-clamp: 3; min-height: 3.6em; @@ -2023,7 +2157,7 @@ select.name-input { color: #ffffff; border-color: rgba(0, 140, 168, 0.34); margin-bottom: 0; - font-size: 16px; + font-size: clamp(17px, 1.2vw, 22px); padding: 10px 16px; } @@ -2040,19 +2174,189 @@ select.name-input { } .podium-live-card .podium-col.pos-1 .podium-score { - font-size: 18px; + font-size: clamp(20px, 1.45vw, 26px); padding: 12px 18px; } .podium-live-card .podium-medal-icon { /* filter: grayscale(1) brightness(1.2) drop-shadow(0 4px 10px rgba(0, 0, 0, 0.35)); */ - font-size: 60px; - margin-top: 86px; + font-size: 68px; + margin-top: 92px; } .podium-live-card .podium-col.pos-1 .podium-medal-icon { - font-size: 84px; - margin-top: 118px; + font-size: 94px; + margin-top: 126px; +} + +@media (min-width: 1400px) and (max-height: 780px) { + .app-shell.mode-live .masthead-main { + padding-top: 7px; + padding-bottom: 8px; + } + + .app-shell.mode-live .masthead-logo { + width: clamp(190px, 17vw, 300px); + } + + .app-shell.mode-live .masthead-subtitle { + display: none; + } + + .app-shell.mode-live .control-toggle-btn { + padding: 4px 8px; + font-size: 11px; + } + + .app-shell.mode-live .control-toggle-meta, + .app-shell.mode-live .server-time, + .app-shell.mode-live .live-badge { + font-size: 10px; + } + + .app-shell.mode-live .control-icon-btn { + width: 30px; + height: 30px; + } + + .app-shell.mode-live .control-icon-btn svg { + width: 14px; + height: 14px; + } + + .app-shell.mode-live .status-row { + gap: 6px; + } + + .app-shell.mode-live .page-content { + padding-top: 8px; + } + + .live-mode-shell, + .live-mode-overlay { + min-height: min(83vh, calc(100vh - 112px)); + } + + .live-mode-overlay { + padding: 10px 10px 8px; + } + + .live-mode-header h2 { + font-size: clamp(22px, 1.8vw, 34px); + } + + .live-mode-header p { + margin-bottom: 7px; + font-size: 12px; + } + + .live-focus-title { + font-size: clamp(42px, 4.4vw, 74px); + } + + .live-focus-banner.focus-final .live-focus-title { + font-size: clamp(26px, 2.9vw, 44px); + } + + .live-screen-head h3 { + font-size: clamp(20px, 1.42vw, 27px); + } + + .live-score-table thead th, + .live-screen-card .score-table thead th, + .live-screen-card .score-table td { + font-size: clamp(17px, 1.2vw, 23px); + padding: clamp(6px, 0.62vh, 9px) 7px; + } + + .live-screen-card .name-main { + font-size: clamp(17px, 1.2vw, 23px); + } + + .app-shell.mode-live .live-screen-card .competitor-cell.compact .competitor-image { + width: clamp(50px, 2.9vw, 66px); + height: clamp(50px, 2.9vw, 66px); + } + + .live-mode-footer { + padding: 6px 10px; + } + + .live-footer-logo { + height: 48px; + } + + .live-footer-logo-datwyler { + height: 54px; + } +} + +@media (min-width: 1800px) and (min-height: 880px) { + .app-shell.mode-live .masthead-main { + padding-top: 12px; + padding-bottom: 14px; + } + + .app-shell.mode-live .masthead-logo { + width: clamp(260px, 21.5vw, 430px); + } + + .app-shell.mode-live .masthead-subtitle { + font-size: clamp(11px, 0.7vw, 14px); + } + + .app-shell.mode-live .control-toggle-btn { + font-size: clamp(12px, 0.78vw, 14px); + } + + .live-mode-shell, + .live-mode-overlay { + min-height: min(86vh, calc(100vh - 128px)); + } + + .live-mode-overlay { + padding: 16px 18px 12px; + } + + .live-mode-header h2 { + font-size: clamp(32px, 2.1vw, 48px); + } + + .live-mode-header p { + font-size: clamp(16px, 1vw, 20px); + margin-bottom: 12px; + } + + .live-screen-card { + padding: 14px; + } + + .live-focus-title { + font-size: clamp(58px, 5.1vw, 98px); + } + + .live-focus-banner.focus-final .live-focus-title { + font-size: clamp(36px, 3.5vw, 66px); + } + + .live-screen-head h3 { + font-size: clamp(30px, 1.9vw, 40px); + } + + .live-score-table thead th, + .live-screen-card .score-table thead th, + .live-screen-card .score-table td { + font-size: clamp(23px, 1.55vw, 31px); + } + + .live-screen-card .name-main { + font-size: clamp(23px, 1.55vw, 31px); + } + + .app-shell.mode-live .live-screen-card .competitor-cell.compact .competitor-image { + width: clamp(64px, 3.25vw, 96px); + height: clamp(64px, 3.25vw, 96px); + } } @@ -2080,7 +2384,6 @@ select.name-input { flex-direction: column; align-items: center; position: relative; - background: #fff; border-radius: 16px 16px 0 0; box-shadow: 0 10px 40px rgba(13, 27, 46, 0.1); transition: transform 0.25s ease; @@ -2200,8 +2503,6 @@ select.name-input { } .podium-score-wrap { - margin-top: auto; - margin-bottom: 12px; width: calc(100% - 16px); display: grid; gap: 4px; @@ -2952,7 +3253,6 @@ select.name-input { min-height: 180px; height: auto !important; padding-top: 88px; - padding-bottom: 16px; } .podium-live-card .podium-img {