@bendyline/squisq-react 2.7.1 → 2.8.0

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.
@@ -1242,10 +1242,282 @@ function DocControlsSlideshow({
1242
1242
  );
1243
1243
  }
1244
1244
 
1245
+ // src/DashboardView.tsx
1246
+ import { Fragment as Fragment2, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef4 } from "react";
1247
+ import { materializeDashboard, resolveThemeForDoc, VIEWPORT_PRESETS } from "@bendyline/squisq/doc";
1248
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
1249
+ async function waitForDashboardAssets(root) {
1250
+ if (typeof document !== "undefined" && document.fonts?.ready) {
1251
+ try {
1252
+ await document.fonts.ready;
1253
+ } catch {
1254
+ }
1255
+ }
1256
+ const images = Array.from(root.querySelectorAll("img"));
1257
+ await Promise.allSettled(
1258
+ images.map((img) => {
1259
+ if (img.complete) return Promise.resolve();
1260
+ if (typeof img.decode === "function") return img.decode().catch(() => void 0);
1261
+ return new Promise((resolve) => {
1262
+ img.addEventListener("load", () => resolve(), { once: true });
1263
+ img.addEventListener("error", () => resolve(), { once: true });
1264
+ });
1265
+ })
1266
+ );
1267
+ await new Promise((resolve) => {
1268
+ if (typeof requestAnimationFrame === "function") {
1269
+ requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
1270
+ } else {
1271
+ setTimeout(resolve, 0);
1272
+ }
1273
+ });
1274
+ }
1275
+ function syntheticBlock(id, layers) {
1276
+ return { id, startTime: 0, duration: 0, audioSegment: 0, layers };
1277
+ }
1278
+ function DashboardView({
1279
+ doc,
1280
+ theme,
1281
+ viewport,
1282
+ layout,
1283
+ showTitle,
1284
+ style,
1285
+ documentTitle,
1286
+ basePath = ".",
1287
+ animationsEnabled = true,
1288
+ muted = true,
1289
+ renderMode = false,
1290
+ onRenderAPIReady,
1291
+ className
1292
+ }) {
1293
+ const rootRef = useRef4(null);
1294
+ const activeTheme = useMemo3(() => theme ?? resolveThemeForDoc(doc), [theme, doc]);
1295
+ const activeViewport = viewport ?? VIEWPORT_PRESETS.landscape;
1296
+ const materialization = useMemo3(
1297
+ () => materializeDashboard(doc, {
1298
+ theme: activeTheme,
1299
+ viewport: activeViewport,
1300
+ layout,
1301
+ showTitle,
1302
+ style,
1303
+ documentTitle
1304
+ }),
1305
+ [doc, activeTheme, activeViewport, layout, showTitle, style, documentTitle]
1306
+ );
1307
+ const backdropBottom = useMemo3(
1308
+ () => syntheticBlock("dashboard-backdrop-bottom", materialization.backdrop.bottomLayers),
1309
+ [materialization]
1310
+ );
1311
+ const backdropTop = useMemo3(
1312
+ () => materialization.backdrop.topLayers.length > 0 ? syntheticBlock("dashboard-backdrop-top", materialization.backdrop.topLayers) : null,
1313
+ [materialization]
1314
+ );
1315
+ const titleBlock = useMemo3(
1316
+ () => materialization.title ? syntheticBlock("dashboard-title-band", materialization.title.layers) : null,
1317
+ [materialization]
1318
+ );
1319
+ useEffect4(() => {
1320
+ if (!renderMode || !onRenderAPIReady) return;
1321
+ const api = {
1322
+ seekTo: async () => {
1323
+ const root = rootRef.current;
1324
+ if (root) await waitForDashboardAssets(root);
1325
+ },
1326
+ getRenderedTime: () => 0,
1327
+ getDuration: () => 0,
1328
+ getBlocks: () => materialization.cells.map((cell) => ({
1329
+ id: String(cell.block.id),
1330
+ template: cell.block.template ?? "content",
1331
+ startTime: 0,
1332
+ duration: 0
1333
+ })),
1334
+ getAudioSegments: () => [],
1335
+ getCaptions: () => [],
1336
+ getChapters: () => [],
1337
+ showCover: async () => {
1338
+ },
1339
+ hideCover: async () => {
1340
+ },
1341
+ hasCoverBlock: () => false
1342
+ };
1343
+ onRenderAPIReady(api);
1344
+ return () => onRenderAPIReady(null);
1345
+ }, [renderMode, onRenderAPIReady, materialization]);
1346
+ const canvasDimensions = { width: activeViewport.width, height: activeViewport.height };
1347
+ const coverStyle = { position: "absolute", inset: 0 };
1348
+ const canvasStyle = {
1349
+ position: "relative",
1350
+ width: "var(--squisq-dashboard-fit-width, 100%)",
1351
+ aspectRatio: `${activeViewport.width} / ${activeViewport.height}`,
1352
+ overflow: "hidden",
1353
+ // The style variant owns the canvas fill: card styles tint it away
1354
+ // from the card surface so cards read as raised.
1355
+ background: materialization.backdrop.fill,
1356
+ margin: "0 auto",
1357
+ "--squisq-dashboard-aspect": (activeViewport.width / activeViewport.height).toFixed(6)
1358
+ };
1359
+ return /* @__PURE__ */ jsxs4(
1360
+ "div",
1361
+ {
1362
+ ref: rootRef,
1363
+ className: className ? `squisq-dashboard ${className}` : "squisq-dashboard",
1364
+ "data-dashboard-layout": materialization.layout.name,
1365
+ "data-dashboard-style": materialization.style,
1366
+ style: canvasStyle,
1367
+ children: [
1368
+ /* @__PURE__ */ jsx7("div", { style: coverStyle, "aria-hidden": "true", children: /* @__PURE__ */ jsx7(
1369
+ BlockRenderer,
1370
+ {
1371
+ block: backdropBottom,
1372
+ blockTime: 0,
1373
+ basePath,
1374
+ viewport: canvasDimensions,
1375
+ isPlaying: false,
1376
+ muted: true,
1377
+ animationsEnabled,
1378
+ theme: activeTheme
1379
+ }
1380
+ ) }),
1381
+ materialization.cells.map((cell) => /* @__PURE__ */ jsxs4(Fragment2, { children: [
1382
+ cell.frame && /* @__PURE__ */ jsx7(
1383
+ "div",
1384
+ {
1385
+ className: "squisq-dashboard__frame",
1386
+ "data-cell-index": cell.index,
1387
+ "aria-hidden": "true",
1388
+ style: {
1389
+ position: "absolute",
1390
+ left: cell.frame.rectPct.left,
1391
+ top: cell.frame.rectPct.top,
1392
+ width: cell.frame.rectPct.width,
1393
+ height: cell.frame.rectPct.height,
1394
+ pointerEvents: "none"
1395
+ },
1396
+ children: /* @__PURE__ */ jsx7(
1397
+ BlockRenderer,
1398
+ {
1399
+ block: syntheticBlock(`dashboard-frame-${cell.index}`, cell.frame.layers),
1400
+ blockTime: 0,
1401
+ basePath,
1402
+ viewport: {
1403
+ width: cell.frame.viewport.width,
1404
+ height: cell.frame.viewport.height
1405
+ },
1406
+ isPlaying: false,
1407
+ muted: true,
1408
+ animationsEnabled,
1409
+ theme: activeTheme
1410
+ }
1411
+ )
1412
+ }
1413
+ ),
1414
+ /* @__PURE__ */ jsxs4(
1415
+ "div",
1416
+ {
1417
+ className: "squisq-dashboard__cell",
1418
+ "data-cell-index": cell.index,
1419
+ style: {
1420
+ position: "absolute",
1421
+ left: cell.rectPct.left,
1422
+ top: cell.rectPct.top,
1423
+ width: cell.rectPct.width,
1424
+ height: cell.rectPct.height,
1425
+ // Percentage radii scale with the rendered canvas, so a card
1426
+ // cell's full-bleed art stays clipped to its corners at any
1427
+ // export resolution.
1428
+ ...cell.frame?.contentRadiusPct ? { borderRadius: cell.frame.contentRadiusPct, overflow: "hidden" } : {}
1429
+ },
1430
+ children: [
1431
+ /* @__PURE__ */ jsx7(
1432
+ BlockRenderer,
1433
+ {
1434
+ block: { ...cell.block, layers: cell.layers },
1435
+ blockTime: 0,
1436
+ basePath,
1437
+ viewport: { width: cell.viewport.width, height: cell.viewport.height },
1438
+ isPlaying: false,
1439
+ muted,
1440
+ animationsEnabled,
1441
+ theme: activeTheme
1442
+ }
1443
+ ),
1444
+ cell.frame && cell.frame.overlayLayers.length > 0 && // Borders and accents ride above the block: a template that
1445
+ // paints its own opaque surface would bury them. Same box, so
1446
+ // the cell's clip rounds them to the card's corners.
1447
+ /* @__PURE__ */ jsx7("div", { style: { position: "absolute", inset: 0, pointerEvents: "none" }, children: /* @__PURE__ */ jsx7(
1448
+ BlockRenderer,
1449
+ {
1450
+ block: syntheticBlock(
1451
+ `dashboard-frame-overlay-${cell.index}`,
1452
+ cell.frame.overlayLayers
1453
+ ),
1454
+ blockTime: 0,
1455
+ basePath,
1456
+ viewport: {
1457
+ width: cell.frame.overlayViewport.width,
1458
+ height: cell.frame.overlayViewport.height
1459
+ },
1460
+ isPlaying: false,
1461
+ muted: true,
1462
+ animationsEnabled,
1463
+ theme: activeTheme
1464
+ }
1465
+ ) })
1466
+ ]
1467
+ }
1468
+ )
1469
+ ] }, `${cell.index}-${cell.block.id}`)),
1470
+ materialization.title && titleBlock && /* @__PURE__ */ jsx7(
1471
+ "div",
1472
+ {
1473
+ className: "squisq-dashboard__title",
1474
+ style: {
1475
+ position: "absolute",
1476
+ left: materialization.title.rectPct.left,
1477
+ top: materialization.title.rectPct.top,
1478
+ width: materialization.title.rectPct.width,
1479
+ height: materialization.title.rectPct.height
1480
+ },
1481
+ children: /* @__PURE__ */ jsx7(
1482
+ BlockRenderer,
1483
+ {
1484
+ block: titleBlock,
1485
+ blockTime: 0,
1486
+ basePath,
1487
+ viewport: {
1488
+ width: materialization.title.viewport.width,
1489
+ height: materialization.title.viewport.height
1490
+ },
1491
+ isPlaying: false,
1492
+ muted: true,
1493
+ animationsEnabled,
1494
+ theme: activeTheme
1495
+ }
1496
+ )
1497
+ }
1498
+ ),
1499
+ backdropTop && /* @__PURE__ */ jsx7("div", { style: { ...coverStyle, pointerEvents: "none" }, "aria-hidden": "true", children: /* @__PURE__ */ jsx7(
1500
+ BlockRenderer,
1501
+ {
1502
+ block: backdropTop,
1503
+ blockTime: 0,
1504
+ basePath,
1505
+ viewport: canvasDimensions,
1506
+ isPlaying: false,
1507
+ muted: true,
1508
+ animationsEnabled,
1509
+ theme: activeTheme
1510
+ }
1511
+ ) })
1512
+ ]
1513
+ }
1514
+ );
1515
+ }
1516
+
1245
1517
  // src/docPlayer/playerAppearance.ts
