diff --git a/tl/resources/public/css/app.css b/tl/resources/public/css/app.css index 74b4bf5..38f661c 100644 --- a/tl/resources/public/css/app.css +++ b/tl/resources/public/css/app.css @@ -6,6 +6,7 @@ body { overflow: hidden; } .app { height: 100vh; + height: 100dvh; /* avoids mobile URL-bar jump where supported */ display: flex; flex-direction: column; overflow: hidden; @@ -15,21 +16,23 @@ body { overflow: hidden; } } /* --- top region: video | annotation ------------------------------------ */ -.top { display: flex; min-height: 0; } +/* sizes are relative (vh / %), set via CSS vars from the app; px mins below */ +.top { display: flex; min-height: 140px; height: var(--top-h, 46vh); } .video-pane { - flex-shrink: 0; + flex-shrink: 0; width: var(--video-w, 50%); min-width: 200px; display: flex; align-items: center; justify-content: center; - background: #000; overflow: hidden; min-width: 0; + background: #000; overflow: hidden; } .video-pane video { max-width: 100%; max-height: 100%; display: block; background: #000; } -.annot-pane { flex: 1; min-width: 0; display: flex; } +.annot-pane { flex: 1; min-width: 200px; display: flex; } /* --- draggable dividers ------------------------------------------------- */ -.divider-v { flex-shrink: 0; width: 6px; cursor: col-resize; background: #222; } -.divider-h { flex-shrink: 0; height: 6px; cursor: row-resize; background: #222; } -.divider-v:hover, .divider-h:hover { background: #3a6ea5; } +/* touch-action:none so a drag doesn't scroll the page on touch devices */ +.divider-v { flex-shrink: 0; width: 7px; cursor: col-resize; background: #222; touch-action: none; } +.divider-h { flex-shrink: 0; height: 7px; cursor: row-resize; background: #222; touch-action: none; } +.divider-v:hover, .divider-h:hover, .divider-v:active, .divider-h:active { background: #3a6ea5; } /* --- commentary --------------------------------------------------------- */ .commentary { @@ -69,6 +72,94 @@ body { overflow: hidden; } } .jump-pop button:hover { background: #2a4a6a; } +/* --- commentary head + actions ----------------------------------------- */ +.commentary-head { margin-bottom: 8px; } +.add-btn { + width: 100%; background: #1c2a38; color: #cfe3f5; + border: 1px solid #3a6ea5; border-radius: 4px; + padding: 6px 8px; cursor: pointer; font-size: 12px; +} +.add-btn:hover { background: #24384e; } +.ann-actions { display: flex; align-items: center; gap: 6px; flex-shrink: 0; } +.edit-btn { + background: none; color: #7aa6d6; border: 1px solid transparent; + border-radius: 4px; padding: 1px 6px; cursor: pointer; font-size: 11px; +} +.edit-btn:hover { color: #cfe3f5; border-color: #3a6ea5; } +.del-btn { + background: none; color: #a66; border: 1px solid transparent; + border-radius: 4px; padding: 1px 6px; cursor: pointer; font-size: 11px; +} +.del-btn:hover { color: #e66; border-color: #a44; } + +.clip.clickable { cursor: copy; outline: 1px solid #5ab07a; } + +/* --- authoring form (fills the annotation pane) ------------------------- */ +.form { + flex: 1; min-width: 0; overflow-y: auto; + background: #111; border: 1px solid #333; box-sizing: border-box; + padding: 10px 12px; + display: flex; flex-direction: column; gap: 10px; +} +.form-head { font-size: 13px; font-weight: 600; color: #cfe3f5; } +.form-row { display: flex; gap: 8px; align-items: center; } +.form-name { flex: 1; } +.form input[type=text], .form-name, .form-content { + background: #0e0e0e; color: #ddd; border: 1px solid #333; + border-radius: 4px; padding: 6px 8px; font-size: 13px; +} +.form-color { width: 40px; height: 32px; padding: 0; border: 1px solid #333; + border-radius: 4px; background: #0e0e0e; cursor: pointer; } +.form-content { width: 100%; min-height: 70px; resize: vertical; box-sizing: border-box; + font-family: inherit; } +.form-marks-label { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; + color: #7aa6d6; margin-top: 4px; } + +.mark-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; } +.mark-arrow { color: #666; } +.row-x, .add-mark { + background: #1c1c1c; color: #aaa; border: 1px solid #333; border-radius: 4px; + padding: 3px 8px; cursor: pointer; font-size: 12px; +} +.row-x:hover { color: #e66; border-color: #a44; } +.add-mark { align-self: flex-start; color: #cfe3f5; border-color: #3a6ea5; } + +/* point editor + autocomplete */ +.pt-input { position: relative; flex: 1 1 130px; display: inline-block; } +.pt-text { + width: 100%; box-sizing: border-box; + background: #0e0e0e; color: #ddd; border: 1px solid #333; + border-radius: 4px; padding: 6px 8px; font-size: 13px; +} +.pt-dropdown { + position: absolute; left: 0; right: 0; top: 100%; z-index: 5; + margin: 2px 0 0; padding: 4px; list-style: none; + max-height: 220px; overflow-y: auto; + background: #1b1b1b; border: 1px solid #3a6ea5; border-radius: 4px; + box-shadow: 0 6px 18px rgba(0,0,0,0.5); +} +.pt-dropdown li { padding: 4px 6px; border-radius: 3px; font-size: 12px; + color: #cde; cursor: pointer; white-space: nowrap; + overflow: hidden; text-overflow: ellipsis; } +.pt-dropdown li.hi { background: #2a4a6a; } + +.pt-chip { flex: 1; display: flex; align-items: center; gap: 4px; + background: #233; border: 1px solid #3a6ea5; border-radius: 4px; + padding: 2px 4px; } +.pt-chip-name { font-size: 12px; color: #cfe3f5; white-space: nowrap; + overflow: hidden; text-overflow: ellipsis; flex: 1; } +.pt-frame { width: 56px; background: #0e0e0e; color: #ddd; border: 1px solid #333; + border-radius: 3px; padding: 2px 4px; font-size: 12px; } +.pt-dur { color: #889; font-size: 11px; white-space: nowrap; } +.pt-x { background: none; border: none; color: #a99; cursor: pointer; font-size: 14px; } +.pt-x:hover { color: #e66; } + +.form-hint { font-size: 11px; color: #777; } +.form-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 4px; } +.save, .cancel { border-radius: 4px; padding: 6px 14px; cursor: pointer; font-size: 13px; } +.save { background: #2a4a6a; color: #fff; border: 1px solid #3a6ea5; } +.cancel { background: #1c1c1c; color: #aaa; border: 1px solid #333; } + /* --- markdown (tl.md output is wrapped in .md) -------------------------- */ .md h1 { font-size: 16px; margin: 0 0 6px; line-height: 1.25; } .md h2 { font-size: 14px; margin: 0 0 6px; line-height: 1.25; } @@ -79,12 +170,18 @@ body { overflow: hidden; } .md code { background: #222; padding: 0 3px; border-radius: 3px; font-size: 12px; } /* --- timeline region ---------------------------------------------------- */ -.timeline-pane { flex: 1; display: flex; flex-direction: column; min-height: 0; } +.timeline-pane { flex: 1; display: flex; flex-direction: column; min-height: 150px; } -.toolbar { display: flex; gap: 20px; align-items: center; padding: 6px 8px; - background: #0c0c0c; border-bottom: 1px solid #222; flex-shrink: 0; } +.toolbar { display: flex; flex-wrap: wrap; gap: 8px 18px; align-items: center; + padding: 6px 8px; background: #0c0c0c; border-bottom: 1px solid #222; + flex-shrink: 0; } .slider { display: flex; align-items: center; gap: 6px; font-size: 11px; color: #9ab; } -.slider input { width: 150px; } +.slider input { width: 150px; touch-action: none; } +.play-btn { + background: #1c2a38; color: #cfe3f5; border: 1px solid #3a6ea5; + border-radius: 4px; padding: 2px 12px; cursor: pointer; font-size: 14px; line-height: 1.4; +} +.play-btn:hover { background: #24384e; } .timeline-scroll { flex: 1; overflow-y: auto; overflow-x: hidden; min-height: 0; } .timeline { display: flex; align-items: flex-start; background: #111; } @@ -117,3 +214,13 @@ body { overflow: hidden; } .ann-bar-label { position: absolute; top: 1px; font-size: 9px; line-height: 16px; color: #eee; white-space: nowrap; pointer-events: none; text-shadow: 0 1px 2px #000; } + +/* --- mobile: stack the top region vertically (video over annotation) ---- */ +@media (max-width: 720px) { + .top { flex-direction: column; } + .divider-v { display: none; } /* width-split is meaningless when stacked */ + .video-pane { width: 100%; min-width: 0; flex: 1 1 0; min-height: 110px; } + .annot-pane { width: 100%; min-width: 0; flex: 1 1 0; min-height: 110px; } + .divider-h { height: 14px; } /* bigger touch target (top vs timeline) */ + .slider input { width: 120px; } +} diff --git a/tl/resources/public/icons/apple-touch-icon.png b/tl/resources/public/icons/apple-touch-icon.png new file mode 100644 index 0000000..f375569 Binary files /dev/null and b/tl/resources/public/icons/apple-touch-icon.png differ diff --git a/tl/resources/public/icons/icon-192.png b/tl/resources/public/icons/icon-192.png new file mode 100644 index 0000000..823e1e6 Binary files /dev/null and b/tl/resources/public/icons/icon-192.png differ diff --git a/tl/resources/public/icons/icon-512.png b/tl/resources/public/icons/icon-512.png new file mode 100644 index 0000000..94f8383 Binary files /dev/null and b/tl/resources/public/icons/icon-512.png differ diff --git a/tl/resources/public/index.html b/tl/resources/public/index.html index a9a0f93..5b0f759 100644 --- a/tl/resources/public/index.html +++ b/tl/resources/public/index.html @@ -2,9 +2,18 @@ - + tl + + + + + + + + +