chordia-ui 3.4.0 → 3.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Timeline.cjs.js +1 -6
- package/dist/Timeline.cjs.js.map +1 -1
- package/dist/Timeline.es.js +129 -597
- package/dist/Timeline.es.js.map +1 -1
- package/dist/TranscriptCard.cjs.js +7 -0
- package/dist/TranscriptCard.cjs.js.map +1 -0
- package/dist/TranscriptCard.es.js +474 -0
- package/dist/TranscriptCard.es.js.map +1 -0
- package/dist/UpdatedInteractionRecording.cjs.js +1 -1
- package/dist/UpdatedInteractionRecording.cjs.js.map +1 -1
- package/dist/UpdatedInteractionRecording.es.js +516 -420
- package/dist/UpdatedInteractionRecording.es.js.map +1 -1
- package/dist/components/UpdatedInteractionDetails.cjs.js +2 -2
- package/dist/components/UpdatedInteractionDetails.cjs.js.map +1 -1
- package/dist/components/UpdatedInteractionDetails.es.js +304 -285
- package/dist/components/UpdatedInteractionDetails.es.js.map +1 -1
- package/dist/components/media.cjs.js +1 -1
- package/dist/components/media.cjs.js.map +1 -1
- package/dist/components/media.es.js +9 -8
- package/dist/components/media.es.js.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs2.js +1 -1
- package/dist/index.cjs2.js.map +1 -1
- package/dist/index.cjs3.js +2 -2
- package/dist/index.cjs3.js.map +1 -1
- package/dist/index.es.js +53 -52
- package/dist/index.es.js.map +1 -1
- package/dist/index.es2.js +1 -1
- package/dist/index.es2.js.map +1 -1
- package/dist/index.es3.js +11 -4
- package/dist/index.es3.js.map +1 -1
- package/dist/pages/interactionDetails.cjs.js +2 -2
- package/dist/pages/interactionDetails.cjs.js.map +1 -1
- package/dist/pages/interactionDetails.es.js +17 -16
- package/dist/pages/interactionDetails.es.js.map +1 -1
- package/package.json +1 -1
- package/src/components/UpdatedInteractionDetails/UpdatedInteractionDetails.jsx +125 -107
- package/src/components/UpdatedInteractionDetails/UpdatedInteractionRecording.jsx +342 -178
package/dist/Timeline.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Timeline.es.js","sources":["../src/components/media/ConversationTurn.jsx","../src/components/media/TranscriptCard.jsx","../src/components/media/Timeline.jsx"],"sourcesContent":["\"use client\";\n\nimport React, { useEffect } from \"react\";\n\n/**\n * Actor configuration — rail color + subtle card tint per role.\n * Colors reference CSS custom properties from the Chordia design system.\n */\nconst ACTOR_DEFAULTS = {\n customer: {\n label: \"Customer\",\n railColor: \"var(--rail-discovery)\",\n cardBg: \"var(--card-customer)\",\n cardBgHighlight: \"rgba(94, 136, 176, 0.12)\",\n borderColor: \"var(--border-subtle)\",\n },\n agent: {\n label: \"Agent\",\n railColor: \"var(--rail-outcome)\",\n cardBg: \"var(--card-agent)\",\n cardBgHighlight: \"rgba(107, 124, 147, 0.10)\",\n borderColor: \"var(--border-subtle)\",\n },\n assistant: {\n label: \"AI Assistant\",\n railColor: \"var(--rail-purple)\",\n cardBg: \"var(--card-assistant)\",\n cardBgHighlight: \"rgba(155, 122, 168, 0.10)\",\n borderColor: \"var(--border-subtle)\",\n },\n system: {\n label: \"System\",\n railColor: \"var(--text-faint)\",\n cardBg: \"transparent\",\n cardBgHighlight: \"transparent\",\n borderColor: \"transparent\",\n },\n};\n\n/**\n * ConversationTurn Component\n * Displays a single turn in a live conversation stream.\n * Uses the TranscriptCard design language: left actor rail, uppercase label,\n * subtle per-actor card tinting.\n *\n * @param {Object} props\n * @param {string} props.role - \"customer\" | \"agent\" | \"assistant\" | \"system\"\n * @param {string} props.text - Message content\n * @param {string} [props.actorLabel] - Override the default actor label\n * @param {string} [props.actorRailColor] - Override the rail color for this turn\n * @param {string} [props.actionKicker] - NBA action label above message\n * @param {Array} [props.toolBadges] - [{name, success, pending}] tool call results\n * @param {boolean} [props.streaming] - Whether this message is actively streaming\n * @param {string} [props.meta] - Timing info, turn number, etc.\n * @param {string} [props.timeRange] - Time range label (e.g., \"00:03–00:07\")\n * @param {boolean} [props.isHighlighted] - Extra emphasis on this turn\n * @param {string} [props.highlightRailColor] - Color for the right highlight rail (when highlighted)\n * @param {React.ReactNode} [props.children] - Additional content below the message text\n */\nconst KEYFRAMES_ID = \"conversation-turn-keyframes\";\nfunction ensureKeyframes() {\n if (typeof document === \"undefined\") return;\n if (document.getElementById(KEYFRAMES_ID)) return;\n const style = document.createElement(\"style\");\n style.id = KEYFRAMES_ID;\n style.textContent = `\n @keyframes turn-playing-pulse {\n 0%, 100% { opacity: 0.4; }\n 50% { opacity: 0.9; }\n }\n `;\n document.head.appendChild(style);\n}\n\nexport default function ConversationTurn({\n role = \"agent\",\n text,\n actorLabel,\n actorRailColor,\n actionKicker,\n toolBadges,\n streaming = false,\n meta,\n timeRange,\n isHighlighted = false,\n highlightRailColor,\n observations,\n onObservationClick,\n children,\n}) {\n useEffect(() => { ensureKeyframes(); }, []);\n const actor = ACTOR_DEFAULTS[role] || ACTOR_DEFAULTS.agent;\n const label = actorLabel || actor.label;\n const railColor = actorRailColor || actor.railColor;\n const highlighted = isHighlighted || streaming;\n\n // System messages: minimal centered text, no card\n if (role === \"system\") {\n return (\n <div\n style={{\n textAlign: \"center\",\n padding: \"6px 0\",\n flexShrink: 0,\n fontSize: \"var(--text-sm, 11px)\",\n color: \"var(--text-faint, rgba(30,33,37,0.36))\",\n fontWeight: 500,\n letterSpacing: \"0.02em\",\n }}\n >\n {text}\n </div>\n );\n }\n\n return (\n <div\n style={{\n position: \"relative\",\n padding: \"10px 14px 10px 18px\",\n borderRadius: 10,\n overflow: \"hidden\",\n flexShrink: 0,\n background: highlighted ? actor.cardBgHighlight : actor.cardBg,\n border: `1px solid ${streaming ? railColor : actor.borderColor}`,\n boxShadow: streaming\n ? `0 0 8px ${actor.cardBgHighlight}`\n : \"none\",\n transition: \"background 0.2s, border-color 0.2s, box-shadow 0.2s\",\n }}\n >\n {/* Left actor rail */}\n <div\n style={{\n position: \"absolute\",\n left: 0,\n top: 0,\n bottom: 0,\n width: \"var(--rail-width-thin, 4px)\",\n backgroundColor: railColor,\n borderRadius: \"10px 0 0 10px\",\n }}\n />\n\n {/* Header row: actor label left, tool badges right */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"flex-start\",\n justifyContent: \"space-between\",\n gap: 8,\n marginBottom: 4,\n }}\n >\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 2 }}>\n {/* Action kicker (NBA label) */}\n {actionKicker ? (\n <div\n style={{\n fontSize: \"var(--text-xs-plus, 10.5px)\",\n fontWeight: 650,\n textTransform: \"uppercase\",\n letterSpacing: \"var(--tracking-label, 0.16em)\",\n color: railColor,\n }}\n >\n {actionKicker}\n </div>\n ) : null}\n\n {/* Actor label */}\n <div\n style={{\n fontSize: \"var(--text-xs-plus, 10.5px)\",\n fontWeight: 650,\n textTransform: \"uppercase\",\n letterSpacing: \"var(--tracking-label, 0.16em)\",\n color: \"var(--text-faint, rgba(30,33,37,0.36))\",\n }}\n >\n {label}\n </div>\n </div>\n\n {/* Tool badges — top right pills, uniform neutral with status dot */}\n {toolBadges && toolBadges.length > 0 ? (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 4, flexShrink: 0, justifyContent: \"flex-end\" }}>\n {toolBadges.map((t, i) => {\n const isPending = t.pending;\n const isError = !isPending && t.success === false;\n // Dot color only — rail colors for categorization, not judgment\n const dotColor = isPending\n ? \"var(--rail-discovery, #5E88B0)\"\n : isError\n ? \"var(--rail-compliance, #C98A5A)\"\n : \"var(--text-xfaint, rgba(30,33,37,0.28))\";\n\n return (\n <span\n key={i}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 5,\n fontSize: \"var(--text-xs, 10px)\",\n padding: \"2px 8px 2px 6px\",\n borderRadius: 999,\n background: \"var(--paper, rgba(255,255,255,0.78))\",\n border: \"1px solid var(--border-subtle, rgba(52,58,64,0.08))\",\n color: \"var(--text-faint, rgba(30,33,37,0.36))\",\n fontWeight: 500,\n fontFamily: \"var(--font-fira-code, var(--font-mono, monospace))\",\n letterSpacing: \"0.01em\",\n lineHeight: 1.4,\n whiteSpace: \"nowrap\",\n }}\n >\n <span\n style={{\n width: 5,\n height: 5,\n borderRadius: \"50%\",\n backgroundColor: dotColor,\n flexShrink: 0,\n }}\n />\n {t.name}\n </span>\n );\n })}\n </div>\n ) : null}\n </div>\n\n {/* Message text */}\n <div\n style={{\n fontSize: \"var(--text-md, 13px)\",\n lineHeight: \"var(--leading-normal, 1.5)\",\n color: streaming\n ? \"var(--text-strong, rgba(30,33,37,0.92))\"\n : \"var(--text-base, rgba(30,33,37,0.78))\",\n fontWeight: streaming ? 550 : 400,\n }}\n >\n {text}\n {streaming ? (\n <span\n style={{\n display: \"inline-block\",\n width: 6,\n height: 14,\n background: railColor,\n marginLeft: 2,\n borderRadius: 1,\n animation: \"cursorBlink 0.8s ease-in-out infinite\",\n verticalAlign: \"text-bottom\",\n }}\n />\n ) : null}\n </div>\n\n {/* Time range + play button + observation pills — single row */}\n {timeRange || children || (observations && observations.length > 0) ? (\n <div style={{ marginTop: 6, display: \"flex\", alignItems: \"center\", gap: 6 }}>\n {children}\n {timeRange ? (\n <span\n style={{\n fontSize: \"var(--text-sm, 11px)\",\n padding: \"2px 8px\",\n borderRadius: 999,\n border: \"1px solid var(--border, rgba(52,58,64,0.12))\",\n background: \"var(--timestamp-bg, rgba(255,255,255,0.70))\",\n color: \"var(--text-muted, rgba(30,33,37,0.56))\",\n fontFamily: \"var(--font-mono, monospace)\",\n }}\n >\n {timeRange}\n </span>\n ) : null}\n {observations && observations.length > 0 ? (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 4, marginLeft: \"auto\" }}>\n {observations.map((obs, i) => (\n <span\n key={i}\n onClick={obs.onClick || (onObservationClick ? () => onObservationClick(obs) : undefined)}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 4,\n fontSize: \"var(--text-xs, 10px)\",\n padding: \"2px 8px\",\n borderRadius: 999,\n background: `color-mix(in srgb, ${obs.color || \"var(--state-present)\"} 12%, transparent)`,\n border: `1px solid color-mix(in srgb, ${obs.color || \"var(--state-present)\"} 25%, transparent)`,\n color: obs.color || \"var(--state-present)\",\n fontWeight: 550,\n lineHeight: 1.4,\n whiteSpace: \"nowrap\",\n cursor: obs.onClick || onObservationClick ? \"pointer\" : \"default\",\n transition: \"background 0.15s\",\n }}\n title={obs.reason || obs.label}\n >\n <span style={{\n width: 4, height: 4, borderRadius: \"50%\",\n backgroundColor: obs.color || \"var(--state-present)\",\n flexShrink: 0, opacity: 0.7,\n }} />\n {obs.label}\n </span>\n ))}\n </div>\n ) : null}\n </div>\n ) : null}\n\n {/* Meta / timestamp */}\n {meta ? (\n <div\n style={{\n marginTop: 6,\n fontSize: \"var(--text-xs-plus, 10.5px)\",\n color: \"var(--text-faint, rgba(30,33,37,0.36))\",\n fontFamily: \"var(--font-mono, monospace)\",\n }}\n >\n {meta}\n </div>\n ) : null}\n\n {/* Right highlight rail (used by TranscriptCard for active/highlighted turns) */}\n {highlighted && highlightRailColor ? (\n <div\n style={{\n position: \"absolute\",\n right: 8,\n top: 8,\n bottom: 8,\n width: 6,\n borderRadius: 4,\n backgroundColor: highlightRailColor,\n opacity: 0.7,\n animation: \"turn-playing-pulse 1.5s ease-in-out infinite\",\n }}\n />\n ) : null}\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useState, useRef, useEffect } from \"react\";\nimport { Play, Pause } from \"lucide-react\";\nimport ConversationTurn from \"./ConversationTurn\";\n\n/**\n * Helper function to parse time range string (e.g., \"00:03–00:07\") to seconds\n */\nconst parseTimeRange = (timeRange) => {\n const [start, end] = timeRange.split(\"–\").map((time) => {\n const [minutes, seconds] = time.split(\":\").map(Number);\n return minutes * 60 + seconds;\n });\n return { start, end };\n};\n\n/**\n * Map TranscriptCard actorType values to ConversationTurn role values.\n * ConversationTurn uses: \"customer\" | \"agent\" | \"assistant\" | \"system\"\n * TranscriptCard uses: \"customer\" | \"agent\" | \"third_party\" | \"system\"\n */\nconst mapActorTypeToRole = (actorType) => {\n const map = {\n customer: \"customer\",\n agent: \"agent\",\n third_party: \"agent\",\n system: \"system\",\n assistant: \"assistant\",\n };\n return map[actorType] || \"agent\";\n};\n\n/**\n * TranscriptCard Component\n * Displays a complete transcript with multiple turns, audio playback,\n * highlighting, and per-turn play buttons. Composes ConversationTurn\n * for individual turn rendering.\n *\n * @param {Object} props - Component props\n * @param {Array} props.turns - Array of transcript turn objects\n * @param {string} props.turns[].actor - Display name (e.g., \"Agent\", \"Customer\")\n * @param {string} props.turns[].actorType - \"agent\" | \"customer\" | \"third_party\" | \"system\" | \"assistant\"\n * @param {string} [props.turns[].actorColor] - Override rail color for this turn\n * @param {string} props.turns[].text - Transcript text\n * @param {string} [props.turns[].timeRange] - Time range (e.g., \"00:03–00:07\")\n * @param {boolean} [props.turns[].isHighlighted] - Whether this turn is highlighted\n * @param {string} [props.turns[].highlightColor] - Color for the right highlight rail\n * @param {Array} [props.turns[].toolBadges] - Tool badge data [{name, success, pending}]\n * @param {string} [props.audioUrl] - Audio URL for segment playback\n * @param {number} [props.activeTurnIndex=-1] - Index of the externally active turn\n * @param {boolean} [props.autoScrollActiveTurn=false] - Auto-scroll to active turn\n * @param {boolean} [props.isExternalPlaying=false] - External playback state\n * @param {Function} [props.onTurnPlayPause] - External playback handler (turn, index) => void\n */\nexport default function TranscriptCard({\n turns,\n audioUrl,\n activeTurnIndex = -1,\n autoScrollActiveTurn = false,\n isExternalPlaying = false,\n onTurnPlayPause,\n}) {\n const [playingSegment, setPlayingSegment] = useState(null);\n const [isPlaying, setIsPlaying] = useState(false);\n const audioRef = useRef(null);\n const endTimeListenerRef = useRef(null);\n const turnRefs = useRef([]);\n const containerRef = useRef(null);\n const lastAutoScrolledIndexRef = useRef(-1);\n const useExternalPlaybackControl = typeof onTurnPlayPause === \"function\";\n const hasExternalPlaybackState = isExternalPlaying !== undefined;\n\n // Initialize audio element\n useEffect(() => {\n if (audioUrl) {\n audioRef.current = new Audio(audioUrl);\n audioRef.current.preload = \"auto\";\n return () => {\n if (audioRef.current) {\n audioRef.current.pause();\n audioRef.current = null;\n }\n };\n }\n }, [audioUrl]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (audioRef.current) {\n audioRef.current.pause();\n if (endTimeListenerRef.current) {\n audioRef.current.removeEventListener(\"timeupdate\", endTimeListenerRef.current);\n }\n }\n };\n }, []);\n\n // Auto-scroll to active turn\n useEffect(() => {\n if (!autoScrollActiveTurn || activeTurnIndex < 0) return;\n const container = containerRef.current;\n const activeNode = turnRefs.current[activeTurnIndex];\n if (!activeNode || !container) return;\n\n const containerRect = container.getBoundingClientRect();\n const activeRect = activeNode.getBoundingClientRect();\n const topPadding = 12;\n const isFullyVisible =\n activeRect.top >= containerRect.top + topPadding &&\n activeRect.bottom <= containerRect.bottom - 8;\n const didScrollForThisTurn = lastAutoScrolledIndexRef.current === activeTurnIndex;\n\n if (!didScrollForThisTurn || !isFullyVisible) {\n const activeTopInContainer = activeRect.top - containerRect.top + container.scrollTop;\n container.scrollTop = Math.max(activeTopInContainer - topPadding, 0);\n }\n lastAutoScrolledIndexRef.current = activeTurnIndex;\n }, [activeTurnIndex, autoScrollActiveTurn]);\n\n const handlePlayPause = (timeRange, index) => {\n if (useExternalPlaybackControl) {\n onTurnPlayPause(turns[index], index);\n return;\n }\n\n if (playingSegment === index && isPlaying) {\n // Pause current segment\n if (audioRef.current) {\n audioRef.current.pause();\n if (endTimeListenerRef.current) {\n audioRef.current.removeEventListener(\"timeupdate\", endTimeListenerRef.current);\n endTimeListenerRef.current = null;\n }\n }\n setIsPlaying(false);\n } else {\n // Start/switch segment\n const previousSegment = playingSegment;\n setPlayingSegment(index);\n\n if (audioUrl && audioRef.current) {\n const { start, end } = parseTimeRange(timeRange);\n\n if (previousSegment !== null && previousSegment !== index) {\n audioRef.current.pause();\n if (endTimeListenerRef.current) {\n audioRef.current.removeEventListener(\"timeupdate\", endTimeListenerRef.current);\n endTimeListenerRef.current = null;\n }\n }\n\n const playSegment = () => {\n if (!audioRef.current) return;\n audioRef.current.currentTime = start;\n\n if (end) {\n const checkEndTime = () => {\n if (audioRef.current && audioRef.current.currentTime >= end) {\n audioRef.current.pause();\n setIsPlaying(false);\n setPlayingSegment(null);\n if (endTimeListenerRef.current) {\n audioRef.current.removeEventListener(\"timeupdate\", endTimeListenerRef.current);\n endTimeListenerRef.current = null;\n }\n }\n };\n endTimeListenerRef.current = checkEndTime;\n audioRef.current.addEventListener(\"timeupdate\", checkEndTime);\n }\n\n audioRef.current.play()\n .then(() => setIsPlaying(true))\n .catch((err) => {\n // Ignore AbortError which occurs when play() is interrupted by pause()\n if (err && err.name === \"AbortError\") {\n return;\n }\n setIsPlaying(false);\n setPlayingSegment(null);\n });\n };\n\n if (audioRef.current.readyState >= 2) {\n playSegment();\n } else {\n audioRef.current.addEventListener(\"loadedmetadata\", playSegment, { once: true });\n audioRef.current.load();\n }\n } else {\n setIsPlaying(true);\n }\n }\n };\n\n return (\n <div\n ref={containerRef}\n className=\"custom-thin-scrollbar-library\"\n style={{\n maxHeight: 560,\n overflowY: \"auto\",\n scrollBehavior: \"smooth\",\n border: \"1px solid var(--border, rgba(52,58,64,0.12))\",\n // borderRadius: \"var(--radius-lg, 12px)\",\n borderRadius: \"12px 0px 0px 12px\",\n background: \"var(--paper-elevated, rgba(255,255,255,0.82))\",\n padding: 16,\n }}\n >\n {/* Section label */}\n <div\n style={{\n fontSize: \"var(--text-xs-plus, 10.5px)\",\n fontWeight: 650,\n textTransform: \"uppercase\",\n letterSpacing: \"var(--tracking-label, 0.16em)\",\n color: \"var(--text-faint, rgba(30,33,37,0.36))\",\n marginBottom: 12,\n }}\n >\n Transcript\n </div>\n\n {/* Turns */}\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 8 }}>\n {turns.map((turn, index) => {\n const isTurnPlaying = (useExternalPlaybackControl || hasExternalPlaybackState)\n ? Boolean(isExternalPlaying) && activeTurnIndex === index\n : playingSegment === index && isPlaying;\n const isTurnHighlighted = Boolean(turn.isHighlighted) || isTurnPlaying;\n const role = mapActorTypeToRole(turn.actorType);\n\n return (\n <div\n key={index}\n ref={(el) => { turnRefs.current[index] = el; }}\n >\n <ConversationTurn\n role={role}\n text={turn.text}\n actorLabel={turn.actor}\n actorRailColor={turn.actorColor}\n timeRange={turn.timeRange}\n isHighlighted={isTurnHighlighted}\n highlightRailColor={isTurnPlaying \n ? (turn.highlightColor || (role === 'agent' ? 'var(--rail-outcome)' : 'var(--rail-discovery)'))\n : turn.highlightColor}\n toolBadges={turn.toolBadges}\n observations={turn.observations}\n onObservationClick={turn.onObservationClick}\n >\n {/* Play/pause button — rendered inline left of time range */}\n {turn.timeRange ? (\n <button\n onClick={() => handlePlayPause(turn.timeRange, index)}\n style={{\n width: 24,\n height: 24,\n borderRadius: \"50%\",\n border: \"1px solid var(--border, rgba(52,58,64,0.12))\",\n background: isTurnPlaying\n ? \"var(--rail-discovery, #5E88B0)\"\n : \"var(--paper, rgba(255,255,255,0.78))\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: \"pointer\",\n padding: 0,\n transition: \"all 0.15s\",\n }}\n aria-label={isTurnPlaying ? `Pause segment ${turn.timeRange}` : `Play segment ${turn.timeRange}`}\n >\n {isTurnPlaying ? (\n <Pause\n style={{ width: 12, height: 12, color: \"var(--paper, #fff)\", fill: \"var(--paper, #fff)\" }}\n strokeWidth={0}\n />\n ) : (\n <Play\n style={{ width: 12, height: 12, color: \"var(--text-muted, rgba(30,33,37,0.56))\", fill: \"var(--text-muted, rgba(30,33,37,0.56))\", marginLeft: 1 }}\n strokeWidth={0}\n />\n )}\n </button>\n ) : null}\n </ConversationTurn>\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport { Play, Pause, RotateCcw, RotateCw } from \"lucide-react\";\n\nexport default function Timeline({\n segments = [],\n durationSeconds = 0,\n actorRows = [],\n currentTimeSeconds = 0,\n onSeek,\n showControls = false,\n hasRecording = false,\n timelinePlaying = false,\n playbackRate = 1,\n speedOptions = [1, 1.25, 1.5, 2],\n onTogglePlay,\n onSeekBack,\n onSeekForward,\n onSetPlaybackRate,\n totalDurationLabel,\n}) {\n const [activeControl, setActiveControl] = useState(null);\n\n useEffect(() => {\n if (!activeControl) return;\n const timer = setTimeout(() => setActiveControl(null), 220);\n return () => clearTimeout(timer);\n }, [activeControl]);\n\n const timelineDuration = Math.max(\n Number(durationSeconds) || 0,\n ...segments.map((segment) => Number(segment.endTime) || 0),\n 1\n );\n const clampedCurrent = Math.max(0, Math.min(Number(currentTimeSeconds) || 0, timelineDuration));\n const playheadPercent = timelineDuration > 0 ? (clampedCurrent / timelineDuration) * 100 : 0;\n const playheadLeft = `calc(${playheadPercent}% + ${(5 * (1 - playheadPercent / 100)).toFixed(4)}rem)`;\n\n const formatTime = (seconds) => {\n const mins = Math.floor(seconds / 60);\n const secs = Math.floor(seconds % 60);\n return `${mins.toString().padStart(2, \"0\")}:${secs.toString().padStart(2, \"0\")}`;\n };\n\n const rows = useMemo(() => {\n if (actorRows.length) {\n return actorRows.map((actor) => ({\n ...actor,\n segments: segments.filter((segment) => segment.actor === actor.key),\n }));\n }\n const actors = Array.from(new Set(segments.map((segment) => segment.actor)));\n const actorColors = new Map(segments.map((segment) => [segment.actor, segment.actorColor]));\n return actors.map((actor) => ({\n key: actor,\n label: actor,\n color: actorColors.get(actor) || \"#6B7C93\",\n segments: segments.filter((segment) => segment.actor === actor),\n }));\n }, [actorRows, segments]);\n\n const timeMarkers = [];\n const interval = 120;\n for (let marker = 0; marker <= timelineDuration; marker += interval) {\n timeMarkers.push(marker);\n }\n if (!timeMarkers.length || timeMarkers[timeMarkers.length - 1] < timelineDuration) {\n timeMarkers.push(timelineDuration);\n }\n\n const handleSeekClick = (event) => {\n if (!onSeek) return;\n const rect = event.currentTarget.getBoundingClientRect();\n if (!rect.width) return;\n const ratio = Math.max(0, Math.min((event.clientX - rect.left) / rect.width, 1));\n onSeek(ratio * timelineDuration);\n };\n\n return (\n <div style={{\n padding: \"10px 0\",\n }}>\n {showControls && (\n <div style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", marginBottom: 8 }}>\n <div style={{\n fontSize: \"var(--text-sm, 11px)\",\n fontFamily: \"var(--font-mono, monospace)\",\n color: \"var(--text-muted, rgba(30,33,37,0.56))\",\n fontWeight: 500,\n minWidth: 70,\n }}>\n {formatTime(clampedCurrent)} <span style={{ color: \"var(--text-faint, rgba(30,33,37,0.36))\" }}>/ {formatTime(timelineDuration)}</span>\n </div>\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 6 }}>\n <button\n type=\"button\"\n onClick={() => { setActiveControl(\"rewind\"); onSeekBack?.(); }}\n disabled={!hasRecording}\n title=\"Rewind 15s\"\n style={{\n display: \"inline-flex\", alignItems: \"center\", justifyContent: \"center\",\n width: 28, height: 28, borderRadius: \"50%\",\n border: `1px solid ${activeControl === \"rewind\" ? \"var(--rail-discovery, #5E88B0)\" : \"var(--border, rgba(52,58,64,0.12))\"}`,\n background: \"var(--paper, rgba(255,255,255,0.78))\", cursor: \"pointer\", padding: 0,\n }}\n >\n <RotateCcw size={13} stroke=\"var(--rail-discovery, #5E88B0)\" />\n </button>\n\n <button\n type=\"button\"\n onClick={onTogglePlay}\n disabled={!hasRecording}\n style={{\n display: \"inline-flex\", alignItems: \"center\", justifyContent: \"center\",\n width: 32, height: 32, borderRadius: \"50%\",\n background: \"var(--rail-discovery, #5E88B0)\", color: \"#fff\",\n border: \"none\", cursor: \"pointer\", padding: 0,\n }}\n aria-label={timelinePlaying ? \"Pause recording\" : \"Play recording\"}\n >\n {timelinePlaying ? <Pause size={14} /> : <Play size={14} style={{ marginLeft: 1 }} />}\n </button>\n\n <button\n type=\"button\"\n onClick={() => { setActiveControl(\"forward\"); onSeekForward?.(); }}\n disabled={!hasRecording}\n title=\"Forward 15s\"\n style={{\n display: \"inline-flex\", alignItems: \"center\", justifyContent: \"center\",\n width: 28, height: 28, borderRadius: \"50%\",\n border: `1px solid ${activeControl === \"forward\" ? \"var(--rail-discovery, #5E88B0)\" : \"var(--border, rgba(52,58,64,0.12))\"}`,\n background: \"var(--paper, rgba(255,255,255,0.78))\", cursor: \"pointer\", padding: 0,\n }}\n >\n <RotateCw size={13} stroke=\"var(--rail-discovery, #5E88B0)\" />\n </button>\n\n <div style={{ display: \"inline-flex\", alignItems: \"center\", gap: 4, borderRadius: 999, border: \"1px solid var(--border, rgba(52,58,64,0.12))\", padding: \"2px 3px\", background: \"var(--paper, rgba(255,255,255,0.78))\", marginLeft: 4 }}>\n {speedOptions.map((speed) => {\n const isActive = playbackRate === speed;\n return (\n <button\n key={speed}\n type=\"button\"\n onClick={() => onSetPlaybackRate?.(speed)}\n disabled={!hasRecording}\n title={`Speed: ${speed}x`}\n style={{\n display: \"inline-flex\", alignItems: \"center\", justifyContent: \"center\",\n height: 24, minWidth: 38, padding: \"0 6px\", borderRadius: 999,\n border: `1px solid ${isActive ? \"var(--rail-discovery, #5E88B0)\" : \"transparent\"}`,\n background: isActive ? \"var(--rail-discovery, #5E88B0)\" : \"transparent\",\n color: isActive ? \"#fff\" : \"var(--text-muted, rgba(30,33,37,0.56))\",\n fontSize: \"var(--text-xs, 10px)\", fontWeight: 600, cursor: \"pointer\",\n }}\n >\n {speed === 1.5 ? \"1.50x\" : `${speed}x`}\n </button>\n );\n })}\n </div>\n </div>\n </div>\n )}\n\n <div style={{\n background: \"var(--paper, rgba(255,255,255,0.78))\",\n border: \"1px solid var(--border, rgba(52,58,64,0.12))\",\n borderRadius: 10,\n padding: \"12px 16px 10px\",\n }}>\n <div style={{ position: \"relative\" }}>\n {/* Time markers row */}\n <div style={{ display: \"flex\", alignItems: \"center\", marginBottom: 6, height: 16 }}>\n <div style={{ width: \"5rem\", flexShrink: 0 }} />\n <div style={{ position: \"relative\", flex: 1 }}>\n {timeMarkers.map((time) => {\n const percentage = timelineDuration > 0 ? (time / timelineDuration) * 100 : 0;\n return (\n <div\n key={time}\n style={{\n position: \"absolute\",\n fontSize: \"var(--text-xs, 10px)\",\n color: \"var(--text-faint, rgba(30,33,37,0.36))\",\n left: `${percentage}%`,\n transform: \"translateX(-50%)\",\n fontFamily: \"var(--font-mono, monospace)\",\n whiteSpace: \"nowrap\",\n }}\n >\n {formatTime(time)}\n </div>\n );\n })}\n </div>\n </div>\n\n {/* Vertical gridlines */}\n <div\n style={{\n position: \"absolute\",\n pointerEvents: \"none\",\n top: 0,\n bottom: 0,\n left: \"5rem\",\n width: \"calc(100% - 5rem)\",\n zIndex: 20,\n }}\n >\n {timeMarkers.map((time) => {\n const percentage = timelineDuration > 0 ? (time / timelineDuration) * 100 : 0;\n return (\n <div\n key={time}\n style={{\n position: \"absolute\",\n top: 0,\n bottom: 0,\n left: `${percentage}%`,\n borderLeft: \"1px dashed var(--border, rgba(52,58,64,0.12))\",\n transform: \"translateX(-1px)\",\n }}\n />\n );\n })}\n </div>\n\n {/* Swim lanes */}\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 10, marginTop: 8 }}>\n {rows.map((row) => {\n const isSystem = row.key === \"system\" || row.label === \"System\";\n return (\n <div key={row.key} style={{ display: \"flex\", alignItems: \"center\" }}>\n <div\n style={{\n width: \"5rem\",\n flexShrink: 0,\n fontSize: \"var(--text-sm, 11px)\",\n fontWeight: 600,\n color: \"var(--text-muted, rgba(30,33,37,0.56))\",\n fontFamily: \"var(--font-sans, system-ui, sans-serif)\",\n paddingRight: 8,\n }}\n >\n {row.label}\n </div>\n\n <div\n style={{\n position: \"relative\",\n borderRadius: 4,\n flex: 1,\n height: 18,\n backgroundColor: \"var(--paper-secondary, rgba(244,241,230,0.6))\",\n border: \"1px solid var(--border-subtle, rgba(52,58,64,0.08))\",\n }}\n >\n {row.segments.map((segment, idx) => {\n let leftPercent = timelineDuration > 0 ? (segment.startTime / timelineDuration) * 100 : 0;\n let widthPercent =\n timelineDuration > 0\n ? ((segment.endTime - segment.startTime) / timelineDuration) * 100\n : 0;\n leftPercent = Math.max(0, Math.min(100, leftPercent));\n const rightPercent = leftPercent + widthPercent;\n if (rightPercent > 100) widthPercent = 100 - leftPercent;\n widthPercent = Math.max(0, widthPercent);\n const segmentDuration = segment.endTime - segment.startTime;\n\n if (isSystem && segmentDuration <= 5) {\n return (\n <div\n key={idx}\n style={{\n position: \"absolute\",\n cursor: \"pointer\",\n left: `${leftPercent}%`,\n top: \"50%\",\n transform: \"translateY(-50%)\",\n width: 10,\n height: 10,\n borderRadius: \"50%\",\n backgroundColor: row.color,\n opacity: 0.85,\n }}\n title={`${row.label}: ${formatTime(segment.startTime)}-${formatTime(segment.endTime)}`}\n />\n );\n }\n\n return (\n <div\n key={idx}\n style={{\n position: \"absolute\",\n top: 0,\n bottom: 0,\n left: `${leftPercent}%`,\n width: `${Math.max(widthPercent, 0.7)}%`,\n maxWidth: `${100 - leftPercent}%`,\n backgroundColor: row.color,\n opacity: 0.85,\n borderRadius: 2,\n cursor: \"pointer\",\n transition: \"opacity 0.15s\",\n }}\n title={`${row.label}: ${formatTime(segment.startTime)}-${formatTime(segment.endTime)}`}\n />\n );\n })}\n </div>\n </div>\n );\n })}\n </div>\n\n {/* Playhead */}\n <div\n style={{\n pointerEvents: \"none\",\n position: \"absolute\",\n top: 0,\n bottom: 0,\n width: 2,\n borderRadius: 1,\n backgroundColor: \"var(--rail-discovery, #5E88B0)\",\n opacity: 0.55,\n boxShadow: \"0 0 0 1px rgba(94,136,176,0.10)\",\n left: playheadLeft,\n transform: \"translateX(-50%)\",\n }}\n />\n\n {/* Seek overlay */}\n {onSeek ? (\n <button\n type=\"button\"\n onClick={handleSeekClick}\n style={{\n position: \"absolute\",\n cursor: \"pointer\",\n background: \"transparent\",\n border: \"none\",\n padding: 0,\n margin: 0,\n appearance: \"none\",\n top: 0,\n bottom: 0,\n left: \"5rem\",\n width: \"calc(100% - 5rem)\",\n zIndex: 25,\n }}\n title=\"Click timeline to play from that point\"\n aria-label=\"Click timeline to play from that point\"\n />\n ) : null}\n </div>\n </div>\n </div>\n );\n}\n"],"names":["ACTOR_DEFAULTS","KEYFRAMES_ID","ensureKeyframes","style","ConversationTurn","role","text","actorLabel","actorRailColor","actionKicker","toolBadges","streaming","meta","timeRange","isHighlighted","highlightRailColor","observations","onObservationClick","children","useEffect","actor","label","railColor","highlighted","jsx","jsxs","t","i","isPending","isError","obs","parseTimeRange","start","end","time","minutes","seconds","mapActorTypeToRole","actorType","TranscriptCard","turns","audioUrl","activeTurnIndex","autoScrollActiveTurn","isExternalPlaying","onTurnPlayPause","playingSegment","setPlayingSegment","useState","isPlaying","setIsPlaying","audioRef","useRef","endTimeListenerRef","turnRefs","containerRef","lastAutoScrolledIndexRef","useExternalPlaybackControl","hasExternalPlaybackState","container","activeNode","containerRect","activeRect","topPadding","isFullyVisible","activeTopInContainer","handlePlayPause","index","previousSegment","playSegment","checkEndTime","err","turn","isTurnPlaying","isTurnHighlighted","el","Pause","Play","Timeline","segments","durationSeconds","actorRows","currentTimeSeconds","onSeek","showControls","hasRecording","timelinePlaying","playbackRate","speedOptions","onTogglePlay","onSeekBack","onSeekForward","onSetPlaybackRate","totalDurationLabel","activeControl","setActiveControl","timer","timelineDuration","segment","clampedCurrent","playheadPercent","playheadLeft","formatTime","mins","secs","rows","useMemo","actors","actorColors","timeMarkers","interval","marker","handleSeekClick","event","rect","ratio","RotateCcw","RotateCw","speed","isActive","percentage","row","isSystem","idx","leftPercent","widthPercent","segmentDuration"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Timeline.es.js","sources":["../src/components/media/Timeline.jsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport { Play, Pause, RotateCcw, RotateCw } from \"lucide-react\";\n\nexport default function Timeline({\n segments = [],\n durationSeconds = 0,\n actorRows = [],\n currentTimeSeconds = 0,\n onSeek,\n showControls = false,\n hasRecording = false,\n timelinePlaying = false,\n playbackRate = 1,\n speedOptions = [1, 1.25, 1.5, 2],\n onTogglePlay,\n onSeekBack,\n onSeekForward,\n onSetPlaybackRate,\n totalDurationLabel,\n}) {\n const [activeControl, setActiveControl] = useState(null);\n\n useEffect(() => {\n if (!activeControl) return;\n const timer = setTimeout(() => setActiveControl(null), 220);\n return () => clearTimeout(timer);\n }, [activeControl]);\n\n const timelineDuration = Math.max(\n Number(durationSeconds) || 0,\n ...segments.map((segment) => Number(segment.endTime) || 0),\n 1\n );\n const clampedCurrent = Math.max(0, Math.min(Number(currentTimeSeconds) || 0, timelineDuration));\n const playheadPercent = timelineDuration > 0 ? (clampedCurrent / timelineDuration) * 100 : 0;\n const playheadLeft = `calc(${playheadPercent}% + ${(5 * (1 - playheadPercent / 100)).toFixed(4)}rem)`;\n\n const formatTime = (seconds) => {\n const mins = Math.floor(seconds / 60);\n const secs = Math.floor(seconds % 60);\n return `${mins.toString().padStart(2, \"0\")}:${secs.toString().padStart(2, \"0\")}`;\n };\n\n const rows = useMemo(() => {\n if (actorRows.length) {\n return actorRows.map((actor) => ({\n ...actor,\n segments: segments.filter((segment) => segment.actor === actor.key),\n }));\n }\n const actors = Array.from(new Set(segments.map((segment) => segment.actor)));\n const actorColors = new Map(segments.map((segment) => [segment.actor, segment.actorColor]));\n return actors.map((actor) => ({\n key: actor,\n label: actor,\n color: actorColors.get(actor) || \"#6B7C93\",\n segments: segments.filter((segment) => segment.actor === actor),\n }));\n }, [actorRows, segments]);\n\n const timeMarkers = [];\n const interval = 120;\n for (let marker = 0; marker <= timelineDuration; marker += interval) {\n timeMarkers.push(marker);\n }\n if (!timeMarkers.length || timeMarkers[timeMarkers.length - 1] < timelineDuration) {\n timeMarkers.push(timelineDuration);\n }\n\n const handleSeekClick = (event) => {\n if (!onSeek) return;\n const rect = event.currentTarget.getBoundingClientRect();\n if (!rect.width) return;\n const ratio = Math.max(0, Math.min((event.clientX - rect.left) / rect.width, 1));\n onSeek(ratio * timelineDuration);\n };\n\n return (\n <div style={{\n padding: \"10px 0\",\n }}>\n {showControls && (\n <div style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", marginBottom: 8 }}>\n <div style={{\n fontSize: \"var(--text-sm, 11px)\",\n fontFamily: \"var(--font-mono, monospace)\",\n color: \"var(--text-muted, rgba(30,33,37,0.56))\",\n fontWeight: 500,\n minWidth: 70,\n }}>\n {formatTime(clampedCurrent)} <span style={{ color: \"var(--text-faint, rgba(30,33,37,0.36))\" }}>/ {formatTime(timelineDuration)}</span>\n </div>\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 6 }}>\n <button\n type=\"button\"\n onClick={() => { setActiveControl(\"rewind\"); onSeekBack?.(); }}\n disabled={!hasRecording}\n title=\"Rewind 15s\"\n style={{\n display: \"inline-flex\", alignItems: \"center\", justifyContent: \"center\",\n width: 28, height: 28, borderRadius: \"50%\",\n border: `1px solid ${activeControl === \"rewind\" ? \"var(--rail-discovery, #5E88B0)\" : \"var(--border, rgba(52,58,64,0.12))\"}`,\n background: \"var(--paper, rgba(255,255,255,0.78))\", cursor: \"pointer\", padding: 0,\n }}\n >\n <RotateCcw size={13} stroke=\"var(--rail-discovery, #5E88B0)\" />\n </button>\n\n <button\n type=\"button\"\n onClick={onTogglePlay}\n disabled={!hasRecording}\n style={{\n display: \"inline-flex\", alignItems: \"center\", justifyContent: \"center\",\n width: 32, height: 32, borderRadius: \"50%\",\n background: \"var(--rail-discovery, #5E88B0)\", color: \"#fff\",\n border: \"none\", cursor: \"pointer\", padding: 0,\n }}\n aria-label={timelinePlaying ? \"Pause recording\" : \"Play recording\"}\n >\n {timelinePlaying ? <Pause size={14} /> : <Play size={14} style={{ marginLeft: 1 }} />}\n </button>\n\n <button\n type=\"button\"\n onClick={() => { setActiveControl(\"forward\"); onSeekForward?.(); }}\n disabled={!hasRecording}\n title=\"Forward 15s\"\n style={{\n display: \"inline-flex\", alignItems: \"center\", justifyContent: \"center\",\n width: 28, height: 28, borderRadius: \"50%\",\n border: `1px solid ${activeControl === \"forward\" ? \"var(--rail-discovery, #5E88B0)\" : \"var(--border, rgba(52,58,64,0.12))\"}`,\n background: \"var(--paper, rgba(255,255,255,0.78))\", cursor: \"pointer\", padding: 0,\n }}\n >\n <RotateCw size={13} stroke=\"var(--rail-discovery, #5E88B0)\" />\n </button>\n\n <div style={{ display: \"inline-flex\", alignItems: \"center\", gap: 4, borderRadius: 999, border: \"1px solid var(--border, rgba(52,58,64,0.12))\", padding: \"2px 3px\", background: \"var(--paper, rgba(255,255,255,0.78))\", marginLeft: 4 }}>\n {speedOptions.map((speed) => {\n const isActive = playbackRate === speed;\n return (\n <button\n key={speed}\n type=\"button\"\n onClick={() => onSetPlaybackRate?.(speed)}\n disabled={!hasRecording}\n title={`Speed: ${speed}x`}\n style={{\n display: \"inline-flex\", alignItems: \"center\", justifyContent: \"center\",\n height: 24, minWidth: 38, padding: \"0 6px\", borderRadius: 999,\n border: `1px solid ${isActive ? \"var(--rail-discovery, #5E88B0)\" : \"transparent\"}`,\n background: isActive ? \"var(--rail-discovery, #5E88B0)\" : \"transparent\",\n color: isActive ? \"#fff\" : \"var(--text-muted, rgba(30,33,37,0.56))\",\n fontSize: \"var(--text-xs, 10px)\", fontWeight: 600, cursor: \"pointer\",\n }}\n >\n {speed === 1.5 ? \"1.50x\" : `${speed}x`}\n </button>\n );\n })}\n </div>\n </div>\n </div>\n )}\n\n <div style={{\n background: \"var(--paper, rgba(255,255,255,0.78))\",\n border: \"1px solid var(--border, rgba(52,58,64,0.12))\",\n borderRadius: 10,\n padding: \"12px 16px 10px\",\n }}>\n <div style={{ position: \"relative\" }}>\n {/* Time markers row */}\n <div style={{ display: \"flex\", alignItems: \"center\", marginBottom: 6, height: 16 }}>\n <div style={{ width: \"5rem\", flexShrink: 0 }} />\n <div style={{ position: \"relative\", flex: 1 }}>\n {timeMarkers.map((time) => {\n const percentage = timelineDuration > 0 ? (time / timelineDuration) * 100 : 0;\n return (\n <div\n key={time}\n style={{\n position: \"absolute\",\n fontSize: \"var(--text-xs, 10px)\",\n color: \"var(--text-faint, rgba(30,33,37,0.36))\",\n left: `${percentage}%`,\n transform: \"translateX(-50%)\",\n fontFamily: \"var(--font-mono, monospace)\",\n whiteSpace: \"nowrap\",\n }}\n >\n {formatTime(time)}\n </div>\n );\n })}\n </div>\n </div>\n\n {/* Vertical gridlines */}\n <div\n style={{\n position: \"absolute\",\n pointerEvents: \"none\",\n top: 0,\n bottom: 0,\n left: \"5rem\",\n width: \"calc(100% - 5rem)\",\n zIndex: 20,\n }}\n >\n {timeMarkers.map((time) => {\n const percentage = timelineDuration > 0 ? (time / timelineDuration) * 100 : 0;\n return (\n <div\n key={time}\n style={{\n position: \"absolute\",\n top: 0,\n bottom: 0,\n left: `${percentage}%`,\n borderLeft: \"1px dashed var(--border, rgba(52,58,64,0.12))\",\n transform: \"translateX(-1px)\",\n }}\n />\n );\n })}\n </div>\n\n {/* Swim lanes */}\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 10, marginTop: 8 }}>\n {rows.map((row) => {\n const isSystem = row.key === \"system\" || row.label === \"System\";\n return (\n <div key={row.key} style={{ display: \"flex\", alignItems: \"center\" }}>\n <div\n style={{\n width: \"5rem\",\n flexShrink: 0,\n fontSize: \"var(--text-sm, 11px)\",\n fontWeight: 600,\n color: \"var(--text-muted, rgba(30,33,37,0.56))\",\n fontFamily: \"var(--font-sans, system-ui, sans-serif)\",\n paddingRight: 8,\n }}\n >\n {row.label}\n </div>\n\n <div\n style={{\n position: \"relative\",\n borderRadius: 4,\n flex: 1,\n height: 18,\n backgroundColor: \"var(--paper-secondary, rgba(244,241,230,0.6))\",\n border: \"1px solid var(--border-subtle, rgba(52,58,64,0.08))\",\n }}\n >\n {row.segments.map((segment, idx) => {\n let leftPercent = timelineDuration > 0 ? (segment.startTime / timelineDuration) * 100 : 0;\n let widthPercent =\n timelineDuration > 0\n ? ((segment.endTime - segment.startTime) / timelineDuration) * 100\n : 0;\n leftPercent = Math.max(0, Math.min(100, leftPercent));\n const rightPercent = leftPercent + widthPercent;\n if (rightPercent > 100) widthPercent = 100 - leftPercent;\n widthPercent = Math.max(0, widthPercent);\n const segmentDuration = segment.endTime - segment.startTime;\n\n if (isSystem && segmentDuration <= 5) {\n return (\n <div\n key={idx}\n style={{\n position: \"absolute\",\n cursor: \"pointer\",\n left: `${leftPercent}%`,\n top: \"50%\",\n transform: \"translateY(-50%)\",\n width: 10,\n height: 10,\n borderRadius: \"50%\",\n backgroundColor: row.color,\n opacity: 0.85,\n }}\n title={`${row.label}: ${formatTime(segment.startTime)}-${formatTime(segment.endTime)}`}\n />\n );\n }\n\n return (\n <div\n key={idx}\n style={{\n position: \"absolute\",\n top: 0,\n bottom: 0,\n left: `${leftPercent}%`,\n width: `${Math.max(widthPercent, 0.7)}%`,\n maxWidth: `${100 - leftPercent}%`,\n backgroundColor: row.color,\n opacity: 0.85,\n borderRadius: 2,\n cursor: \"pointer\",\n transition: \"opacity 0.15s\",\n }}\n title={`${row.label}: ${formatTime(segment.startTime)}-${formatTime(segment.endTime)}`}\n />\n );\n })}\n </div>\n </div>\n );\n })}\n </div>\n\n {/* Playhead */}\n <div\n style={{\n pointerEvents: \"none\",\n position: \"absolute\",\n top: 0,\n bottom: 0,\n width: 2,\n borderRadius: 1,\n backgroundColor: \"var(--rail-discovery, #5E88B0)\",\n opacity: 0.55,\n boxShadow: \"0 0 0 1px rgba(94,136,176,0.10)\",\n left: playheadLeft,\n transform: \"translateX(-50%)\",\n }}\n />\n\n {/* Seek overlay */}\n {onSeek ? (\n <button\n type=\"button\"\n onClick={handleSeekClick}\n style={{\n position: \"absolute\",\n cursor: \"pointer\",\n background: \"transparent\",\n border: \"none\",\n padding: 0,\n margin: 0,\n appearance: \"none\",\n top: 0,\n bottom: 0,\n left: \"5rem\",\n width: \"calc(100% - 5rem)\",\n zIndex: 25,\n }}\n title=\"Click timeline to play from that point\"\n aria-label=\"Click timeline to play from that point\"\n />\n ) : null}\n </div>\n </div>\n </div>\n );\n}\n"],"names":["Timeline","segments","durationSeconds","actorRows","currentTimeSeconds","onSeek","showControls","hasRecording","timelinePlaying","playbackRate","speedOptions","onTogglePlay","onSeekBack","onSeekForward","onSetPlaybackRate","totalDurationLabel","activeControl","setActiveControl","useState","useEffect","timer","timelineDuration","segment","clampedCurrent","playheadPercent","playheadLeft","formatTime","seconds","mins","secs","rows","useMemo","actor","actors","actorColors","timeMarkers","interval","marker","handleSeekClick","event","rect","ratio","jsxs","jsx","RotateCcw","Pause","Play","RotateCw","speed","isActive","time","percentage","row","isSystem","idx","leftPercent","widthPercent","segmentDuration"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";const r=require("react/jsx-runtime"),l=require("react"),T=require("lucide-react"),w={customer:{label:"Customer",railColor:"var(--rail-discovery)",cardBg:"var(--card-customer)",cardBgHighlight:"rgba(94, 136, 176, 0.12)",borderColor:"var(--border-subtle)"},agent:{label:"Agent",railColor:"var(--rail-outcome)",cardBg:"var(--card-agent)",cardBgHighlight:"rgba(107, 124, 147, 0.10)",borderColor:"var(--border-subtle)"},assistant:{label:"AI Assistant",railColor:"var(--rail-purple)",cardBg:"var(--card-assistant)",cardBgHighlight:"rgba(155, 122, 168, 0.10)",borderColor:"var(--border-subtle)"},system:{label:"System",railColor:"var(--text-faint)",cardBg:"transparent",cardBgHighlight:"transparent",borderColor:"transparent"}},E="conversation-turn-keyframes";function L(){if(typeof document>"u"||document.getElementById(E))return;const i=document.createElement("style");i.id=E,i.textContent=`
|
|
2
|
+
@keyframes turn-playing-pulse {
|
|
3
|
+
0%, 100% { opacity: 0.4; }
|
|
4
|
+
50% { opacity: 0.9; }
|
|
5
|
+
}
|
|
6
|
+
`,document.head.appendChild(i)}function A({role:i="agent",text:s,actorLabel:c,actorRailColor:h,actionKicker:x,toolBadges:f,streaming:d=!1,meta:v,timeRange:b,isHighlighted:m=!1,highlightRailColor:t,observations:n,onObservationClick:y,children:k}){l.useEffect(()=>{L()},[]);const p=w[i]||w.agent,j=c||p.label,C=h||p.railColor,B=m||d;return i==="system"?r.jsx("div",{style:{textAlign:"center",padding:"6px 0",flexShrink:0,fontSize:"var(--text-sm, 11px)",color:"var(--text-faint, rgba(30,33,37,0.36))",fontWeight:500,letterSpacing:"0.02em"},children:s}):r.jsxs("div",{style:{position:"relative",padding:"10px 14px 10px 18px",borderRadius:10,overflow:"hidden",flexShrink:0,background:B?p.cardBgHighlight:p.cardBg,border:`1px solid ${d?C:p.borderColor}`,boxShadow:d?`0 0 8px ${p.cardBgHighlight}`:"none",transition:"background 0.2s, border-color 0.2s, box-shadow 0.2s"},children:[r.jsx("div",{style:{position:"absolute",left:0,top:0,bottom:0,width:"var(--rail-width-thin, 4px)",backgroundColor:C,borderRadius:"10px 0 0 10px"}}),r.jsxs("div",{style:{display:"flex",alignItems:"flex-start",justifyContent:"space-between",gap:8,marginBottom:4},children:[r.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:2},children:[x?r.jsx("div",{style:{fontSize:"var(--text-xs-plus, 10.5px)",fontWeight:650,textTransform:"uppercase",letterSpacing:"var(--tracking-label, 0.16em)",color:C},children:x}):null,r.jsx("div",{style:{fontSize:"var(--text-xs-plus, 10.5px)",fontWeight:650,textTransform:"uppercase",letterSpacing:"var(--tracking-label, 0.16em)",color:"var(--text-faint, rgba(30,33,37,0.36))"},children:j})]}),f&&f.length>0?r.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:4,flexShrink:0,justifyContent:"flex-end"},children:f.map((e,a)=>{const o=e.pending,g=!o&&e.success===!1,u=o?"var(--rail-discovery, #5E88B0)":g?"var(--rail-compliance, #C98A5A)":"var(--text-xfaint, rgba(30,33,37,0.28))";return r.jsxs("span",{style:{display:"inline-flex",alignItems:"center",gap:5,fontSize:"var(--text-xs, 10px)",padding:"2px 8px 2px 6px",borderRadius:999,background:"var(--paper, rgba(255,255,255,0.78))",border:"1px solid var(--border-subtle, rgba(52,58,64,0.08))",color:"var(--text-faint, rgba(30,33,37,0.36))",fontWeight:500,fontFamily:"var(--font-fira-code, var(--font-mono, monospace))",letterSpacing:"0.01em",lineHeight:1.4,whiteSpace:"nowrap"},children:[r.jsx("span",{style:{width:5,height:5,borderRadius:"50%",backgroundColor:u,flexShrink:0}}),e.name]},a)})}):null]}),r.jsxs("div",{style:{fontSize:"var(--text-md, 13px)",lineHeight:"var(--leading-normal, 1.5)",color:d?"var(--text-strong, rgba(30,33,37,0.92))":"var(--text-base, rgba(30,33,37,0.78))",fontWeight:d?550:400},children:[s,d?r.jsx("span",{style:{display:"inline-block",width:6,height:14,background:C,marginLeft:2,borderRadius:1,animation:"cursorBlink 0.8s ease-in-out infinite",verticalAlign:"text-bottom"}}):null]}),b||k||n&&n.length>0?r.jsxs("div",{style:{marginTop:6,display:"flex",alignItems:"center",gap:6},children:[k,b?r.jsx("span",{style:{fontSize:"var(--text-sm, 11px)",padding:"2px 8px",borderRadius:999,border:"1px solid var(--border, rgba(52,58,64,0.12))",background:"var(--timestamp-bg, rgba(255,255,255,0.70))",color:"var(--text-muted, rgba(30,33,37,0.56))",fontFamily:"var(--font-mono, monospace)"},children:b}):null,n&&n.length>0?r.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:4,marginLeft:"auto"},children:n.map((e,a)=>r.jsxs("span",{onClick:e.onClick||(y?()=>y(e):void 0),style:{display:"inline-flex",alignItems:"center",gap:4,fontSize:"var(--text-xs, 10px)",padding:"2px 8px",borderRadius:999,background:`color-mix(in srgb, ${e.color||"var(--state-present)"} 12%, transparent)`,border:`1px solid color-mix(in srgb, ${e.color||"var(--state-present)"} 25%, transparent)`,color:e.color||"var(--state-present)",fontWeight:550,lineHeight:1.4,whiteSpace:"nowrap",cursor:e.onClick||y?"pointer":"default",transition:"background 0.15s"},title:e.reason||e.label,children:[r.jsx("span",{style:{width:4,height:4,borderRadius:"50%",backgroundColor:e.color||"var(--state-present)",flexShrink:0,opacity:.7}}),e.label]},a))}):null]}):null,v?r.jsx("div",{style:{marginTop:6,fontSize:"var(--text-xs-plus, 10.5px)",color:"var(--text-faint, rgba(30,33,37,0.36))",fontFamily:"var(--font-mono, monospace)"},children:v}):null,B&&t?r.jsx("div",{style:{position:"absolute",right:8,top:8,bottom:8,width:6,borderRadius:4,backgroundColor:t,opacity:.7,animation:"turn-playing-pulse 1.5s ease-in-out infinite"}}):null]})}const P=i=>{const[s,c]=i.split("–").map(h=>{const[x,f]=h.split(":").map(Number);return x*60+f});return{start:s,end:c}},W=i=>({customer:"customer",agent:"agent",third_party:"agent",system:"system",assistant:"assistant"})[i]||"agent";function z({turns:i,audioUrl:s,activeTurnIndex:c=-1,autoScrollActiveTurn:h=!1,isExternalPlaying:x=!1,onTurnPlayPause:f}){const[d,v]=l.useState(null),[b,m]=l.useState(!1),t=l.useRef(null),n=l.useRef(null),y=l.useRef([]),k=l.useRef(null),p=l.useRef(-1),j=typeof f=="function",C=x!==void 0;l.useEffect(()=>{if(s)return t.current=new Audio(s),t.current.preload="auto",()=>{t.current&&(t.current.pause(),t.current=null)}},[s]),l.useEffect(()=>()=>{t.current&&(t.current.pause(),n.current&&t.current.removeEventListener("timeupdate",n.current))},[]),l.useEffect(()=>{if(!h||c<0)return;const e=k.current,a=y.current[c];if(!a||!e)return;const o=e.getBoundingClientRect(),g=a.getBoundingClientRect(),u=12,R=g.top>=o.top+u&&g.bottom<=o.bottom-8;if(!(p.current===c)||!R){const H=g.top-o.top+e.scrollTop;e.scrollTop=Math.max(H-u,0)}p.current=c},[c,h]);const B=(e,a)=>{if(j){f(i[a],a);return}if(d===a&&b)t.current&&(t.current.pause(),n.current&&(t.current.removeEventListener("timeupdate",n.current),n.current=null)),m(!1);else{const o=d;if(v(a),s&&t.current){const{start:g,end:u}=P(e);o!==null&&o!==a&&(t.current.pause(),n.current&&(t.current.removeEventListener("timeupdate",n.current),n.current=null));const R=()=>{if(t.current){if(t.current.currentTime=g,u){const S=()=>{t.current&&t.current.currentTime>=u&&(t.current.pause(),m(!1),v(null),n.current&&(t.current.removeEventListener("timeupdate",n.current),n.current=null))};n.current=S,t.current.addEventListener("timeupdate",S)}t.current.play().then(()=>m(!0)).catch(S=>{S&&S.name==="AbortError"||(m(!1),v(null))})}};t.current.readyState>=2?R():(t.current.addEventListener("loadedmetadata",R,{once:!0}),t.current.load())}else m(!0)}};return r.jsxs("div",{ref:k,className:"custom-thin-scrollbar-library",style:{maxHeight:560,overflowY:"auto",scrollBehavior:"smooth",border:"1px solid var(--border, rgba(52,58,64,0.12))",borderRadius:"12px 0px 0px 12px",background:"var(--paper-elevated, rgba(255,255,255,0.82))",padding:16},children:[r.jsx("div",{style:{fontSize:"var(--text-xs-plus, 10.5px)",fontWeight:650,textTransform:"uppercase",letterSpacing:"var(--tracking-label, 0.16em)",color:"var(--text-faint, rgba(30,33,37,0.36))",marginBottom:12},children:"Transcript"}),r.jsx("div",{style:{display:"flex",flexDirection:"column",gap:8},children:i.map((e,a)=>{const o=j||C?!!x&&c===a:d===a&&b,g=!!e.isHighlighted||o,u=W(e.actorType);return r.jsx("div",{ref:R=>{y.current[a]=R},children:r.jsx(A,{role:u,text:e.text,actorLabel:e.actor,actorRailColor:e.actorColor,timeRange:e.timeRange,isHighlighted:g,highlightRailColor:o?e.highlightColor||(u==="agent"?"var(--rail-outcome)":"var(--rail-discovery)"):e.highlightColor,toolBadges:e.toolBadges,observations:e.observations,onObservationClick:e.onObservationClick,children:e.timeRange?r.jsx("button",{onClick:()=>B(e.timeRange,a),style:{width:24,height:24,borderRadius:"50%",border:"1px solid var(--border, rgba(52,58,64,0.12))",background:o?"var(--rail-discovery, #5E88B0)":"var(--paper, rgba(255,255,255,0.78))",display:"inline-flex",alignItems:"center",justifyContent:"center",cursor:"pointer",padding:0,transition:"all 0.15s"},"aria-label":o?`Pause segment ${e.timeRange}`:`Play segment ${e.timeRange}`,children:o?r.jsx(T.Pause,{style:{width:12,height:12,color:"var(--paper, #fff)",fill:"var(--paper, #fff)"},strokeWidth:0}):r.jsx(T.Play,{style:{width:12,height:12,color:"var(--text-muted, rgba(30,33,37,0.56))",fill:"var(--text-muted, rgba(30,33,37,0.56))",marginLeft:1},strokeWidth:0})}):null})},a)})})]})}exports.ConversationTurn=A;exports.TranscriptCard=z;
|
|
7
|
+
//# sourceMappingURL=TranscriptCard.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TranscriptCard.cjs.js","sources":["../src/components/media/ConversationTurn.jsx","../src/components/media/TranscriptCard.jsx"],"sourcesContent":["\"use client\";\n\nimport React, { useEffect } from \"react\";\n\n/**\n * Actor configuration — rail color + subtle card tint per role.\n * Colors reference CSS custom properties from the Chordia design system.\n */\nconst ACTOR_DEFAULTS = {\n customer: {\n label: \"Customer\",\n railColor: \"var(--rail-discovery)\",\n cardBg: \"var(--card-customer)\",\n cardBgHighlight: \"rgba(94, 136, 176, 0.12)\",\n borderColor: \"var(--border-subtle)\",\n },\n agent: {\n label: \"Agent\",\n railColor: \"var(--rail-outcome)\",\n cardBg: \"var(--card-agent)\",\n cardBgHighlight: \"rgba(107, 124, 147, 0.10)\",\n borderColor: \"var(--border-subtle)\",\n },\n assistant: {\n label: \"AI Assistant\",\n railColor: \"var(--rail-purple)\",\n cardBg: \"var(--card-assistant)\",\n cardBgHighlight: \"rgba(155, 122, 168, 0.10)\",\n borderColor: \"var(--border-subtle)\",\n },\n system: {\n label: \"System\",\n railColor: \"var(--text-faint)\",\n cardBg: \"transparent\",\n cardBgHighlight: \"transparent\",\n borderColor: \"transparent\",\n },\n};\n\n/**\n * ConversationTurn Component\n * Displays a single turn in a live conversation stream.\n * Uses the TranscriptCard design language: left actor rail, uppercase label,\n * subtle per-actor card tinting.\n *\n * @param {Object} props\n * @param {string} props.role - \"customer\" | \"agent\" | \"assistant\" | \"system\"\n * @param {string} props.text - Message content\n * @param {string} [props.actorLabel] - Override the default actor label\n * @param {string} [props.actorRailColor] - Override the rail color for this turn\n * @param {string} [props.actionKicker] - NBA action label above message\n * @param {Array} [props.toolBadges] - [{name, success, pending}] tool call results\n * @param {boolean} [props.streaming] - Whether this message is actively streaming\n * @param {string} [props.meta] - Timing info, turn number, etc.\n * @param {string} [props.timeRange] - Time range label (e.g., \"00:03–00:07\")\n * @param {boolean} [props.isHighlighted] - Extra emphasis on this turn\n * @param {string} [props.highlightRailColor] - Color for the right highlight rail (when highlighted)\n * @param {React.ReactNode} [props.children] - Additional content below the message text\n */\nconst KEYFRAMES_ID = \"conversation-turn-keyframes\";\nfunction ensureKeyframes() {\n if (typeof document === \"undefined\") return;\n if (document.getElementById(KEYFRAMES_ID)) return;\n const style = document.createElement(\"style\");\n style.id = KEYFRAMES_ID;\n style.textContent = `\n @keyframes turn-playing-pulse {\n 0%, 100% { opacity: 0.4; }\n 50% { opacity: 0.9; }\n }\n `;\n document.head.appendChild(style);\n}\n\nexport default function ConversationTurn({\n role = \"agent\",\n text,\n actorLabel,\n actorRailColor,\n actionKicker,\n toolBadges,\n streaming = false,\n meta,\n timeRange,\n isHighlighted = false,\n highlightRailColor,\n observations,\n onObservationClick,\n children,\n}) {\n useEffect(() => { ensureKeyframes(); }, []);\n const actor = ACTOR_DEFAULTS[role] || ACTOR_DEFAULTS.agent;\n const label = actorLabel || actor.label;\n const railColor = actorRailColor || actor.railColor;\n const highlighted = isHighlighted || streaming;\n\n // System messages: minimal centered text, no card\n if (role === \"system\") {\n return (\n <div\n style={{\n textAlign: \"center\",\n padding: \"6px 0\",\n flexShrink: 0,\n fontSize: \"var(--text-sm, 11px)\",\n color: \"var(--text-faint, rgba(30,33,37,0.36))\",\n fontWeight: 500,\n letterSpacing: \"0.02em\",\n }}\n >\n {text}\n </div>\n );\n }\n\n return (\n <div\n style={{\n position: \"relative\",\n padding: \"10px 14px 10px 18px\",\n borderRadius: 10,\n overflow: \"hidden\",\n flexShrink: 0,\n background: highlighted ? actor.cardBgHighlight : actor.cardBg,\n border: `1px solid ${streaming ? railColor : actor.borderColor}`,\n boxShadow: streaming\n ? `0 0 8px ${actor.cardBgHighlight}`\n : \"none\",\n transition: \"background 0.2s, border-color 0.2s, box-shadow 0.2s\",\n }}\n >\n {/* Left actor rail */}\n <div\n style={{\n position: \"absolute\",\n left: 0,\n top: 0,\n bottom: 0,\n width: \"var(--rail-width-thin, 4px)\",\n backgroundColor: railColor,\n borderRadius: \"10px 0 0 10px\",\n }}\n />\n\n {/* Header row: actor label left, tool badges right */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"flex-start\",\n justifyContent: \"space-between\",\n gap: 8,\n marginBottom: 4,\n }}\n >\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 2 }}>\n {/* Action kicker (NBA label) */}\n {actionKicker ? (\n <div\n style={{\n fontSize: \"var(--text-xs-plus, 10.5px)\",\n fontWeight: 650,\n textTransform: \"uppercase\",\n letterSpacing: \"var(--tracking-label, 0.16em)\",\n color: railColor,\n }}\n >\n {actionKicker}\n </div>\n ) : null}\n\n {/* Actor label */}\n <div\n style={{\n fontSize: \"var(--text-xs-plus, 10.5px)\",\n fontWeight: 650,\n textTransform: \"uppercase\",\n letterSpacing: \"var(--tracking-label, 0.16em)\",\n color: \"var(--text-faint, rgba(30,33,37,0.36))\",\n }}\n >\n {label}\n </div>\n </div>\n\n {/* Tool badges — top right pills, uniform neutral with status dot */}\n {toolBadges && toolBadges.length > 0 ? (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 4, flexShrink: 0, justifyContent: \"flex-end\" }}>\n {toolBadges.map((t, i) => {\n const isPending = t.pending;\n const isError = !isPending && t.success === false;\n // Dot color only — rail colors for categorization, not judgment\n const dotColor = isPending\n ? \"var(--rail-discovery, #5E88B0)\"\n : isError\n ? \"var(--rail-compliance, #C98A5A)\"\n : \"var(--text-xfaint, rgba(30,33,37,0.28))\";\n\n return (\n <span\n key={i}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 5,\n fontSize: \"var(--text-xs, 10px)\",\n padding: \"2px 8px 2px 6px\",\n borderRadius: 999,\n background: \"var(--paper, rgba(255,255,255,0.78))\",\n border: \"1px solid var(--border-subtle, rgba(52,58,64,0.08))\",\n color: \"var(--text-faint, rgba(30,33,37,0.36))\",\n fontWeight: 500,\n fontFamily: \"var(--font-fira-code, var(--font-mono, monospace))\",\n letterSpacing: \"0.01em\",\n lineHeight: 1.4,\n whiteSpace: \"nowrap\",\n }}\n >\n <span\n style={{\n width: 5,\n height: 5,\n borderRadius: \"50%\",\n backgroundColor: dotColor,\n flexShrink: 0,\n }}\n />\n {t.name}\n </span>\n );\n })}\n </div>\n ) : null}\n </div>\n\n {/* Message text */}\n <div\n style={{\n fontSize: \"var(--text-md, 13px)\",\n lineHeight: \"var(--leading-normal, 1.5)\",\n color: streaming\n ? \"var(--text-strong, rgba(30,33,37,0.92))\"\n : \"var(--text-base, rgba(30,33,37,0.78))\",\n fontWeight: streaming ? 550 : 400,\n }}\n >\n {text}\n {streaming ? (\n <span\n style={{\n display: \"inline-block\",\n width: 6,\n height: 14,\n background: railColor,\n marginLeft: 2,\n borderRadius: 1,\n animation: \"cursorBlink 0.8s ease-in-out infinite\",\n verticalAlign: \"text-bottom\",\n }}\n />\n ) : null}\n </div>\n\n {/* Time range + play button + observation pills — single row */}\n {timeRange || children || (observations && observations.length > 0) ? (\n <div style={{ marginTop: 6, display: \"flex\", alignItems: \"center\", gap: 6 }}>\n {children}\n {timeRange ? (\n <span\n style={{\n fontSize: \"var(--text-sm, 11px)\",\n padding: \"2px 8px\",\n borderRadius: 999,\n border: \"1px solid var(--border, rgba(52,58,64,0.12))\",\n background: \"var(--timestamp-bg, rgba(255,255,255,0.70))\",\n color: \"var(--text-muted, rgba(30,33,37,0.56))\",\n fontFamily: \"var(--font-mono, monospace)\",\n }}\n >\n {timeRange}\n </span>\n ) : null}\n {observations && observations.length > 0 ? (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 4, marginLeft: \"auto\" }}>\n {observations.map((obs, i) => (\n <span\n key={i}\n onClick={obs.onClick || (onObservationClick ? () => onObservationClick(obs) : undefined)}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 4,\n fontSize: \"var(--text-xs, 10px)\",\n padding: \"2px 8px\",\n borderRadius: 999,\n background: `color-mix(in srgb, ${obs.color || \"var(--state-present)\"} 12%, transparent)`,\n border: `1px solid color-mix(in srgb, ${obs.color || \"var(--state-present)\"} 25%, transparent)`,\n color: obs.color || \"var(--state-present)\",\n fontWeight: 550,\n lineHeight: 1.4,\n whiteSpace: \"nowrap\",\n cursor: obs.onClick || onObservationClick ? \"pointer\" : \"default\",\n transition: \"background 0.15s\",\n }}\n title={obs.reason || obs.label}\n >\n <span style={{\n width: 4, height: 4, borderRadius: \"50%\",\n backgroundColor: obs.color || \"var(--state-present)\",\n flexShrink: 0, opacity: 0.7,\n }} />\n {obs.label}\n </span>\n ))}\n </div>\n ) : null}\n </div>\n ) : null}\n\n {/* Meta / timestamp */}\n {meta ? (\n <div\n style={{\n marginTop: 6,\n fontSize: \"var(--text-xs-plus, 10.5px)\",\n color: \"var(--text-faint, rgba(30,33,37,0.36))\",\n fontFamily: \"var(--font-mono, monospace)\",\n }}\n >\n {meta}\n </div>\n ) : null}\n\n {/* Right highlight rail (used by TranscriptCard for active/highlighted turns) */}\n {highlighted && highlightRailColor ? (\n <div\n style={{\n position: \"absolute\",\n right: 8,\n top: 8,\n bottom: 8,\n width: 6,\n borderRadius: 4,\n backgroundColor: highlightRailColor,\n opacity: 0.7,\n animation: \"turn-playing-pulse 1.5s ease-in-out infinite\",\n }}\n />\n ) : null}\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useState, useRef, useEffect } from \"react\";\nimport { Play, Pause } from \"lucide-react\";\nimport ConversationTurn from \"./ConversationTurn\";\n\n/**\n * Helper function to parse time range string (e.g., \"00:03–00:07\") to seconds\n */\nconst parseTimeRange = (timeRange) => {\n const [start, end] = timeRange.split(\"–\").map((time) => {\n const [minutes, seconds] = time.split(\":\").map(Number);\n return minutes * 60 + seconds;\n });\n return { start, end };\n};\n\n/**\n * Map TranscriptCard actorType values to ConversationTurn role values.\n * ConversationTurn uses: \"customer\" | \"agent\" | \"assistant\" | \"system\"\n * TranscriptCard uses: \"customer\" | \"agent\" | \"third_party\" | \"system\"\n */\nconst mapActorTypeToRole = (actorType) => {\n const map = {\n customer: \"customer\",\n agent: \"agent\",\n third_party: \"agent\",\n system: \"system\",\n assistant: \"assistant\",\n };\n return map[actorType] || \"agent\";\n};\n\n/**\n * TranscriptCard Component\n * Displays a complete transcript with multiple turns, audio playback,\n * highlighting, and per-turn play buttons. Composes ConversationTurn\n * for individual turn rendering.\n *\n * @param {Object} props - Component props\n * @param {Array} props.turns - Array of transcript turn objects\n * @param {string} props.turns[].actor - Display name (e.g., \"Agent\", \"Customer\")\n * @param {string} props.turns[].actorType - \"agent\" | \"customer\" | \"third_party\" | \"system\" | \"assistant\"\n * @param {string} [props.turns[].actorColor] - Override rail color for this turn\n * @param {string} props.turns[].text - Transcript text\n * @param {string} [props.turns[].timeRange] - Time range (e.g., \"00:03–00:07\")\n * @param {boolean} [props.turns[].isHighlighted] - Whether this turn is highlighted\n * @param {string} [props.turns[].highlightColor] - Color for the right highlight rail\n * @param {Array} [props.turns[].toolBadges] - Tool badge data [{name, success, pending}]\n * @param {string} [props.audioUrl] - Audio URL for segment playback\n * @param {number} [props.activeTurnIndex=-1] - Index of the externally active turn\n * @param {boolean} [props.autoScrollActiveTurn=false] - Auto-scroll to active turn\n * @param {boolean} [props.isExternalPlaying=false] - External playback state\n * @param {Function} [props.onTurnPlayPause] - External playback handler (turn, index) => void\n */\nexport default function TranscriptCard({\n turns,\n audioUrl,\n activeTurnIndex = -1,\n autoScrollActiveTurn = false,\n isExternalPlaying = false,\n onTurnPlayPause,\n}) {\n const [playingSegment, setPlayingSegment] = useState(null);\n const [isPlaying, setIsPlaying] = useState(false);\n const audioRef = useRef(null);\n const endTimeListenerRef = useRef(null);\n const turnRefs = useRef([]);\n const containerRef = useRef(null);\n const lastAutoScrolledIndexRef = useRef(-1);\n const useExternalPlaybackControl = typeof onTurnPlayPause === \"function\";\n const hasExternalPlaybackState = isExternalPlaying !== undefined;\n\n // Initialize audio element\n useEffect(() => {\n if (audioUrl) {\n audioRef.current = new Audio(audioUrl);\n audioRef.current.preload = \"auto\";\n return () => {\n if (audioRef.current) {\n audioRef.current.pause();\n audioRef.current = null;\n }\n };\n }\n }, [audioUrl]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (audioRef.current) {\n audioRef.current.pause();\n if (endTimeListenerRef.current) {\n audioRef.current.removeEventListener(\"timeupdate\", endTimeListenerRef.current);\n }\n }\n };\n }, []);\n\n // Auto-scroll to active turn\n useEffect(() => {\n if (!autoScrollActiveTurn || activeTurnIndex < 0) return;\n const container = containerRef.current;\n const activeNode = turnRefs.current[activeTurnIndex];\n if (!activeNode || !container) return;\n\n const containerRect = container.getBoundingClientRect();\n const activeRect = activeNode.getBoundingClientRect();\n const topPadding = 12;\n const isFullyVisible =\n activeRect.top >= containerRect.top + topPadding &&\n activeRect.bottom <= containerRect.bottom - 8;\n const didScrollForThisTurn = lastAutoScrolledIndexRef.current === activeTurnIndex;\n\n if (!didScrollForThisTurn || !isFullyVisible) {\n const activeTopInContainer = activeRect.top - containerRect.top + container.scrollTop;\n container.scrollTop = Math.max(activeTopInContainer - topPadding, 0);\n }\n lastAutoScrolledIndexRef.current = activeTurnIndex;\n }, [activeTurnIndex, autoScrollActiveTurn]);\n\n const handlePlayPause = (timeRange, index) => {\n if (useExternalPlaybackControl) {\n onTurnPlayPause(turns[index], index);\n return;\n }\n\n if (playingSegment === index && isPlaying) {\n // Pause current segment\n if (audioRef.current) {\n audioRef.current.pause();\n if (endTimeListenerRef.current) {\n audioRef.current.removeEventListener(\"timeupdate\", endTimeListenerRef.current);\n endTimeListenerRef.current = null;\n }\n }\n setIsPlaying(false);\n } else {\n // Start/switch segment\n const previousSegment = playingSegment;\n setPlayingSegment(index);\n\n if (audioUrl && audioRef.current) {\n const { start, end } = parseTimeRange(timeRange);\n\n if (previousSegment !== null && previousSegment !== index) {\n audioRef.current.pause();\n if (endTimeListenerRef.current) {\n audioRef.current.removeEventListener(\"timeupdate\", endTimeListenerRef.current);\n endTimeListenerRef.current = null;\n }\n }\n\n const playSegment = () => {\n if (!audioRef.current) return;\n audioRef.current.currentTime = start;\n\n if (end) {\n const checkEndTime = () => {\n if (audioRef.current && audioRef.current.currentTime >= end) {\n audioRef.current.pause();\n setIsPlaying(false);\n setPlayingSegment(null);\n if (endTimeListenerRef.current) {\n audioRef.current.removeEventListener(\"timeupdate\", endTimeListenerRef.current);\n endTimeListenerRef.current = null;\n }\n }\n };\n endTimeListenerRef.current = checkEndTime;\n audioRef.current.addEventListener(\"timeupdate\", checkEndTime);\n }\n\n audioRef.current.play()\n .then(() => setIsPlaying(true))\n .catch((err) => {\n // Ignore AbortError which occurs when play() is interrupted by pause()\n if (err && err.name === \"AbortError\") {\n return;\n }\n setIsPlaying(false);\n setPlayingSegment(null);\n });\n };\n\n if (audioRef.current.readyState >= 2) {\n playSegment();\n } else {\n audioRef.current.addEventListener(\"loadedmetadata\", playSegment, { once: true });\n audioRef.current.load();\n }\n } else {\n setIsPlaying(true);\n }\n }\n };\n\n return (\n <div\n ref={containerRef}\n className=\"custom-thin-scrollbar-library\"\n style={{\n maxHeight: 560,\n overflowY: \"auto\",\n scrollBehavior: \"smooth\",\n border: \"1px solid var(--border, rgba(52,58,64,0.12))\",\n // borderRadius: \"var(--radius-lg, 12px)\",\n borderRadius: \"12px 0px 0px 12px\",\n background: \"var(--paper-elevated, rgba(255,255,255,0.82))\",\n padding: 16,\n }}\n >\n {/* Section label */}\n <div\n style={{\n fontSize: \"var(--text-xs-plus, 10.5px)\",\n fontWeight: 650,\n textTransform: \"uppercase\",\n letterSpacing: \"var(--tracking-label, 0.16em)\",\n color: \"var(--text-faint, rgba(30,33,37,0.36))\",\n marginBottom: 12,\n }}\n >\n Transcript\n </div>\n\n {/* Turns */}\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 8 }}>\n {turns.map((turn, index) => {\n const isTurnPlaying = (useExternalPlaybackControl || hasExternalPlaybackState)\n ? Boolean(isExternalPlaying) && activeTurnIndex === index\n : playingSegment === index && isPlaying;\n const isTurnHighlighted = Boolean(turn.isHighlighted) || isTurnPlaying;\n const role = mapActorTypeToRole(turn.actorType);\n\n return (\n <div\n key={index}\n ref={(el) => { turnRefs.current[index] = el; }}\n >\n <ConversationTurn\n role={role}\n text={turn.text}\n actorLabel={turn.actor}\n actorRailColor={turn.actorColor}\n timeRange={turn.timeRange}\n isHighlighted={isTurnHighlighted}\n highlightRailColor={isTurnPlaying \n ? (turn.highlightColor || (role === 'agent' ? 'var(--rail-outcome)' : 'var(--rail-discovery)'))\n : turn.highlightColor}\n toolBadges={turn.toolBadges}\n observations={turn.observations}\n onObservationClick={turn.onObservationClick}\n >\n {/* Play/pause button — rendered inline left of time range */}\n {turn.timeRange ? (\n <button\n onClick={() => handlePlayPause(turn.timeRange, index)}\n style={{\n width: 24,\n height: 24,\n borderRadius: \"50%\",\n border: \"1px solid var(--border, rgba(52,58,64,0.12))\",\n background: isTurnPlaying\n ? \"var(--rail-discovery, #5E88B0)\"\n : \"var(--paper, rgba(255,255,255,0.78))\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: \"pointer\",\n padding: 0,\n transition: \"all 0.15s\",\n }}\n aria-label={isTurnPlaying ? `Pause segment ${turn.timeRange}` : `Play segment ${turn.timeRange}`}\n >\n {isTurnPlaying ? (\n <Pause\n style={{ width: 12, height: 12, color: \"var(--paper, #fff)\", fill: \"var(--paper, #fff)\" }}\n strokeWidth={0}\n />\n ) : (\n <Play\n style={{ width: 12, height: 12, color: \"var(--text-muted, rgba(30,33,37,0.56))\", fill: \"var(--text-muted, rgba(30,33,37,0.56))\", marginLeft: 1 }}\n strokeWidth={0}\n />\n )}\n </button>\n ) : null}\n </ConversationTurn>\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n"],"names":["ACTOR_DEFAULTS","KEYFRAMES_ID","ensureKeyframes","style","ConversationTurn","role","text","actorLabel","actorRailColor","actionKicker","toolBadges","streaming","meta","timeRange","isHighlighted","highlightRailColor","observations","onObservationClick","children","useEffect","actor","label","railColor","highlighted","jsx","jsxs","t","i","isPending","isError","dotColor","obs","parseTimeRange","start","end","time","minutes","seconds","mapActorTypeToRole","actorType","TranscriptCard","turns","audioUrl","activeTurnIndex","autoScrollActiveTurn","isExternalPlaying","onTurnPlayPause","playingSegment","setPlayingSegment","useState","isPlaying","setIsPlaying","audioRef","useRef","endTimeListenerRef","turnRefs","containerRef","lastAutoScrolledIndexRef","useExternalPlaybackControl","hasExternalPlaybackState","container","activeNode","containerRect","activeRect","topPadding","isFullyVisible","activeTopInContainer","handlePlayPause","index","previousSegment","playSegment","checkEndTime","err","turn","isTurnPlaying","isTurnHighlighted","el","Pause","Play"],"mappings":"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"}
|