1246
1518
  import {
1247
1519
  resolveCoverSlideSettings,
1248
- resolveThemeForDoc
1520
+ resolveThemeForDoc as resolveThemeForDoc2
1249
1521
  } from "@bendyline/squisq/doc";
1250
1522
  function readFrontmatterSetting(frontmatter, canonical, legacy) {
1251
1523
  if (!frontmatter) return void 0;
@@ -1303,7 +1575,7 @@ function resolveDocPlayerAppearance(doc, overrides = {}) {
1303
1575
  ...overrides.coverSlidePlayback !== void 0 ? { playback: overrides.coverSlidePlayback } : {}
1304
1576
  });
1305
1577
  return {
1306
- theme: overrides.theme ?? resolveThemeForDoc(doc),
1578
+ theme: overrides.theme ?? resolveThemeForDoc2(doc),
1307
1579
  videoPresentation: overrides.videoPresentation ?? resolveVideoPresentation(
1308
1580
  readFrontmatterSetting(frontmatter, "squisq-video-presentation", "video-presentation")
1309
1581
  ) ?? "background",
@@ -1321,14 +1593,14 @@ function resolveDocPlayerAppearance(doc, overrides = {}) {
1321
1593
 
1322
1594
  // src/DocPlayer.tsx
1323
1595
  import {
1324
- Fragment as Fragment2,
1596
+ Fragment as Fragment3,
1325
1597
  useId as useId2,
1326
- useRef as useRef5,
1598
+ useRef as useRef6,
1327
1599
  useState as useState5,
1328
- useEffect as useEffect5,
1600
+ useEffect as useEffect6,
1329
1601
  useLayoutEffect as useLayoutEffect2,
1330
1602
  useCallback as useCallback4,
1331
- useMemo as useMemo3
1603
+ useMemo as useMemo4
1332
1604
  } from "react";
1333
1605
  import { flushSync } from "react-dom";
1334
1606
  import {
@@ -1340,7 +1612,7 @@ import {
1340
1612
  import { applySurface, pipStyleVars } from "@bendyline/squisq/schemas";
1341
1613
 
1342
1614
  // src/hooks/useSlideSwipe.ts
1343
- import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef4, useState as useState4 } from "react";
1615
+ import { useCallback as useCallback3, useEffect as useEffect5, useRef as useRef5, useState as useState4 } from "react";
1344
1616
  var DISTANCE_RATIO = 0.3;
1345
1617
  var FLICK_VELOCITY = 0.5;
1346
1618
  var MIN_FLICK_DISTANCE = 12;
@@ -1366,13 +1638,13 @@ function useSlideSwipe(opts) {
1366
1638
  const settleMs = opts.settleMs ?? DEFAULT_SETTLE_MS;
1367
1639
  const [offsetPx, setOffsetPx] = useState4(0);
1368
1640
  const [phase, setPhase] = useState4("idle");
1369
- const optsRef = useRef4(opts);
1641
+ const optsRef = useRef5(opts);
1370
1642
  optsRef.current = opts;
1371
- const dragRef = useRef4(null);
1372
- const phaseRef = useRef4("idle");
1643
+ const dragRef = useRef5(null);
1644
+ const phaseRef = useRef5("idle");
1373
1645
  phaseRef.current = phase;
1374
- const settleTimer = useRef4(null);
1375
- const settleRaf = useRef4(null);
1646
+ const settleTimer = useRef5(null);
1647
+ const settleRaf = useRef5(null);
1376
1648
  const clearPending = useCallback3(() => {
1377
1649
  if (settleTimer.current != null) {
1378
1650
  clearTimeout(settleTimer.current);
@@ -1403,7 +1675,7 @@ function useSlideSwipe(opts) {
1403
1675
  setPhase("dragging");
1404
1676
  setOffsetPx(0);
1405
1677
  }, []);
1406
- useEffect4(() => {
1678
+ useEffect5(() => {
1407
1679
  function currentWidth() {
1408
1680
  return optsRef.current.containerRef.current?.getBoundingClientRect().width ?? 0;
1409
1681
  }
@@ -1473,7 +1745,7 @@ function useSlideSwipe(opts) {
1473
1745
  window.removeEventListener("pointercancel", onCancel);
1474
1746
  };
1475
1747
  }, [settleMs]);
1476
- useEffect4(() => {
1748
+ useEffect5(() => {
1477
1749
  if (!opts.enabled) {
1478
1750
  dragRef.current = null;
1479
1751
  clearPending();
@@ -1481,7 +1753,7 @@ function useSlideSwipe(opts) {
1481
1753
  setOffsetPx(0);
1482
1754
  }
1483
1755
  }, [opts.enabled, clearPending]);
1484
- useEffect4(() => clearPending, [clearPending]);
1756
+ useEffect5(() => clearPending, [clearPending]);
1485
1757
  return { offsetPx, phase, onPointerDown };
1486
1758
  }
1487
1759
 
@@ -1490,7 +1762,7 @@ import {
1490
1762
  expandCoverBlock,
1491
1763
  createTemplateContext,
1492
1764
  markdownToDoc,
1493
- VIEWPORT_PRESETS
1765
+ VIEWPORT_PRESETS as VIEWPORT_PRESETS2
1494
1766
  } from "@bendyline/squisq/doc";
1495
1767
  import { parseMarkdown } from "@bendyline/squisq/markdown";
1496
1768
 
@@ -1780,7 +2052,7 @@ function seekVideoToFrame(video, targetTime, timeoutMs = DEFAULT_VIDEO_FRAME_TIM
1780
2052
  }
1781
2053
 
1782
2054
  // src/DocPlayer.tsx
1783
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
2055
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1784
2056
  function isDevEnvironment() {
1785
2057
  try {
1786
2058
  return typeof process !== "undefined" && process.env.NODE_ENV !== "production";
@@ -1812,15 +2084,15 @@ function waitForVisualUpdate() {
1812
2084
  }
1813
2085
  function DocPlayer(props) {
1814
2086
  const { doc, markdown } = props;
1815
- const markdownDoc = useMemo3(
2087
+ const markdownDoc = useMemo4(
1816
2088
  () => !doc && markdown !== void 0 ? markdownToDoc(parseMarkdown(markdown)) : void 0,
1817
2089
  [doc, markdown]
1818
2090
  );
1819
2091
  const resolvedDoc = doc ?? markdownDoc;
1820
2092
  if (!resolvedDoc) {
1821
- return /* @__PURE__ */ jsx7("div", { className: "doc-player doc-player--empty" });
2093
+ return /* @__PURE__ */ jsx8("div", { className: "doc-player doc-player--empty" });
1822
2094
  }
1823
- return /* @__PURE__ */ jsx7(DocPlayerContent, { ...props, doc: resolvedDoc });
2095
+ return /* @__PURE__ */ jsx8(DocPlayerContent, { ...props, doc: resolvedDoc });
1824
2096
  }
1825
2097
  function DocPlayerContent({
1826
2098
  doc,
@@ -1846,6 +2118,10 @@ function DocPlayerContent({
1846
2118
  onBlockMarkers,
1847
2119
  forceViewport,
1848
2120
  displayMode = "video",
2121
+ dashboardLayout,
2122
+ dashboardShowTitle,
2123
+ dashboardStyle,
2124
+ dashboardDocumentTitle,
1849
2125
  showCoverSlide,
1850
2126
  coverSlideTemplate,
1851
2127
  coverSlideDuration,
@@ -1866,20 +2142,21 @@ function DocPlayerContent({
1866
2142
  }) {
1867
2143
  const isSlideshowMode = displayMode === "slideshow";
1868
2144
  const isLinearMode = displayMode === "linear";
1869
- const audioRef = useRef5(null);
1870
- const containerRef = useRef5(null);
2145
+ const isDashboardMode = displayMode === "dashboard";
2146
+ const audioRef = useRef6(null);
2147
+ const containerRef = useRef6(null);
1871
2148
  const playerId = `squisq-player-${useId2().replace(/:/g, "")}`;
1872
2149
  const [tapFeedback, setTapFeedback] = useState5(null);
1873
- const tapFeedbackTimer = useRef5();
2150
+ const tapFeedbackTimer = useRef6();
1874
2151
  const { viewport } = useViewportOrientation();
1875
- const activeViewport = forceViewport || (renderMode ? VIEWPORT_PRESETS.landscape : viewport);
2152
+ const activeViewport = forceViewport || (renderMode ? VIEWPORT_PRESETS2.landscape : viewport);
1876
2153
  const activeOrientation = activeViewport.height > activeViewport.width ? "portrait" : "landscape";
1877
- const isDebugMode = useMemo3(() => {
2154
+ const isDebugMode = useMemo4(() => {
1878
2155
  if (typeof window === "undefined") return false;
1879
2156
  const params = new URLSearchParams(window.location.search);
1880
2157
  return params.get("debug") === "true";
1881
2158
  }, []);
1882
- const syntheticDuration = useMemo3(
2159
+ const syntheticDuration = useMemo4(
1883
2160
  () => audioMode === "synthetic" ? getDocPlaybackDuration(doc) : 0,
1884
2161
  [audioMode, doc]
1885
2162
  );
@@ -1892,7 +2169,7 @@ function DocPlayerContent({
1892
2169
  syntheticDuration
1893
2170
  );
1894
2171
  const audio = externalAudioController || internalAudio;
1895
- useEffect5(() => {
2172
+ useEffect6(() => {
1896
2173
  if (warnedMissingStyles || !isDevEnvironment()) return;
1897
2174
  const el = containerRef.current;
1898
2175
  if (!el || typeof getComputedStyle !== "function") return;
@@ -1923,9 +2200,9 @@ function DocPlayerContent({
1923
2200
  const [renderClock, setRenderClock] = useState5(null);
1924
2201
  const renderTimeOverride = renderClock?.doc === doc ? renderClock.time : null;
1925
2202
  const currentTime = renderMode ? renderTimeOverride ?? audioCurrentTime : audioCurrentTime;
1926
- const rawSchedule = useMemo3(() => resolveMediaSchedule(doc), [doc]);
2203
+ const rawSchedule = useMemo4(() => resolveMediaSchedule(doc), [doc]);
1927
2204
  const clipDurations = useMediaClipDurations(rawSchedule, basePath);
1928
- const mediaSchedule = useMemo3(
2205
+ const mediaSchedule = useMemo4(
1929
2206
  () => resolveMediaSchedule(doc, { intrinsicDuration: (clip) => clipDurations.get(clip.src) }),
1930
2207
  [doc, clipDurations]
1931
2208
  );
@@ -1950,13 +2227,13 @@ function DocPlayerContent({
1950
2227
  if (!isPlaying) startActiveTimelineMedia();
1951
2228
  return toggle();
1952
2229
  }, [isPlaying, startActiveTimelineMedia, toggle]);
1953
- const currentTimeRef = useRef5(currentTime);
2230
+ const currentTimeRef = useRef6(currentTime);
1954
2231
  currentTimeRef.current = currentTime;
1955
- const committedRenderTimeRef = useRef5(currentTime);
1956
- const renderCommitWaitersRef = useRef5([]);
1957
- const totalDurationRef = useRef5(totalDuration);
2232
+ const committedRenderTimeRef = useRef6(currentTime);
2233
+ const renderCommitWaitersRef = useRef6([]);
2234
+ const totalDurationRef = useRef6(totalDuration);
1958
2235
  totalDurationRef.current = totalDuration;
1959
- const expandedBlocksLenRef = useRef5(0);
2236
+ const expandedBlocksLenRef = useRef6(0);
1960
2237
  useLayoutEffect2(() => {
1961
2238
  committedRenderTimeRef.current = currentTime;
1962
2239
  const pending = renderCommitWaitersRef.current;
@@ -1966,7 +2243,7 @@ function DocPlayerContent({
1966
2243
  return false;
1967
2244
  });
1968
2245
  }, [currentTime]);
1969
- useEffect5(
2246
+ useEffect6(
1970
2247
  () => () => {
1971
2248
  const error = new Error("DocPlayer unmounted before the requested frame committed.");
1972
2249
  renderCommitWaitersRef.current.splice(0).forEach((waiter) => waiter.reject(error));
@@ -2006,7 +2283,7 @@ function DocPlayerContent({
2006
2283
  );
2007
2284
  const autoSurface = useAutoSurface(surface === "auto");
2008
2285
  const resolvedSurface = surface === "auto" ? autoSurface : surface;
2009
- const appearance = useMemo3(
2286
+ const appearance = useMemo4(
2010
2287
  () => resolveDocPlayerAppearance(doc, {
2011
2288
  theme,
2012
2289
  videoPresentation,
@@ -2031,13 +2308,13 @@ function DocPlayerContent({
2031
2308
  coverSlidePlayback
2032
2309
  ]
2033
2310
  );
2034
- const effectiveTheme = useMemo3(() => {
2311
+ const effectiveTheme = useMemo4(() => {
2035
2312
  const base = appearance.theme;
2036
2313
  return resolvedSurface ? applySurface(base, resolvedSurface) : base;
2037
2314
  }, [appearance.theme, resolvedSurface]);
2038
- const resolvedPipStyle = useMemo3(() => pipStyleVars(effectiveTheme), [effectiveTheme]);
2315
+ const resolvedPipStyle = useMemo4(() => pipStyleVars(effectiveTheme), [effectiveTheme]);
2039
2316
  const pipVars = resolvedPipStyle;
2040
- const pipFrameStyle = useMemo3(
2317
+ const pipFrameStyle = useMemo4(
2041
2318
  () => ({
2042
2319
  border: resolvedPipStyle["--squisq-pip-border"],
2043
2320
  borderRadius: resolvedPipStyle["--squisq-pip-radius"],
@@ -2067,7 +2344,7 @@ function DocPlayerContent({
2067
2344
  // remove authored slides from the default loss-averse projection.
2068
2345
  useAudioSegmentTiming: audioMode !== "synthetic"
2069
2346
  });
2070
- const coverBlock = useMemo3(() => {
2347
+ const coverBlock = useMemo4(() => {
2071
2348
  const startBlockConfig = doc.startBlock;
2072
2349
  if (!appearance.showCoverSlide) return null;
2073
2350
  if (!startBlockConfig) return null;
@@ -2092,11 +2369,11 @@ function DocPlayerContent({
2092
2369
  const hasManagedCover = !!coverBlock;
2093
2370
  const [slideshowCoverVisible, setSlideshowCoverVisible] = useState5(false);
2094
2371
  const [isSlideshowPickerOpen, setIsSlideshowPickerOpen] = useState5(false);
2095
- const slideshowCoverInitKeyRef = useRef5("");
2096
- useEffect5(() => {
2372
+ const slideshowCoverInitKeyRef = useRef6("");
2373
+ useEffect6(() => {
2097
2374
  slideshowCoverInitKeyRef.current = "";
2098
2375
  }, [doc]);
2099
- useEffect5(() => {
2376
+ useEffect6(() => {
2100
2377
  const initKey = `${isSlideshowMode}:${hasManagedCover}:${renderMode}`;
2101
2378
  if (slideshowCoverInitKeyRef.current === initKey) return;
2102
2379
  slideshowCoverInitKeyRef.current = initKey;
@@ -2109,10 +2386,10 @@ function DocPlayerContent({
2109
2386
  }, [isSlideshowMode, hasManagedCover, renderMode, pause]);
2110
2387
  const [coverForced, setCoverForced] = useState5(false);
2111
2388
  const [coverGraceActive, setCoverGraceActive] = useState5(false);
2112
- const coverGraceTimer = useRef5();
2113
- const coverWasShowing = useRef5(false);
2114
- const hasPlayedOnce = useRef5(false);
2115
- useEffect5(() => {
2389
+ const coverGraceTimer = useRef6();
2390
+ const coverWasShowing = useRef6(false);
2391
+ const hasPlayedOnce = useRef6(false);
2392
+ useEffect6(() => {
2116
2393
  hasPlayedOnce.current = false;
2117
2394
  coverWasShowing.current = false;
2118
2395
  clearTimeout(coverGraceTimer.current);
@@ -2121,7 +2398,7 @@ function DocPlayerContent({
2121
2398
  }, [doc]);
2122
2399
  const atRest = !!(coverBlock && !isSlideshowMode && !isPlaying && currentTime === 0 && !hasPlayedOnce.current && !renderMode && !autoPlay);
2123
2400
  if (atRest) coverWasShowing.current = true;
2124
- useEffect5(() => {
2401
+ useEffect6(() => {
2125
2402
  if (isPlaying && coverWasShowing.current && coverBlock && !renderMode && !isSlideshowMode) {
2126
2403
  coverWasShowing.current = false;
2127
2404
  hasPlayedOnce.current = true;
@@ -2132,8 +2409,8 @@ function DocPlayerContent({
2132
2409
  );
2133
2410
  }
2134
2411
  }, [isPlaying, coverBlock, renderMode, isSlideshowMode, appearance.coverSlideDuration]);
2135
- useEffect5(() => () => clearTimeout(coverGraceTimer.current), []);
2136
- useEffect5(() => () => clearTimeout(tapFeedbackTimer.current), []);
2412
+ useEffect6(() => () => clearTimeout(coverGraceTimer.current), []);
2413
+ useEffect6(() => () => clearTimeout(tapFeedbackTimer.current), []);
2137
2414
  const showVideoCoverBlock = !isSlideshowMode && !isLinearMode && !!coverBlock && (coverForced || coverGraceActive || !isPlaying && currentTime === 0 && !hasPlayedOnce.current && !renderMode && !autoPlay);
2138
2415
  const effectiveSlideshowCoverVisible = coverVisible ?? slideshowCoverVisible;
2139
2416
  const showSlideshowCover = !!(isSlideshowMode && !isLinearMode && !renderMode && coverBlock && effectiveSlideshowCoverVisible);
@@ -2141,29 +2418,29 @@ function DocPlayerContent({
2141
2418
  const slideshowHasCover = !!(isSlideshowMode && !renderMode && coverBlock);
2142
2419
  const slideshowSlideIndex = slideshowHasCover ? effectiveSlideshowCoverVisible ? 0 : currentBlockIndex + 1 : currentBlockIndex;
2143
2420
  const slideshowTotalSlides = slideshowHasCover ? expandedBlocks.length + 1 : expandedBlocks.length;
2144
- const hasAutoPlayed = useRef5(false);
2145
- useEffect5(() => {
2421
+ const hasAutoPlayed = useRef6(false);
2422
+ useEffect6(() => {
2146
2423
  hasAutoPlayed.current = false;
2147
2424
  }, [doc]);
2148
- useEffect5(() => {
2425
+ useEffect6(() => {
2149
2426
  if (isAudioReady && autoPlay && !hasAutoPlayed.current) {
2150
2427
  hasAutoPlayed.current = true;
2151
2428
  playWithTimelineMedia();
2152
2429
  }
2153
2430
  }, [isAudioReady, autoPlay, playWithTimelineMedia]);
2154
- useEffect5(() => {
2431
+ useEffect6(() => {
2155
2432
  onTimeUpdate?.(currentTime);
2156
2433
  }, [currentTime, onTimeUpdate]);
2157
- useEffect5(() => {
2434
+ useEffect6(() => {
2158
2435
  if (isEnded) {
2159
2436
  onEnded?.();
2160
- if (loop && !isSlideshowMode && !isLinearMode) {
2437
+ if (loop && !isSlideshowMode && !isLinearMode && !isDashboardMode) {
2161
2438
  void restart();
2162
2439
  }
2163
2440
  }
2164
- }, [isEnded, isLinearMode, isSlideshowMode, loop, onEnded, restart]);
2165
- const liveRenderAPIRef = useRef5(null);
2166
- const stableRenderAPIRef = useRef5(null);
2441
+ }, [isEnded, isDashboardMode, isLinearMode, isSlideshowMode, loop, onEnded, restart]);
2442
+ const liveRenderAPIRef = useRef6(null);
2443
+ const stableRenderAPIRef = useRef6(null);
2167
2444
  if (!stableRenderAPIRef.current) {
2168
2445
  const current = () => {
2169
2446
  const api = liveRenderAPIRef.current;
@@ -2184,8 +2461,8 @@ function DocPlayerContent({
2184
2461
  };
2185
2462
  }
2186
2463
  const stableRenderAPI = stableRenderAPIRef.current;
2187
- useEffect5(() => {
2188
- if (!renderMode && !isDebugMode) {
2464
+ useEffect6(() => {
2465
+ if (isDashboardMode || !renderMode && !isDebugMode) {
2189
2466
  liveRenderAPIRef.current = null;
2190
2467
  return;
2191
2468
  }
@@ -2311,19 +2588,21 @@ function DocPlayerContent({
2311
2588
  coverBlock,
2312
2589
  doc,
2313
2590
  externalAudioController,
2314
- waitForRenderCommit
2591
+ waitForRenderCommit,
2592
+ isDashboardMode
2315
2593
  ]);
2316
- useEffect5(() => {
2594
+ useEffect6(() => {
2595
+ if (isDashboardMode) return;
2317
2596
  if (!renderMode && !isDebugMode || !containerRef.current) {
2318
2597
  onRenderAPIReady?.(null);
2319
2598
  return;
2320
2599
  }
2321
2600
  onRenderAPIReady?.(stableRenderAPI);
2322
2601
  return () => onRenderAPIReady?.(null);
2323
- }, [renderMode, isDebugMode, onRenderAPIReady, stableRenderAPI]);
2602
+ }, [renderMode, isDebugMode, isDashboardMode, onRenderAPIReady, stableRenderAPI]);
2324
2603
  const defaultMode = captionsEnabledProp === false ? "off" : captionStyle || "standard";
2325
2604
  const [captionMode, setCaptionMode] = useState5(defaultMode);
2326
- useEffect5(() => {
2605
+ useEffect6(() => {
2327
2606
  setCaptionMode(defaultMode);
2328
2607
  }, [defaultMode]);
2329
2608
  const captionsEnabled = captionMode !== "off";
@@ -2343,8 +2622,8 @@ function DocPlayerContent({
2343
2622
  });
2344
2623
  }, [onCaptionsToggle]);
2345
2624
  const hasCaptions = doc.captions && doc.captions.phrases.length > 0;
2346
- const segmentTitleMap = useMemo3(() => buildSegmentTitleMap(doc), [doc]);
2347
- const playbackState = useMemo3(
2625
+ const segmentTitleMap = useMemo4(() => buildSegmentTitleMap(doc), [doc]);
2626
+ const playbackState = useMemo4(
2348
2627
  () => ({
2349
2628
  isPlaying,
2350
2629
  currentTime,
@@ -2387,7 +2666,7 @@ function DocPlayerContent({
2387
2666
  expandedBlocks.length
2388
2667
  ]
2389
2668
  );
2390
- const playbackActions = useMemo3(
2669
+ const playbackActions = useMemo4(
2391
2670
  () => ({
2392
2671
  toggle: toggleWithTimelineMedia,
2393
2672
  restart,
@@ -2405,7 +2684,7 @@ function DocPlayerContent({
2405
2684
  onFullscreenToggle
2406
2685
  ]
2407
2686
  );
2408
- const slideNavActions = useMemo3(
2687
+ const slideNavActions = useMemo4(
2409
2688
  () => ({
2410
2689
  nextSlide: () => {
2411
2690
  if (slideshowHasCover && slideshowCoverVisible) {
@@ -2494,10 +2773,10 @@ function DocPlayerContent({
2494
2773
  onNext: handleSwipeNext,
2495
2774
  onPrev: handleSwipePrev
2496
2775
  });
2497
- useEffect5(() => {
2776
+ useEffect6(() => {
2498
2777
  onPlaybackStateChange?.(playbackState);
2499
2778
  }, [playbackState, onPlaybackStateChange]);
2500
- useEffect5(() => {
2779
+ useEffect6(() => {
2501
2780
  onControlsReady?.({ play: playWithTimelineMedia, pause, ...playbackActions });
2502
2781
  }, [playWithTimelineMedia, pause, playbackActions, onControlsReady]);
2503
2782
  const getBlockTitle = useCallback4((block) => {
@@ -2524,7 +2803,7 @@ function DocPlayerContent({
2524
2803
  }
2525
2804
  return block.id.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
2526
2805
  }, []);
2527
- const slideshowPickerItems = useMemo3(() => {
2806
+ const slideshowPickerItems = useMemo4(() => {
2528
2807
  const blockItems = expandedBlocks.map((block, index) => ({
2529
2808
  id: block.id,
2530
2809
  label: String(index + 1),
@@ -2540,7 +2819,7 @@ function DocPlayerContent({
2540
2819
  ...blockItems
2541
2820
  ];
2542
2821
  }, [coverBlock, expandedBlocks, getBlockTitle, slideshowHasCover]);
2543
- const blockMarkers = useMemo3(() => {
2822
+ const blockMarkers = useMemo4(() => {
2544
2823
  if (!totalDuration || !expandedBlocks.length) return [];
2545
2824
  let prevSegment = -1;
2546
2825
  return expandedBlocks.map((block, index) => {
@@ -2555,7 +2834,7 @@ function DocPlayerContent({
2555
2834
  };
2556
2835
  });
2557
2836
  }, [expandedBlocks, totalDuration, getBlockTitle]);
2558
- useEffect5(() => {
2837
+ useEffect6(() => {
2559
2838
  if (blockMarkers.length > 0) {
2560
2839
  onBlockMarkers?.(blockMarkers);
2561
2840
  }
@@ -2577,7 +2856,7 @@ function DocPlayerContent({
2577
2856
  ) && !isSlideshowToolbarTarget) {
2578
2857
  return;
2579
2858
  }
2580
- if (isLinearMode) return;
2859
+ if (isLinearMode || isDashboardMode) return;
2581
2860
  if (e.key === "f" || e.key === "F") {
2582
2861
  if (!onFullscreenToggle) return;
2583
2862
  e.preventDefault();
@@ -2629,6 +2908,7 @@ function DocPlayerContent({
2629
2908
  [
2630
2909
  isSlideshowMode,
2631
2910
  isLinearMode,
2911
+ isDashboardMode,
2632
2912
  toggleWithTimelineMedia,
2633
2913
  seekTo,
2634
2914
  slideNavActions,
@@ -2639,16 +2919,16 @@ function DocPlayerContent({
2639
2919
  (e) => handleKeyboardShortcut(e, false),
2640
2920
  [handleKeyboardShortcut]
2641
2921
  );
2642
- useEffect5(() => {
2643
- if (!globalKeyboardShortcuts || renderMode || isLinearMode) return;
2922
+ useEffect6(() => {
2923
+ if (!globalKeyboardShortcuts || renderMode || isLinearMode || isDashboardMode) return;
2644
2924
  const handleDocumentKeyDown = (event) => {
2645
2925
  handleKeyboardShortcut(event, true);
2646
2926
  };
2647
2927
  document.addEventListener("keydown", handleDocumentKeyDown);
2648
2928
  return () => document.removeEventListener("keydown", handleDocumentKeyDown);
2649
- }, [globalKeyboardShortcuts, handleKeyboardShortcut, isLinearMode, renderMode]);
2929
+ }, [globalKeyboardShortcuts, handleKeyboardShortcut, isDashboardMode, isLinearMode, renderMode]);
2650
2930
  if (isLinearMode) {
2651
- return /* @__PURE__ */ jsx7(
2931
+ return /* @__PURE__ */ jsx8(
2652
2932
  "div",
2653
2933
  {
2654
2934
  ref: containerRef,
@@ -2660,7 +2940,7 @@ function DocPlayerContent({
2660
2940
  height: "100%",
2661
2941
  overflow: "hidden"
2662
2942
  },
2663
- children: /* @__PURE__ */ jsx7(
2943
+ children: /* @__PURE__ */ jsx8(
2664
2944
  LinearDocView,
2665
2945
  {
2666
2946
  doc,
@@ -2677,7 +2957,41 @@ function DocPlayerContent({
2677
2957
  }
2678
2958
  );
2679
2959
  }
2680
- return /* @__PURE__ */ jsxs4(
2960
+ if (isDashboardMode) {
2961
+ return /* @__PURE__ */ jsx8(
2962
+ "div",
2963
+ {
2964
+ ref: containerRef,
2965
+ "data-player-id": playerId,
2966
+ className: "doc-player doc-player--dashboard",
2967
+ style: {
2968
+ position: "relative",
2969
+ width: "100%",
2970
+ aspectRatio: `${activeViewport.width} / ${activeViewport.height}`,
2971
+ margin: "0 auto",
2972
+ overflow: "hidden"
2973
+ },
2974
+ children: /* @__PURE__ */ jsx8(
2975
+ DashboardView,
2976
+ {
2977
+ doc,
2978
+ theme,
2979
+ viewport: activeViewport,
2980
+ layout: dashboardLayout,
2981
+ showTitle: dashboardShowTitle,
2982
+ style: dashboardStyle,
2983
+ documentTitle: dashboardDocumentTitle,
2984
+ basePath,
2985
+ animationsEnabled,
2986
+ muted: renderMode || muted,
2987
+ renderMode: renderMode || isDebugMode,
2988
+ onRenderAPIReady
2989
+ }
2990
+ )
2991
+ }
2992
+ );
2993
+ }
2994
+ return /* @__PURE__ */ jsxs5(
2681
2995
  "div",
2682
2996
  {
2683
2997
  ref: containerRef,
@@ -2705,8 +3019,8 @@ function DocPlayerContent({
2705
3019
  touchAction: swipeEnabled ? "pan-y" : void 0
2706
3020
  },
2707
3021
  children: [
2708
- /* @__PURE__ */ jsx7("audio", { ref: audioRef, preload: "auto", muted }),
2709
- /* @__PURE__ */ jsx7(
3022
+ /* @__PURE__ */ jsx8("audio", { ref: audioRef, preload: "auto", muted }),
3023
+ /* @__PURE__ */ jsx8(
2710
3024
  MediaClipLayer,
2711
3025
  {
2712
3026
  schedule: mediaSchedule,
@@ -2723,8 +3037,8 @@ function DocPlayerContent({
2723
3037
  pipFrameStyle
2724
3038
  }
2725
3039
  ),
2726
- /* @__PURE__ */ jsxs4("div", { className: "doc-player__viewport", children: [
2727
- showCoverBlock && coverBlock && /* @__PURE__ */ jsx7("div", { className: "doc-player__block doc-player__block--cover", children: /* @__PURE__ */ jsx7(
3040
+ /* @__PURE__ */ jsxs5("div", { className: "doc-player__viewport", children: [
3041
+ showCoverBlock && coverBlock && /* @__PURE__ */ jsx8("div", { className: "doc-player__block doc-player__block--cover", children: /* @__PURE__ */ jsx8(
2728
3042
  BlockRenderer,
2729
3043
  {
2730
3044
  block: coverBlock,
@@ -2741,7 +3055,7 @@ function DocPlayerContent({
2741
3055
  // reconciles one block's layers onto another's (templates reuse layer
2742
3056
  // ids like `title`/`background`), which would otherwise reuse stale
2743
3057
  // DOM / skip entrance animations mid-transition.
2744
- /* @__PURE__ */ jsx7("div", { className: "doc-player__block doc-player__block--previous", children: /* @__PURE__ */ jsx7(
3058
+ /* @__PURE__ */ jsx8("div", { className: "doc-player__block doc-player__block--previous", children: /* @__PURE__ */ jsx8(
2745
3059
  BlockRenderer,
2746
3060
  {
2747
3061
  block: previousBlock,
@@ -2755,7 +3069,7 @@ function DocPlayerContent({
2755
3069
  theme: effectiveTheme
2756
3070
  }
2757
3071
  ) }, previousBlock.id),
2758
- currentBlock && /* @__PURE__ */ jsx7(
3072
+ currentBlock && /* @__PURE__ */ jsx8(
2759
3073
  "div",
2760
3074
  {
2761
3075
  className: `doc-player__block doc-player__block--active${swipe.phase !== "idle" ? ` doc-player__block--${swipe.phase}` : ""}`,
@@ -2764,7 +3078,7 @@ function DocPlayerContent({
2764
3078
  ...swipe.phase !== "idle" ? { transform: `translateX(${swipe.offsetPx}px)` } : {},
2765
3079
  ...showCoverBlock ? { opacity: 0, pointerEvents: "none" } : {}
2766
3080
  } : void 0,
2767
- children: /* @__PURE__ */ jsx7(
3081
+ children: /* @__PURE__ */ jsx8(
2768
3082
  BlockRenderer,
2769
3083
  {
2770
3084
  block: currentBlock,
@@ -2781,7 +3095,7 @@ function DocPlayerContent({
2781
3095
  },
2782
3096
  currentBlock.id
2783
3097
  ),
2784
- hasCaptions && (renderMode ? captionsEnabled : true) && /* @__PURE__ */ jsx7(
3098
+ hasCaptions && (renderMode ? captionsEnabled : true) && /* @__PURE__ */ jsx8(
2785
3099
  CaptionOverlay,
2786
3100
  {
2787
3101
  captions: doc.captions,
@@ -2793,7 +3107,7 @@ function DocPlayerContent({
2793
3107
  viewport: activeViewport
2794
3108
  }
2795
3109
  ),
2796
- isDebugMode && /* @__PURE__ */ jsxs4(
3110
+ isDebugMode && /* @__PURE__ */ jsxs5(
2797
3111
  "div",
2798
3112
  {
2799
3113
  className: "doc-player__debug",
@@ -2814,27 +3128,27 @@ function DocPlayerContent({
2814
3128
  textAlign: "left"
2815
3129
  },
2816
3130
  children: [
2817
- /* @__PURE__ */ jsx7("div", { style: { color: "#ffcc00", fontWeight: "bold", marginBottom: "4px" }, children: "DEBUG MODE" }),
2818
- /* @__PURE__ */ jsxs4("div", { children: [
2819
- /* @__PURE__ */ jsx7("span", { style: { color: "#888" }, children: "template:" }),
3131
+ /* @__PURE__ */ jsx8("div", { style: { color: "#ffcc00", fontWeight: "bold", marginBottom: "4px" }, children: "DEBUG MODE" }),
3132
+ /* @__PURE__ */ jsxs5("div", { children: [
3133
+ /* @__PURE__ */ jsx8("span", { style: { color: "#888" }, children: "template:" }),
2820
3134
  " ",
2821
- /* @__PURE__ */ jsx7("span", { style: { color: "#ff6b6b" }, children: currentBlock?.template ?? "raw" })
3135
+ /* @__PURE__ */ jsx8("span", { style: { color: "#ff6b6b" }, children: currentBlock?.template ?? "raw" })
2822
3136
  ] }),
2823
- /* @__PURE__ */ jsxs4("div", { children: [
2824
- /* @__PURE__ */ jsx7("span", { style: { color: "#888" }, children: "block:" }),
3137
+ /* @__PURE__ */ jsxs5("div", { children: [
3138
+ /* @__PURE__ */ jsx8("span", { style: { color: "#888" }, children: "block:" }),
2825
3139
  " ",
2826
3140
  currentBlockIndex + 1,
2827
3141
  "/",
2828
3142
  expandedBlocks.length,
2829
3143
  " ",
2830
- /* @__PURE__ */ jsxs4("span", { style: { color: "#666" }, children: [
3144
+ /* @__PURE__ */ jsxs5("span", { style: { color: "#666" }, children: [
2831
3145
  "(",
2832
3146
  currentBlock?.id || "none",
2833
3147
  ")"
2834
3148
  ] })
2835
3149
  ] }),
2836
- /* @__PURE__ */ jsxs4("div", { children: [
2837
- /* @__PURE__ */ jsx7("span", { style: { color: "#888" }, children: "time:" }),
3150
+ /* @__PURE__ */ jsxs5("div", { children: [
3151
+ /* @__PURE__ */ jsx8("span", { style: { color: "#888" }, children: "time:" }),
2838
3152
  " ",
2839
3153
  currentTime.toFixed(2),
2840
3154
  "s /",
@@ -2842,7 +3156,7 @@ function DocPlayerContent({
2842
3156
  totalDuration.toFixed(1),
2843
3157
  "s",
2844
3158
  " ",
2845
- /* @__PURE__ */ jsxs4("span", { style: { color: "#666" }, children: [
3159
+ /* @__PURE__ */ jsxs5("span", { style: { color: "#666" }, children: [
2846
3160
  "(progress: ",
2847
3161
  (docProgress * 100).toFixed(1),
2848
3162
  "%, scriptDur: ",
@@ -2850,8 +3164,8 @@ function DocPlayerContent({
2850
3164
  ")"
2851
3165
  ] })
2852
3166
  ] }),
2853
- /* @__PURE__ */ jsxs4("div", { children: [
2854
- /* @__PURE__ */ jsx7("span", { style: { color: "#888" }, children: "blockTime:" }),
3167
+ /* @__PURE__ */ jsxs5("div", { children: [
3168
+ /* @__PURE__ */ jsx8("span", { style: { color: "#888" }, children: "blockTime:" }),
2855
3169
  " ",
2856
3170
  blockTime.toFixed(2),
2857
3171
  "s /",
@@ -2859,58 +3173,58 @@ function DocPlayerContent({
2859
3173
  (currentBlock?.duration || 0).toFixed(1),
2860
3174
  "s"
2861
3175
  ] }),
2862
- /* @__PURE__ */ jsxs4("div", { children: [
2863
- /* @__PURE__ */ jsx7("span", { style: { color: "#888" }, children: "segment:" }),
3176
+ /* @__PURE__ */ jsxs5("div", { children: [
3177
+ /* @__PURE__ */ jsx8("span", { style: { color: "#888" }, children: "segment:" }),
2864
3178
  " ",
2865
3179
  currentSegment,
2866
3180
  "/",
2867
3181
  doc.audio.segments.length - 1,
2868
3182
  " ",
2869
- /* @__PURE__ */ jsxs4("span", { style: { color: "#666" }, children: [
3183
+ /* @__PURE__ */ jsxs5("span", { style: { color: "#666" }, children: [
2870
3184
  "(",
2871
3185
  doc.audio.segments[currentSegment]?.name || "none",
2872
3186
  ")"
2873
3187
  ] })
2874
3188
  ] }),
2875
- /* @__PURE__ */ jsxs4("div", { children: [
2876
- /* @__PURE__ */ jsx7("span", { style: { color: "#888" }, children: "viewport:" }),
3189
+ /* @__PURE__ */ jsxs5("div", { children: [
3190
+ /* @__PURE__ */ jsx8("span", { style: { color: "#888" }, children: "viewport:" }),
2877
3191
  " ",
2878
3192
  activeViewport.name || `${activeViewport.width}x${activeViewport.height}`,
2879
3193
  " ",
2880
- /* @__PURE__ */ jsxs4("span", { style: { color: "#666" }, children: [
3194
+ /* @__PURE__ */ jsxs5("span", { style: { color: "#666" }, children: [
2881
3195
  "(",
2882
3196
  activeOrientation,
2883
3197
  ")"
2884
3198
  ] })
2885
3199
  ] }),
2886
- /* @__PURE__ */ jsxs4("div", { children: [
2887
- /* @__PURE__ */ jsx7("span", { style: { color: "#888" }, children: "playing:" }),
3200
+ /* @__PURE__ */ jsxs5("div", { children: [
3201
+ /* @__PURE__ */ jsx8("span", { style: { color: "#888" }, children: "playing:" }),
2888
3202
  " ",
2889
- /* @__PURE__ */ jsx7("span", { style: { color: isPlaying ? "#4ade80" : "#f87171" }, children: isPlaying ? "yes" : "no" }),
2890
- showCoverBlock && /* @__PURE__ */ jsx7("span", { style: { color: "#60a5fa" }, children: " (cover)" })
3203
+ /* @__PURE__ */ jsx8("span", { style: { color: isPlaying ? "#4ade80" : "#f87171" }, children: isPlaying ? "yes" : "no" }),
3204
+ showCoverBlock && /* @__PURE__ */ jsx8("span", { style: { color: "#60a5fa" }, children: " (cover)" })
2891
3205
  ] }),
2892
3206
  hasCaptions && (() => {
2893
3207
  const debugPhrase = getCaptionAtTime2(doc.captions, currentTime);
2894
3208
  const debugEnabled = captionsEnabled && (isPlaying || currentTime > 0);
2895
- return /* @__PURE__ */ jsxs4(Fragment2, { children: [
2896
- /* @__PURE__ */ jsxs4("div", { children: [
2897
- /* @__PURE__ */ jsx7("span", { style: { color: "#888" }, children: "captions:" }),
3209
+ return /* @__PURE__ */ jsxs5(Fragment3, { children: [
3210
+ /* @__PURE__ */ jsxs5("div", { children: [
3211
+ /* @__PURE__ */ jsx8("span", { style: { color: "#888" }, children: "captions:" }),
2898
3212
  " ",
2899
3213
  doc.captions?.phrases.length || 0,
2900
3214
  " phrases",
2901
3215
  " ",
2902
- /* @__PURE__ */ jsxs4("span", { style: { color: captionsEnabled ? "#4ade80" : "#666" }, children: [
3216
+ /* @__PURE__ */ jsxs5("span", { style: { color: captionsEnabled ? "#4ade80" : "#666" }, children: [
2903
3217
  "(",
2904
3218
  captionsEnabled ? "on" : "off",
2905
3219
  ")"
2906
3220
  ] })
2907
3221
  ] }),
2908
- /* @__PURE__ */ jsxs4("div", { children: [
2909
- /* @__PURE__ */ jsx7("span", { style: { color: "#888" }, children: "cc.enabled:" }),
3222
+ /* @__PURE__ */ jsxs5("div", { children: [
3223
+ /* @__PURE__ */ jsx8("span", { style: { color: "#888" }, children: "cc.enabled:" }),
2910
3224
  " ",
2911
- /* @__PURE__ */ jsx7("span", { style: { color: debugEnabled ? "#4ade80" : "#f87171" }, children: String(debugEnabled) }),
3225
+ /* @__PURE__ */ jsx8("span", { style: { color: debugEnabled ? "#4ade80" : "#f87171" }, children: String(debugEnabled) }),
2912
3226
  " ",
2913
- /* @__PURE__ */ jsxs4("span", { style: { color: "#666" }, children: [
3227
+ /* @__PURE__ */ jsxs5("span", { style: { color: "#666" }, children: [
2914
3228
  "(playing=",
2915
3229
  String(isPlaying),
2916
3230
  " t>0=",
@@ -2918,15 +3232,15 @@ function DocPlayerContent({
2918
3232
  ")"
2919
3233
  ] })
2920
3234
  ] }),
2921
- /* @__PURE__ */ jsxs4("div", { children: [
2922
- /* @__PURE__ */ jsx7("span", { style: { color: "#888" }, children: "cc.phrase:" }),
3235
+ /* @__PURE__ */ jsxs5("div", { children: [
3236
+ /* @__PURE__ */ jsx8("span", { style: { color: "#888" }, children: "cc.phrase:" }),
2923
3237
  " ",
2924
- /* @__PURE__ */ jsx7("span", { style: { color: debugPhrase ? "#4ade80" : "#f87171" }, children: debugPhrase ? `"${debugPhrase.text.slice(0, 30)}..."` : "null" })
3238
+ /* @__PURE__ */ jsx8("span", { style: { color: debugPhrase ? "#4ade80" : "#f87171" }, children: debugPhrase ? `"${debugPhrase.text.slice(0, 30)}..."` : "null" })
2925
3239
  ] }),
2926
- debugPhrase && /* @__PURE__ */ jsxs4("div", { children: [
2927
- /* @__PURE__ */ jsx7("span", { style: { color: "#888" }, children: "cc.range:" }),
3240
+ debugPhrase && /* @__PURE__ */ jsxs5("div", { children: [
3241
+ /* @__PURE__ */ jsx8("span", { style: { color: "#888" }, children: "cc.range:" }),
2928
3242
  " ",
2929
- /* @__PURE__ */ jsxs4("span", { style: { color: "#60a5fa" }, children: [
3243
+ /* @__PURE__ */ jsxs5("span", { style: { color: "#60a5fa" }, children: [
2930
3244
  debugPhrase.startTime.toFixed(2),
2931
3245
  "-",
2932
3246
  debugPhrase.endTime.toFixed(2)
@@ -2938,7 +3252,7 @@ function DocPlayerContent({
2938
3252
  }
2939
3253
  )
2940
3254
  ] }),
2941
- !isAvailable && unavailableMessage && /* @__PURE__ */ jsxs4(
3255
+ !isAvailable && unavailableMessage && /* @__PURE__ */ jsxs5(
2942
3256
  "div",
2943
3257
  {
2944
3258
  className: "doc-player__unavailable",
@@ -2959,12 +3273,12 @@ function DocPlayerContent({
2959
3273
  zIndex: 50
2960
3274
  },
2961
3275
  children: [
2962
- /* @__PURE__ */ jsx7("span", { style: { fontSize: "32px" }, children: "\u{1F50A}" }),
2963
- /* @__PURE__ */ jsx7("span", { children: unavailableMessage })
3276
+ /* @__PURE__ */ jsx8("span", { style: { fontSize: "32px" }, children: "\u{1F50A}" }),
3277
+ /* @__PURE__ */ jsx8("span", { children: unavailableMessage })
2964
3278
  ]
2965
3279
  }
2966
3280
  ),
2967
- !renderMode && !isSlideshowMode && showControls && /* @__PURE__ */ jsx7(
3281
+ !renderMode && !isSlideshowMode && showControls && /* @__PURE__ */ jsx8(
2968
3282
  DocControlsOverlay,
2969
3283
  {
2970
3284
  state: playbackState,
@@ -2974,7 +3288,7 @@ function DocPlayerContent({
2974
3288
  getBlockTitle
2975
3289
  }
2976
3290
  ),
2977
- !renderMode && !isSlideshowMode && !showControls && showScrubber && /* @__PURE__ */ jsx7(
3291
+ !renderMode && !isSlideshowMode && !showControls && showScrubber && /* @__PURE__ */ jsx8(
2978
3292
  "div",
2979
3293
  {
2980
3294
  className: "doc-player__scrubber",
@@ -2989,7 +3303,7 @@ function DocPlayerContent({
2989
3303
  alignItems: "center",
2990
3304
  zIndex: 100
2991
3305
  },
2992
- children: /* @__PURE__ */ jsx7(
3306
+ children: /* @__PURE__ */ jsx8(
2993
3307
  DocProgressBar,
2994
3308
  {
2995
3309
  state: playbackState,
@@ -3001,7 +3315,7 @@ function DocPlayerContent({
3001
3315
  )
3002
3316
  }
3003
3317
  ),
3004
- !renderMode && isSlideshowMode && showControls && /* @__PURE__ */ jsx7(
3318
+ !renderMode && isSlideshowMode && showControls && /* @__PURE__ */ jsx8(
3005
3319
  DocControlsSlideshow,
3006
3320
  {
3007
3321
  state: playbackState,
@@ -3011,14 +3325,14 @@ function DocPlayerContent({
3011
3325
  onPickerOpenChange: setIsSlideshowPickerOpen
3012
3326
  }
3013
3327
  ),
3014
- !isSlideshowMode && tapFeedback && /* @__PURE__ */ jsx7("div", { className: "doc-player__tap-feedback", children: /* @__PURE__ */ jsx7("svg", { viewBox: "0 0 24 24", fill: "white", width: "48", height: "48", children: tapFeedback === "pause" ? /* @__PURE__ */ jsx7("path", { d: "M6 19h4V5H6v14zm8-14v14h4V5h-4z" }) : /* @__PURE__ */ jsx7("path", { d: "M8 5v14l11-7z" }) }) }, tapFeedback)
3328
+ !isSlideshowMode && tapFeedback && /* @__PURE__ */ jsx8("div", { className: "doc-player__tap-feedback", children: /* @__PURE__ */ jsx8("svg", { viewBox: "0 0 24 24", fill: "white", width: "48", height: "48", children: tapFeedback === "pause" ? /* @__PURE__ */ jsx8("path", { d: "M6 19h4V5H6v14zm8-14v14h4V5h-4z" }) : /* @__PURE__ */ jsx8("path", { d: "M8 5v14l11-7z" }) }) }, tapFeedback)
3015
3329
  ]
3016
3330
  }
3017
3331
  );
3018
3332
  }
3019
3333
 
3020
3334
  // src/DocControlsBottom.tsx
3021
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
3335
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
3022
3336
  function DocControlsBottom({
3023
3337
  state,
3024
3338
  actions,
@@ -3026,32 +3340,32 @@ function DocControlsBottom({
3026
3340
  expandedBlocks,
3027
3341
  getBlockTitle
3028
3342
  }) {
3029
- return /* @__PURE__ */ jsxs5("div", { className: "doc-controls-bottom", children: [
3030
- /* @__PURE__ */ jsx8(
3343
+ return /* @__PURE__ */ jsxs6("div", { className: "doc-controls-bottom", children: [
3344
+ /* @__PURE__ */ jsx9(
3031
3345
  "button",
3032
3346
  {
3033
3347
  className: "bottom-ctrl-btn",
3034
3348
  onClick: actions.restart,
3035
3349
  title: "Restart",
3036
3350
  "aria-label": "Restart from beginning",
3037
- children: /* @__PURE__ */ jsx8("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ jsx8("path", { d: "M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z" }) })
3351
+ children: /* @__PURE__ */ jsx9("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ jsx9("path", { d: "M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z" }) })
3038
3352
  }
3039
3353
  ),
3040
- /* @__PURE__ */ jsx8(
3354
+ /* @__PURE__ */ jsx9(
3041
3355
  "button",
3042
3356
  {
3043
3357
  className: "bottom-ctrl-btn bottom-play-btn",
3044
3358
  onClick: actions.toggle,
3045
3359
  "aria-label": state.isPlaying ? "Pause" : "Play",
3046
- children: state.isPlaying ? /* @__PURE__ */ jsx8("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx8("path", { d: "M6 19h4V5H6v14zm8-14v14h4V5h-4z" }) }) : /* @__PURE__ */ jsx8("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx8("path", { d: "M8 5v14l11-7z" }) })
3360
+ children: state.isPlaying ? /* @__PURE__ */ jsx9("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx9("path", { d: "M6 19h4V5H6v14zm8-14v14h4V5h-4z" }) }) : /* @__PURE__ */ jsx9("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx9("path", { d: "M8 5v14l11-7z" }) })
3047
3361
  }
3048
3362
  ),
3049
- /* @__PURE__ */ jsxs5("span", { className: "bottom-time", children: [
3363
+ /* @__PURE__ */ jsxs6("span", { className: "bottom-time", children: [
3050
3364
  formatTime(state.currentTime),
3051
3365
  " / ",
3052
3366
  formatTime(state.totalDuration)
3053
3367
  ] }),
3054
- /* @__PURE__ */ jsx8(
3368
+ /* @__PURE__ */ jsx9(
3055
3369
  DocProgressBar,
3056
3370
  {
3057
3371
  state,
@@ -3061,92 +3375,92 @@ function DocControlsBottom({
3061
3375
  getBlockTitle
3062
3376
  }
3063
3377
  ),
3064
- /* @__PURE__ */ jsxs5("span", { className: "bottom-segment", children: [
3378
+ /* @__PURE__ */ jsxs6("span", { className: "bottom-segment", children: [
3065
3379
  state.currentBlockIndex + 1,
3066
3380
  "/",
3067
3381
  state.totalBlocks
3068
3382
  ] }),
3069
- state.hasCaptions && /* @__PURE__ */ jsx8(
3383
+ state.hasCaptions && /* @__PURE__ */ jsx9(
3070
3384
  "button",
3071
3385
  {
3072
3386
  className: `bottom-ctrl-btn ${state.captionMode !== "off" ? "bottom-ctrl-btn--active" : ""}`,
3073
3387
  onClick: () => actions.cycleCaptionMode(),
3074
3388
  title: state.captionMode === "off" ? "Captions: Off" : state.captionMode === "standard" ? "Captions: Standard" : "Captions: Social",
3075
3389
  "aria-label": "Cycle caption style",
3076
- children: /* @__PURE__ */ jsx8("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ jsx8("path", { d: "M19 4H5a2 2 0 00-2 2v12a2 2 0 002 2h14a2 2 0 002-2V6a2 2 0 00-2-2zm-8 7H9.5v-.5h-2v3h2V13H11v1a1 1 0 01-1 1H7a1 1 0 01-1-1v-4a1 1 0 011-1h3a1 1 0 011 1v1zm7 0h-1.5v-.5h-2v3h2V13H18v1a1 1 0 01-1 1h-3a1 1 0 01-1-1v-4a1 1 0 011-1h3a1 1 0 011 1v1z" }) })
3390
+ children: /* @__PURE__ */ jsx9("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ jsx9("path", { d: "M19 4H5a2 2 0 00-2 2v12a2 2 0 002 2h14a2 2 0 002-2V6a2 2 0 00-2-2zm-8 7H9.5v-.5h-2v3h2V13H11v1a1 1 0 01-1 1H7a1 1 0 01-1-1v-4a1 1 0 011-1h3a1 1 0 011 1v1zm7 0h-1.5v-.5h-2v3h2V13H18v1a1 1 0 01-1 1h-3a1 1 0 01-1-1v-4a1 1 0 011-1h3a1 1 0 011 1v1z" }) })
3077
3391
  }
3078
3392
  ),
3079
- actions.toggleFullscreen && /* @__PURE__ */ jsx8(
3393
+ actions.toggleFullscreen && /* @__PURE__ */ jsx9(
3080
3394
  "button",
3081
3395
  {
3082
3396
  className: `bottom-ctrl-btn ${state.isFullscreen ? "bottom-ctrl-btn--active" : ""}`,
3083
3397
  onClick: actions.toggleFullscreen,
3084
3398
  title: state.isFullscreen ? "Exit fullscreen (F)" : "Fullscreen (F)",
3085
3399
  "aria-label": state.isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
3086
- children: state.isFullscreen ? /* @__PURE__ */ jsx8("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ jsx8("path", { d: "M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z" }) }) : /* @__PURE__ */ jsx8("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ jsx8("path", { d: "M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" }) })
3400
+ children: state.isFullscreen ? /* @__PURE__ */ jsx9("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ jsx9("path", { d: "M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z" }) }) : /* @__PURE__ */ jsx9("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ jsx9("path", { d: "M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" }) })
3087
3401
  }
3088
3402
  )
3089
3403
  ] });
3090
3404
  }
3091
3405
 
3092
3406
  // src/DocControlsSidebar.tsx
3093
- import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
3407
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
3094
3408
  function DocControlsSidebar({ state, actions }) {
3095
- return /* @__PURE__ */ jsxs6("div", { className: "doc-controls-sidebar", children: [
3096
- /* @__PURE__ */ jsx9(
3409
+ return /* @__PURE__ */ jsxs7("div", { className: "doc-controls-sidebar", children: [
3410
+ /* @__PURE__ */ jsx10(
3097
3411
  "button",
3098
3412
  {
3099
3413
  className: "sidebar-ctrl-btn",
3100
3414
  onClick: actions.restart,
3101
3415
  title: "Restart",
3102
3416
  "aria-label": "Restart from beginning",
3103
- children: /* @__PURE__ */ jsx9("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx9("path", { d: "M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z" }) })
3417
+ children: /* @__PURE__ */ jsx10("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx10("path", { d: "M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z" }) })
3104
3418
  }
3105
3419
  ),
3106
- /* @__PURE__ */ jsx9(
3420
+ /* @__PURE__ */ jsx10(
3107
3421
  "button",
3108
3422
  {
3109
3423
  className: "sidebar-ctrl-btn sidebar-play-btn",
3110
3424
  onClick: actions.toggle,
3111
3425
  "aria-label": state.isPlaying ? "Pause" : "Play",
3112
- children: state.isPlaying ? /* @__PURE__ */ jsx9("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "22", height: "22", children: /* @__PURE__ */ jsx9("path", { d: "M6 19h4V5H6v14zm8-14v14h4V5h-4z" }) }) : /* @__PURE__ */ jsx9("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "22", height: "22", children: /* @__PURE__ */ jsx9("path", { d: "M8 5v14l11-7z" }) })
3426
+ children: state.isPlaying ? /* @__PURE__ */ jsx10("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "22", height: "22", children: /* @__PURE__ */ jsx10("path", { d: "M6 19h4V5H6v14zm8-14v14h4V5h-4z" }) }) : /* @__PURE__ */ jsx10("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "22", height: "22", children: /* @__PURE__ */ jsx10("path", { d: "M8 5v14l11-7z" }) })
3113
3427
  }
3114
3428
  ),
3115
- /* @__PURE__ */ jsxs6("div", { className: "sidebar-time", children: [
3116
- /* @__PURE__ */ jsx9("div", { children: formatTime(state.currentTime) }),
3117
- /* @__PURE__ */ jsx9("div", { className: "sidebar-time-total", children: formatTime(state.totalDuration) })
3429
+ /* @__PURE__ */ jsxs7("div", { className: "sidebar-time", children: [
3430
+ /* @__PURE__ */ jsx10("div", { children: formatTime(state.currentTime) }),
3431
+ /* @__PURE__ */ jsx10("div", { className: "sidebar-time-total", children: formatTime(state.totalDuration) })
3118
3432
  ] }),
3119
- /* @__PURE__ */ jsxs6("div", { className: "sidebar-segment", children: [
3433
+ /* @__PURE__ */ jsxs7("div", { className: "sidebar-segment", children: [
3120
3434
  state.currentBlockIndex + 1,
3121
3435
  "/",
3122
3436
  state.totalBlocks
3123
3437
  ] }),
3124
- state.hasCaptions && /* @__PURE__ */ jsx9(
3438
+ state.hasCaptions && /* @__PURE__ */ jsx10(
3125
3439
  "button",
3126
3440
  {
3127
3441
  className: `sidebar-ctrl-btn ${state.captionMode !== "off" ? "sidebar-ctrl-btn--active" : ""}`,
3128
3442
  onClick: () => actions.cycleCaptionMode(),
3129
3443
  title: state.captionMode === "off" ? "Captions: Off" : state.captionMode === "standard" ? "Captions: Standard" : "Captions: Social",
3130
3444
  "aria-label": "Cycle caption style",
3131
- children: /* @__PURE__ */ jsx9("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx9("path", { d: "M19 4H5a2 2 0 00-2 2v12a2 2 0 002 2h14a2 2 0 002-2V6a2 2 0 00-2-2zm-8 7H9.5v-.5h-2v3h2V13H11v1a1 1 0 01-1 1H7a1 1 0 01-1-1v-4a1 1 0 011-1h3a1 1 0 011 1v1zm7 0h-1.5v-.5h-2v3h2V13H18v1a1 1 0 01-1 1h-3a1 1 0 01-1-1v-4a1 1 0 011-1h3a1 1 0 011 1v1z" }) })
3445
+ children: /* @__PURE__ */ jsx10("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx10("path", { d: "M19 4H5a2 2 0 00-2 2v12a2 2 0 002 2h14a2 2 0 002-2V6a2 2 0 00-2-2zm-8 7H9.5v-.5h-2v3h2V13H11v1a1 1 0 01-1 1H7a1 1 0 01-1-1v-4a1 1 0 011-1h3a1 1 0 011 1v1zm7 0h-1.5v-.5h-2v3h2V13H18v1a1 1 0 01-1 1h-3a1 1 0 01-1-1v-4a1 1 0 011-1h3a1 1 0 011 1v1z" }) })
3132
3446
  }
3133
3447
  ),
3134
- actions.toggleFullscreen && /* @__PURE__ */ jsx9(
3448
+ actions.toggleFullscreen && /* @__PURE__ */ jsx10(
3135
3449
  "button",
3136
3450
  {
3137
3451
  className: `sidebar-ctrl-btn ${state.isFullscreen ? "sidebar-ctrl-btn--active" : ""}`,
3138
3452
  onClick: actions.toggleFullscreen,
3139
3453
  title: state.isFullscreen ? "Exit fullscreen (F)" : "Fullscreen (F)",
3140
3454
  "aria-label": state.isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
3141
- children: state.isFullscreen ? /* @__PURE__ */ jsx9("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx9("path", { d: "M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z" }) }) : /* @__PURE__ */ jsx9("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx9("path", { d: "M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" }) })
3455
+ children: state.isFullscreen ? /* @__PURE__ */ jsx10("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx10("path", { d: "M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z" }) }) : /* @__PURE__ */ jsx10("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx10("path", { d: "M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" }) })
3142
3456
  }
3143
3457
  )
3144
3458
  ] });
3145
3459
  }
3146
3460
 
3147
3461
  // src/DocPlayerWithSidebar.tsx
3148
- import { useRef as useRef6, useState as useState6, useCallback as useCallback5, useEffect as useEffect6 } from "react";
3149
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
3462
+ import { useRef as useRef7, useState as useState6, useCallback as useCallback5, useEffect as useEffect7 } from "react";
3463
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
3150
3464
  var DEFAULT_STATE = {
3151
3465
  isPlaying: false,
3152
3466
  currentTime: 0,
@@ -3178,9 +3492,9 @@ function DocPlayerWithSidebar({
3178
3492
  onPlayingChange,
3179
3493
  theme
3180
3494
  }) {
3181
- const stateRef = useRef6(DEFAULT_STATE);
3182
- const actionsRef = useRef6(null);
3183
- const wasPlayingRef = useRef6(false);
3495
+ const stateRef = useRef7(DEFAULT_STATE);
3496
+ const actionsRef = useRef7(null);
3497
+ const wasPlayingRef = useRef7(false);
3184
3498
  const [, setTick] = useState6(0);
3185
3499
  const handleStateChange = useCallback5(
3186
3500
  (state) => {
@@ -3201,15 +3515,15 @@ function DocPlayerWithSidebar({
3201
3515
  },
3202
3516
  []
3203
3517
  );
3204
- useEffect6(() => {
3518
+ useEffect7(() => {
3205
3519
  const interval = setInterval(() => {
3206
3520
  if (!stateRef.current.isPlaying) return;
3207
3521
  setTick((t) => t + 1);
3208
3522
  }, 250);
3209
3523
  return () => clearInterval(interval);
3210
3524
  }, []);
3211
- return /* @__PURE__ */ jsxs7("div", { className: "doc-player-sidebar-layout", children: [
3212
- /* @__PURE__ */ jsx10("div", { className: "doc-player-sidebar-layout__video", children: /* @__PURE__ */ jsx10(
3525
+ return /* @__PURE__ */ jsxs8("div", { className: "doc-player-sidebar-layout", children: [
3526
+ /* @__PURE__ */ jsx11("div", { className: "doc-player-sidebar-layout__video", children: /* @__PURE__ */ jsx11(
3213
3527
  DocPlayer,
3214
3528
  {
3215
3529
  doc,
@@ -3232,7 +3546,7 @@ function DocPlayerWithSidebar({
3232
3546
  forceViewport
3233
3547
  }
3234
3548
  ) }),
3235
- actionsRef.current && /* @__PURE__ */ jsx10(DocControlsSidebar, { state: stateRef.current, actions: actionsRef.current })
3549
+ actionsRef.current && /* @__PURE__ */ jsx11(DocControlsSidebar, { state: stateRef.current, actions: actionsRef.current })
3236
3550
  ] });
3237
3551
  }
3238
3552
 
@@ -3245,6 +3559,7 @@ export {
3245
3559
  DocProgressBar,
3246
3560
  DocControlsOverlay,
3247
3561
  DocControlsSlideshow,
3562
+ DashboardView,
3248
3563
  resolveDocPlayerAppearance,
3249
3564
  DocPlayer,
3250
3565
  DocControlsBottom,