From 12568b82cc5eed7847667dfe33a231d84fa88da5 Mon Sep 17 00:00:00 2001 From: Giorgio Gilestro Date: Fri, 1 May 2026 14:15:42 +0100 Subject: [PATCH] Welcome modal + port 8085 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a dismissable welcome modal that walks first-time users through the proper annotation sequence (slider to end → check open ROIs → slider to start → arrow-key fine-tune → click). Stays hidden after the first "Got it" via localStorage; the ? button in the header reopens it any time. Picker keyboard shortcuts are inert while the modal is showing. Container exposes 8085 instead of 8000 (8000 was free, but Giorgio's preferred 8082 is already in use on this host; 8085 is the closest free port). Internal port stays 8000 so the FastAPI app is unchanged. Co-Authored-By: Claude Opus 4.7 --- scripts/barrier_picker_app/README.md | 2 +- scripts/barrier_picker_app/docker-compose.yml | 2 +- scripts/barrier_picker_app/static/index.html | 102 ++++++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/scripts/barrier_picker_app/README.md b/scripts/barrier_picker_app/README.md index 2b0614f..2b803bf 100644 --- a/scripts/barrier_picker_app/README.md +++ b/scripts/barrier_picker_app/README.md @@ -38,7 +38,7 @@ cd scripts/barrier_picker_app docker compose up --build ``` -Then browse to http://localhost:8000/. +Then browse to http://localhost:8085/. The container mounts: - `/mnt/data/projects/cupido` (data volume, read-only) diff --git a/scripts/barrier_picker_app/docker-compose.yml b/scripts/barrier_picker_app/docker-compose.yml index 9c9a241..2365997 100644 --- a/scripts/barrier_picker_app/docker-compose.yml +++ b/scripts/barrier_picker_app/docker-compose.yml @@ -4,7 +4,7 @@ services: image: cupido-barrier-picker container_name: cupido-barrier-picker ports: - - "8000:8000" + - "8085:8000" volumes: # Project data volume (videos + tracking DBs + merged TSV) — read-only. - /mnt/data/projects/cupido:/mnt/data/projects/cupido:ro diff --git a/scripts/barrier_picker_app/static/index.html b/scripts/barrier_picker_app/static/index.html index 5e5a1f1..04a67bf 100644 --- a/scripts/barrier_picker_app/static/index.html +++ b/scripts/barrier_picker_app/static/index.html @@ -50,6 +50,32 @@ #flash.show { opacity: 1; } #flash.ok { background: #2d5; color: #042; } #flash.err { background: #d44; color: white; } + + /* Welcome modal */ + #help-btn { background: transparent; border: 1px solid #444; color: #aab; + font-size: 0.85rem; padding: 0.3rem 0.7rem; } + #help-btn:hover { background: #2a2a2a; } + #modal-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.85); + display: none; align-items: center; justify-content: center; + z-index: 100; padding: 1rem; } + #modal-backdrop.show { display: flex; } + #modal { background: #222; border: 1px solid #444; border-radius: 6px; + padding: 1.6rem 2rem; max-width: 640px; width: 100%; + max-height: 90vh; overflow-y: auto; color: #ddd; line-height: 1.55; } + #modal h2 { margin: 0 0 0.6rem; color: #fff; font-size: 1.2rem; } + #modal h3 { margin: 1.2rem 0 0.4rem; color: #cce; font-size: 0.95rem; + font-weight: 600; } + #modal p { margin: 0.5rem 0; } + #modal ol { padding-left: 1.4rem; margin: 0.5rem 0; } + #modal li { margin: 0.6rem 0; } + #modal .button-tag { display: inline-block; padding: 0.05rem 0.4rem; + background: #2d5; color: #053; border-radius: 3px; + font-weight: 600; font-size: 0.85rem; } + #modal-close { margin-top: 1.4rem; width: 100%; padding: 0.7rem; + background: #2d5; color: #053; font-weight: 600; + border-radius: 4px; cursor: pointer; border: 1px solid #1a4; + font-size: 0.95rem; } + #modal-close:hover { background: #3e6; } @@ -57,8 +83,56 @@

Cupido — barrier picker

loading… + + +
@@ -213,6 +287,8 @@ // Keyboard shortcuts document.addEventListener('keydown', (e) => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; + // Don't react to picker shortcuts while the modal is open. + if (modalBackdrop.classList.contains('show')) return; // Prevent the browser default (e.g. video focus side effects on space). const stop = () => { e.preventDefault(); e.stopPropagation(); }; switch (e.key) { @@ -236,6 +312,32 @@ } }); + // Welcome modal — show first time, dismissable; ? button reopens it. + const modalBackdrop = document.getElementById('modal-backdrop'); + const modalClose = document.getElementById('modal-close'); + const helpBtn = document.getElementById('help-btn'); + + function showModal() { modalBackdrop.classList.add('show'); } + function hideModal() { + modalBackdrop.classList.remove('show'); + try { localStorage.setItem('cupido.welcomed', '1'); } catch (e) {} + } + modalClose.addEventListener('click', hideModal); + helpBtn.addEventListener('click', showModal); + // Allow click-on-backdrop to dismiss (but not click-inside-modal) + modalBackdrop.addEventListener('click', (e) => { + if (e.target === modalBackdrop) hideModal(); + }); + // Escape closes the modal too. + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && modalBackdrop.classList.contains('show')) { + e.stopPropagation(); hideModal(); + } + }); + let welcomed = false; + try { welcomed = localStorage.getItem('cupido.welcomed') === '1'; } catch (e) {} + if (!welcomed) showModal(); + fetchQueue();