feat: move the event tag input into the left stats column

The tag input and its prev/next buttons spanned the full width of the
event view above the video row. Move the tags-container into the
eventStats column and narrow that column from col-sm-4 to col-sm-3 so
the video gets the width back.

- tags-container drops its 1rem side margins, which were sized for a
  full-width bar, and gains bottom spacing to separate it from the
  stats table.
- tag-dropdown gets position: relative so the suggestion list anchors
  under the input. It had no positioned ancestor before, so in the
  narrower column the absolutely positioned list would have landed in
  the wrong place. It also gets a min-width so the input stays usable
  once tag chips wrap.
- tag-dropdown-content sizes to its items rather than to the narrow
  input.
- tag-input can shrink inside the flex row instead of forcing overflow.

event.js toggles the video wrapper between the stats-visible width and
col-sm-12 when the stats column is hidden, so update those six places
to col-sm-9 as well.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Isaac ConnorandClaude Opus 5 committed 2026-09-26 12:53:02 -04:00
1 parent da0ba713c1
commit 710c6f07e8
3 files changed
+39 -30

No files matched your search

+11 -2
View File
@@ -1109,10 +1109,11 @@ a.flip {
.tags-container {
display: flex;
flex-wrap: wrap;
align-items: center;
border: 1px solid var(--gray);
border-radius: 4px;
/*min-height: 35px;*/
margin: 0.25rem 1rem 0.25rem 1rem;
margin: 0 0 0.5rem 0;
}
.tags-container button {
@@ -1146,6 +1147,8 @@ a.flip {
height: 100%;
border: none;
width: 100%;
min-width: 0;
background: transparent;
}
.tag-input:focus {
@@ -1155,14 +1158,20 @@ a.flip {
.tag-dropdown {
vertical-align: center;
display: inline-block;
position: relative;
flex-grow: 2;
min-width: 4em;
}
.tag-dropdown-content {
display: none;
position: absolute;
top: 100%;
left: 0;
background-color: #f9f9f9;
min-width: 160px;
min-width: 100%;
width: max-content;
max-width: 300px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 15;
padding: 4px 0;
+22 -22
View File
@@ -272,32 +272,32 @@ if ( $Event->Id() and !file_exists($Event->Path()) )
</div>
</div>
<?php if ( $Event->Id() ) { ?>
<div class="tags-container">
<div class="tag-dropdown">
<!-- input type has to be "search" (not "text") so that the Enter button (not Next) works on mobile Chrome browser. -->
<input type="search" id="tagInput" class="tag-input" placeholder="Add tag" data-role="tagsinput">
<div class="tag-dropdown-content"></div>
</div>
<button type="button" id="tagPrevBtn" title="<?php echo translate('Apply the last tag, then play the previous event') ?>" class="inactive" data-on-click-true="tagAndPrev">
<i class="material-icons md-18"
style="-moz-transform: scaleX(-1);
-o-transform: scaleX(-1);
-webkit-transform: scaleX(-1);
transform: scaleX(-1);
filter: FlipH;
-ms-filter: 'FlipH';">
label</i>
</button>
<button type="button" id="tagNextBtn" title="<?php echo translate('Apply the last tag, then play the next event') ?>" class="inactive" data-on-click-true="tagAndNext">
<i class="material-icons md-18">label</i>
</button>
</div>
<!-- BEGIN VIDEO CONTENT ROW -->
<div id="inner-content">
<div class="d-flex flex-row px-3">
<div class="container-fluid">
<div class="row row-cols-1 row-cols-sm-2">
<div id = "eventStats" class="col col-sm-4 eventStats">
<div id = "eventStats" class="col col-sm-3 eventStats">
<div class="tags-container">
<div class="tag-dropdown">
<!-- input type has to be "search" (not "text") so that the Enter button (not Next) works on mobile Chrome browser. -->
<input type="search" id="tagInput" class="tag-input" placeholder="Add tag" data-role="tagsinput">
<div class="tag-dropdown-content"></div>
</div>
<button type="button" id="tagPrevBtn" title="<?php echo translate('Apply the last tag, then play the previous event') ?>" class="inactive" data-on-click-true="tagAndPrev">
<i class="material-icons md-18"
style="-moz-transform: scaleX(-1);
-o-transform: scaleX(-1);
-webkit-transform: scaleX(-1);
transform: scaleX(-1);
filter: FlipH;
-ms-filter: 'FlipH';">
label</i>
</button>
<button type="button" id="tagNextBtn" title="<?php echo translate('Apply the last tag, then play the next event') ?>" class="inactive" data-on-click-true="tagAndNext">
<i class="material-icons md-18">label</i>
</button>
</div><!--tags-container-->
<!-- VIDEO STATISTICS TABLE -->
<table id="eventStatsTable" class="table-sm table-borderless">
<!-- EVENT STATISTICS POPULATED BY JAVASCRIPT -->
@@ -336,7 +336,7 @@ if (file_exists($Event->Path().'/objdetect.jpg')) {
?>
</div><!-- id="frames" -->
</div><!-- id="eventStats" -->
<div id="wrapperEventVideo" class="col col-sm-8 pl-0 pr-0">
<div id="wrapperEventVideo" class="col col-sm-9 pl-0 pr-0">
<div id="eventVideo">
<!-- VIDEO CONTENT -->
<div id="videoFeed">
+6 -6
View File
@@ -1381,7 +1381,7 @@ function onStatsResize(vidWidth) {
if (eventStats.is(':visible')) {
eventStats.toggle(false);
wasHidden = true;
wrapperEventVideo.removeClass('col-sm-8').addClass('col-sm-12');
wrapperEventVideo.removeClass('col-sm-9').addClass('col-sm-12');
}
// Show the stats table if we hid it previously and sufficient room becomes available
} else if (width >= minWidth) {
@@ -1389,7 +1389,7 @@ function onStatsResize(vidWidth) {
if ( !eventStats.is(':visible') && wasHidden ) {
eventStats.toggle(true);
wasHidden = false;
wrapperEventVideo.removeClass('col-sm-12').addClass('col-sm-8');
wrapperEventVideo.removeClass('col-sm-12').addClass('col-sm-9');
}
}
}
@@ -1413,10 +1413,10 @@ function initPage() {
if (getEvtStatsCookie() != 'on') {
eventStats.toggle(false);
wrapperEventVideo.removeClass('col-sm-8').addClass('col-sm-12');
wrapperEventVideo.removeClass('col-sm-9').addClass('col-sm-12');
} else {
onStatsResize(eventData.Width);
wrapperEventVideo.removeClass('col-sm-12').addClass('col-sm-8');
wrapperEventVideo.removeClass('col-sm-12').addClass('col-sm-9');
}
if (eventData.DefaultVideo) {
canPlayCodec(eventData.DefaultVideo);
@@ -1614,11 +1614,11 @@ function initPage() {
if (eventStats.is(':visible')) {
setCookie(cookie, 'off');
eventStats.toggle(false);
wrapperEventVideo.removeClass('col-sm-8').addClass('col-sm-12');
wrapperEventVideo.removeClass('col-sm-9').addClass('col-sm-12');
} else {
setCookie(cookie, 'on');
eventStats.toggle(true);
wrapperEventVideo.removeClass('col-sm-12').addClass('col-sm-8');
wrapperEventVideo.removeClass('col-sm-12').addClass('col-sm-9');
}
changeScale();
});