diff --git a/services/web-ui/public/screens-asset.jsx b/services/web-ui/public/screens-asset.jsx
index b66e1cc..165f3fa 100644
--- a/services/web-ui/public/screens-asset.jsx
+++ b/services/web-ui/public/screens-asset.jsx
@@ -2,18 +2,33 @@
const { COMMENTS: SEED_COMMENTS } = window.ZAMPP_DATA;
+// Simple gradient palette — replaces the missing thumbGrad function
+const _FRAME_GRADIENTS = [
+ 'linear-gradient(135deg,#1a1f2e 0%,#2a3045 100%)',
+ 'linear-gradient(135deg,#1e2030 0%,#2d2040 100%)',
+ 'linear-gradient(135deg,#0d1520 0%,#1a2535 100%)',
+ 'linear-gradient(135deg,#1f1a2e 0%,#2a2040 100%)',
+ 'linear-gradient(135deg,#0f1e18 0%,#1a3028 100%)',
+ 'linear-gradient(135deg,#1e1510 0%,#302018 100%)',
+ 'linear-gradient(135deg,#1a1020 0%,#281830 100%)',
+ 'linear-gradient(135deg,#101828 0%,#182438 100%)',
+ 'linear-gradient(135deg,#1e2820 0%,#283830 100%)',
+ 'linear-gradient(135deg,#201820 0%,#302030 100%)',
+ 'linear-gradient(135deg,#181e28 0%,#202838 100%)',
+];
+
function AssetDetail({ asset, onClose }) {
const [playing, setPlaying] = React.useState(false);
- const [currentMs, setCurrentMs] = React.useState(720000);
+ const [currentMs, setCurrentMs] = React.useState(0);
const [tab, setTab] = React.useState("comments");
const [showResolved, setShowResolved] = React.useState(false);
- const [comments, setComments] = React.useState(SEED_COMMENTS);
+ const [comments, setComments] = React.useState(SEED_COMMENTS || []);
const [newComment, setNewComment] = React.useState("");
const totalMs = parseDuration(asset.duration);
React.useEffect(() => {
- if (!playing) return;
+ if (!playing || totalMs <= 0) return;
const i = setInterval(() => {
setCurrentMs(t => {
const next = t + 100;
@@ -24,7 +39,7 @@ function AssetDetail({ asset, onClose }) {
return () => clearInterval(i);
}, [playing, totalMs]);
- const seek = (ms) => setCurrentMs(Math.max(0, Math.min(totalMs, ms)));
+ const seek = (ms) => setCurrentMs(Math.max(0, Math.min(totalMs || 0, ms)));
const addComment = () => {
if (!newComment.trim()) return;
const t = msToTimecode(currentMs);
@@ -51,14 +66,12 @@ function AssetDetail({ asset, onClose }) {
{asset.name}
- v3
- {asset.project}·{asset.bin}·updated {asset.updated}
+ {asset.project}·updated {asset.updated}
-
@@ -70,11 +83,21 @@ function AssetDetail({ asset, onClose }) {
- {!playing && (
+ {!playing && totalMs > 0 && (
)}
+ {totalMs <= 0 && (
+
+
+
+ {asset.status === 'processing' ? 'Processing…' : asset.status === 'live' ? 'Live recording in progress' : 'Preview not yet available'}
+
+
+
+
+ )}
{visibleComments
.filter(c => Math.abs(parseDuration(c.time) - currentMs) < 200)
@@ -90,26 +113,31 @@ function AssetDetail({ asset, onClose }) {
LIVE · REC
)}
-
-
{msToTimecode(currentMs)}
-
/ {asset.duration}
+ {totalMs > 0 && (
+
+ {msToTimecode(currentMs)}
+ / {asset.duration}
+
+ )}
+
+
+ {totalMs > 0 && (
+
+
+
{msToTimecode(currentMs)}
+
+
{asset.duration}
+
+
+
-
+ )}
-
-
-
{msToTimecode(currentMs)}
-
-
{asset.duration}
-
-
-
-
-
-
-
+ {totalMs > 0 && (
+
+ )}
@@ -117,7 +145,7 @@ function AssetDetail({ asset, onClose }) {
Comments
{comments.length}
@@ -170,20 +194,21 @@ function PlaybackBar({ current, total, onSeek, comments }) {
const p = (e.clientX - r.left) / r.width;
onSeek(Math.max(0, Math.min(1, p)) * total);
};
- const pct = (current / total) * 100;
+ const pct = total > 0 ? (current / total) * 100 : 0;
return (
{comments.map(c => {
- const x = (parseDuration(c.time) / total) * 100;
+ const ct = parseDuration(c.time);
+ if (!ct || total <= 0) return null;
+ const x = (ct / total) * 100;
return (
{ e.stopPropagation(); onSeek(parseDuration(c.time)); }}
+ onClick={(e) => { e.stopPropagation(); onSeek(ct); }}
>
{c.avatar}
@@ -197,23 +222,26 @@ function FilmStrip({ seed, current, total, onSeek, comments }) {
const ref = React.useRef(null);
const frames = 28;
const handle = (e) => {
+ if (!ref.current || total <= 0) return;
const r = ref.current.getBoundingClientRect();
onSeek(((e.clientX - r.left) / r.width) * total);
};
+ const pct = total > 0 ? (current / total) * 100 : 0;
return (
{Array.from({ length: frames }).map((_, i) => (
-
+
))}
-
+
{comments.map(c => {
- const x = (parseDuration(c.time) / total) * 100;
+ const ct = parseDuration(c.time);
+ if (!ct || total <= 0) return null;
+ const x = (ct / total) * 100;
return (
-
+
{c.avatar}
);
@@ -243,7 +271,7 @@ function CommentsList({ comments, onSeek, onResolve }) {
onSeek(c)}>{c.time}
{c.real}
-
onResolve(c.id)}>
+ onResolve(c.id)}>
@@ -262,15 +290,14 @@ function CommentComposer({ asset, currentMs, value, onChange, onSubmit }) {
Reviewers
- {["KM", "ZG", "MO", "JT"].map((a, i) => (
+ {["ZG"].map((a, i) => (
{a}
))}
-
+
@ {msToTimecode(currentMs)}
- Drawing tools