Match cards: composed title, header stage from match title, equal-sized grid

- SportsMatchController syncs Video.title with SportsMatch.title on
  store/update so the "Match title" field drives the video's display
  title everywhere.
- headerData(): "championship" now prefers event_name (event title)
  and adds a dedicated "stage" key sourced from SportsMatch.title
  (shown between the yellow lines above the weight class in both the
  in-player VS overlay and the vs-mini gallery card).
- Video cards render match titles with flags + corner colours
  ("FINALS – 🇧🇭 Blue vs 🇧🇭 Red (-61 kg)"), matching the video
  page header, and clip long titles to one line.
- Video gallery grid uses repeat(N, minmax(0, 1fr)) + grid-auto-rows:1fr
  so every card thumbnail renders at exactly the same size; hover-preview
  videos use object-fit:cover to stop portrait sources looking smaller.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
ghassanandClaude Opus 4.7 committed 2026-08-11 09:14:25 +03:00
1 parent 04d63cccdb
commit 665bad76bf
7 files changed
+128 -37

No files matched your search

+23 -24
View File
@@ -7,18 +7,28 @@
/* ── Regular video grid ── */
.yt-video-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
/* minmax(0, 1fr) keeps every column exactly equal in width.
Plain 1fr lets a track grow if a child's min-content is wider
than the share, which was making the 3rd column wider (and
therefore taller, since the thumb is 16/9) than the first two. */
grid-template-columns: repeat(3, minmax(0, 1fr));
grid-auto-rows: 1fr;
align-items: stretch;
gap: 20px;
}
@media (max-width: 992px) { .yt-video-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 576px) { .yt-video-grid { grid-template-columns: 1fr; gap: 14px; } }
.yt-video-grid > .yt-video-card { height: 100%; min-width: 0; }
@media (max-width: 992px) { .yt-video-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 576px) { .yt-video-grid { grid-template-columns: minmax(0, 1fr); gap: 14px; } }
/* ── Thumbnail orientation fix ── */
/* ── Thumbnail orientation fix ── */
.yt-video-card .yt-video-thumb img { object-fit: cover; }
/* ── Thumbnail orientation fix ──
Always cover so every thumbnail visually fills its 16/9 box the
same way. `!important` beats any leftover inline style from the
old adjust-fit script (cached page in the wild). */
.yt-video-card .yt-video-thumb img { object-fit: cover !important; }
/* ── Search result helpers ── */
.search-info { margin-bottom: 20px; padding: 16px; background: var(--bg-secondary); border-radius: 12px; }
@@ -207,18 +217,11 @@
@section('scripts')
<script>
(function () {
function adjustPlThumb(img) {
img.style.objectFit = img.naturalWidth < img.naturalHeight ? 'contain' : 'cover';
}
document.querySelectorAll('.yt-video-thumb img').forEach(function (img) {
if (img.complete && img.naturalWidth) {
adjustPlThumb(img);
} else {
img.addEventListener('load', function () { adjustPlThumb(img); });
}
});
})();
/* Thumbnails render at a uniform size: the .yt-video-thumb box is a
strict 16/9 container and every image inside it uses `object-fit:
cover` (set in the shared card CSS) so portrait/square art fills the
frame instead of shrinking with letterboxing. No per-image adjustment
needed. */
/* ─── Filter-bar horizontal scroll ─── */
(function () {
@@ -301,13 +304,9 @@
});
}
// Re-run any grid-scoped init that the page's other IIFE did on first load.
function reinitGrid(root) {
root.querySelectorAll('.yt-video-thumb img').forEach(function (img) {
function fit() { img.style.objectFit = img.naturalWidth < img.naturalHeight ? 'contain' : 'cover'; }
if (img.complete && img.naturalWidth) fit(); else img.addEventListener('load', fit);
});
}
// No per-image sizing needed — CSS `object-fit: cover` on
// `.yt-video-thumb img` gives every card the same visible image size.
function reinitGrid(_root) {}
var currentReq = 0;
async function swapTo(url, pushHist) {