@bendyline/squisq-react 2.7.2 → 2.9.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.
- package/dist/{chunk-KXYE4AGL.js → chunk-2Y7F3S6M.js} +1050 -200
- package/dist/{chunk-UJEHDVQO.js → chunk-G6FVNYNW.js} +2 -1
- package/dist/{chunk-IQGW6SA6.js → chunk-NGQQKH7J.js} +1 -1
- package/dist/index.d.ts +53 -7
- package/dist/index.js +9 -3
- package/dist/layers/index.js +1 -1
- package/dist/page/index.js +2 -2
- package/dist/player/index.d.ts +48 -5
- package/dist/player/index.js +7 -3
- package/dist/squisq-player.full.global.js +437 -434
- package/dist/squisq-player.global.js +68 -65
- package/dist/standalone-source.js +1 -1
- package/dist/styles/index.css +312 -0
- package/package.json +2 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BlockRenderer,
|
|
3
3
|
LinearDocView
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-NGQQKH7J.js";
|
|
5
5
|
import {
|
|
6
6
|
useAudioSync,
|
|
7
7
|
useDocPlayback,
|
|
@@ -11,6 +11,9 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
useAutoSurface
|
|
13
13
|
} from "./chunk-TT6ENR6T.js";
|
|
14
|
+
import {
|
|
15
|
+
MarkdownRenderer
|
|
16
|
+
} from "./chunk-ESI3P77P.js";
|
|
14
17
|
import {
|
|
15
18
|
useMediaProvider,
|
|
16
19
|
useMediaUrl,
|
|
@@ -1242,10 +1245,797 @@ function DocControlsSlideshow({
|
|
|
1242
1245
|
);
|
|
1243
1246
|
}
|
|
1244
1247
|
|
|
1248
|
+
// src/DashboardView.tsx
|
|
1249
|
+
import { Fragment as Fragment2, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef4 } from "react";
|
|
1250
|
+
import { materializeDashboard, resolveThemeForDoc, VIEWPORT_PRESETS } from "@bendyline/squisq/doc";
|
|
1251
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1252
|
+
async function waitForDashboardAssets(root) {
|
|
1253
|
+
if (typeof document !== "undefined" && document.fonts?.ready) {
|
|
1254
|
+
try {
|
|
1255
|
+
await document.fonts.ready;
|
|
1256
|
+
} catch {
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
const images = Array.from(root.querySelectorAll("img"));
|
|
1260
|
+
await Promise.allSettled(
|
|
1261
|
+
images.map((img) => {
|
|
1262
|
+
if (img.complete) return Promise.resolve();
|
|
1263
|
+
if (typeof img.decode === "function") return img.decode().catch(() => void 0);
|
|
1264
|
+
return new Promise((resolve) => {
|
|
1265
|
+
img.addEventListener("load", () => resolve(), { once: true });
|
|
1266
|
+
img.addEventListener("error", () => resolve(), { once: true });
|
|
1267
|
+
});
|
|
1268
|
+
})
|
|
1269
|
+
);
|
|
1270
|
+
await new Promise((resolve) => {
|
|
1271
|
+
if (typeof requestAnimationFrame === "function") {
|
|
1272
|
+
requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
|
|
1273
|
+
} else {
|
|
1274
|
+
setTimeout(resolve, 0);
|
|
1275
|
+
}
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
function syntheticBlock(id, layers) {
|
|
1279
|
+
return { id, startTime: 0, duration: 0, audioSegment: 0, layers };
|
|
1280
|
+
}
|
|
1281
|
+
function DashboardView({
|
|
1282
|
+
doc,
|
|
1283
|
+
theme,
|
|
1284
|
+
viewport,
|
|
1285
|
+
layout,
|
|
1286
|
+
showTitle,
|
|
1287
|
+
style,
|
|
1288
|
+
documentTitle,
|
|
1289
|
+
basePath = ".",
|
|
1290
|
+
animationsEnabled = true,
|
|
1291
|
+
muted = true,
|
|
1292
|
+
renderMode = false,
|
|
1293
|
+
onRenderAPIReady,
|
|
1294
|
+
className
|
|
1295
|
+
}) {
|
|
1296
|
+
const rootRef = useRef4(null);
|
|
1297
|
+
const activeTheme = useMemo3(() => theme ?? resolveThemeForDoc(doc), [theme, doc]);
|
|
1298
|
+
const activeViewport = viewport ?? VIEWPORT_PRESETS.landscape;
|
|
1299
|
+
const materialization = useMemo3(
|
|
1300
|
+
() => materializeDashboard(doc, {
|
|
1301
|
+
theme: activeTheme,
|
|
1302
|
+
viewport: activeViewport,
|
|
1303
|
+
layout,
|
|
1304
|
+
showTitle,
|
|
1305
|
+
style,
|
|
1306
|
+
documentTitle
|
|
1307
|
+
}),
|
|
1308
|
+
[doc, activeTheme, activeViewport, layout, showTitle, style, documentTitle]
|
|
1309
|
+
);
|
|
1310
|
+
const backdropBottom = useMemo3(
|
|
1311
|
+
() => syntheticBlock("dashboard-backdrop-bottom", materialization.backdrop.bottomLayers),
|
|
1312
|
+
[materialization]
|
|
1313
|
+
);
|
|
1314
|
+
const backdropTop = useMemo3(
|
|
1315
|
+
() => materialization.backdrop.topLayers.length > 0 ? syntheticBlock("dashboard-backdrop-top", materialization.backdrop.topLayers) : null,
|
|
1316
|
+
[materialization]
|
|
1317
|
+
);
|
|
1318
|
+
const titleBlock = useMemo3(
|
|
1319
|
+
() => materialization.title ? syntheticBlock("dashboard-title-band", materialization.title.layers) : null,
|
|
1320
|
+
[materialization]
|
|
1321
|
+
);
|
|
1322
|
+
useEffect4(() => {
|
|
1323
|
+
if (!renderMode || !onRenderAPIReady) return;
|
|
1324
|
+
const api = {
|
|
1325
|
+
seekTo: async () => {
|
|
1326
|
+
const root = rootRef.current;
|
|
1327
|
+
if (root) await waitForDashboardAssets(root);
|
|
1328
|
+
},
|
|
1329
|
+
getRenderedTime: () => 0,
|
|
1330
|
+
getDuration: () => 0,
|
|
1331
|
+
getBlocks: () => materialization.cells.map((cell) => ({
|
|
1332
|
+
id: String(cell.block.id),
|
|
1333
|
+
template: cell.block.template ?? "content",
|
|
1334
|
+
startTime: 0,
|
|
1335
|
+
duration: 0
|
|
1336
|
+
})),
|
|
1337
|
+
getAudioSegments: () => [],
|
|
1338
|
+
getCaptions: () => [],
|
|
1339
|
+
getChapters: () => [],
|
|
1340
|
+
showCover: async () => {
|
|
1341
|
+
},
|
|
1342
|
+
hideCover: async () => {
|
|
1343
|
+
},
|
|
1344
|
+
hasCoverBlock: () => false
|
|
1345
|
+
};
|
|
1346
|
+
onRenderAPIReady(api);
|
|
1347
|
+
return () => onRenderAPIReady(null);
|
|
1348
|
+
}, [renderMode, onRenderAPIReady, materialization]);
|
|
1349
|
+
const canvasDimensions = { width: activeViewport.width, height: activeViewport.height };
|
|
1350
|
+
const coverStyle = { position: "absolute", inset: 0 };
|
|
1351
|
+
const canvasStyle = {
|
|
1352
|
+
position: "relative",
|
|
1353
|
+
width: "var(--squisq-dashboard-fit-width, 100%)",
|
|
1354
|
+
aspectRatio: `${activeViewport.width} / ${activeViewport.height}`,
|
|
1355
|
+
overflow: "hidden",
|
|
1356
|
+
// The style variant owns the canvas fill: card styles tint it away
|
|
1357
|
+
// from the card surface so cards read as raised.
|
|
1358
|
+
background: materialization.backdrop.fill,
|
|
1359
|
+
margin: "0 auto",
|
|
1360
|
+
"--squisq-dashboard-aspect": (activeViewport.width / activeViewport.height).toFixed(6)
|
|
1361
|
+
};
|
|
1362
|
+
return /* @__PURE__ */ jsxs4(
|
|
1363
|
+
"div",
|
|
1364
|
+
{
|
|
1365
|
+
ref: rootRef,
|
|
1366
|
+
className: className ? `squisq-dashboard ${className}` : "squisq-dashboard",
|
|
1367
|
+
"data-dashboard-layout": materialization.layout.name,
|
|
1368
|
+
"data-dashboard-style": materialization.style,
|
|
1369
|
+
style: canvasStyle,
|
|
1370
|
+
children: [
|
|
1371
|
+
/* @__PURE__ */ jsx7("div", { style: coverStyle, "aria-hidden": "true", children: /* @__PURE__ */ jsx7(
|
|
1372
|
+
BlockRenderer,
|
|
1373
|
+
{
|
|
1374
|
+
block: backdropBottom,
|
|
1375
|
+
blockTime: 0,
|
|
1376
|
+
basePath,
|
|
1377
|
+
viewport: canvasDimensions,
|
|
1378
|
+
isPlaying: false,
|
|
1379
|
+
muted: true,
|
|
1380
|
+
animationsEnabled,
|
|
1381
|
+
theme: activeTheme
|
|
1382
|
+
}
|
|
1383
|
+
) }),
|
|
1384
|
+
materialization.cells.map((cell) => /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1385
|
+
cell.frame && /* @__PURE__ */ jsx7(
|
|
1386
|
+
"div",
|
|
1387
|
+
{
|
|
1388
|
+
className: "squisq-dashboard__frame",
|
|
1389
|
+
"data-cell-index": cell.index,
|
|
1390
|
+
"aria-hidden": "true",
|
|
1391
|
+
style: {
|
|
1392
|
+
position: "absolute",
|
|
1393
|
+
left: cell.frame.rectPct.left,
|
|
1394
|
+
top: cell.frame.rectPct.top,
|
|
1395
|
+
width: cell.frame.rectPct.width,
|
|
1396
|
+
height: cell.frame.rectPct.height,
|
|
1397
|
+
pointerEvents: "none"
|
|
1398
|
+
},
|
|
1399
|
+
children: /* @__PURE__ */ jsx7(
|
|
1400
|
+
BlockRenderer,
|
|
1401
|
+
{
|
|
1402
|
+
block: syntheticBlock(`dashboard-frame-${cell.index}`, cell.frame.layers),
|
|
1403
|
+
blockTime: 0,
|
|
1404
|
+
basePath,
|
|
1405
|
+
viewport: {
|
|
1406
|
+
width: cell.frame.viewport.width,
|
|
1407
|
+
height: cell.frame.viewport.height
|
|
1408
|
+
},
|
|
1409
|
+
isPlaying: false,
|
|
1410
|
+
muted: true,
|
|
1411
|
+
animationsEnabled,
|
|
1412
|
+
theme: activeTheme
|
|
1413
|
+
}
|
|
1414
|
+
)
|
|
1415
|
+
}
|
|
1416
|
+
),
|
|
1417
|
+
/* @__PURE__ */ jsxs4(
|
|
1418
|
+
"div",
|
|
1419
|
+
{
|
|
1420
|
+
className: "squisq-dashboard__cell",
|
|
1421
|
+
"data-cell-index": cell.index,
|
|
1422
|
+
style: {
|
|
1423
|
+
position: "absolute",
|
|
1424
|
+
left: cell.rectPct.left,
|
|
1425
|
+
top: cell.rectPct.top,
|
|
1426
|
+
width: cell.rectPct.width,
|
|
1427
|
+
height: cell.rectPct.height,
|
|
1428
|
+
// Percentage radii scale with the rendered canvas, so a card
|
|
1429
|
+
// cell's full-bleed art stays clipped to its corners at any
|
|
1430
|
+
// export resolution.
|
|
1431
|
+
...cell.frame?.contentRadiusPct ? { borderRadius: cell.frame.contentRadiusPct, overflow: "hidden" } : {}
|
|
1432
|
+
},
|
|
1433
|
+
children: [
|
|
1434
|
+
/* @__PURE__ */ jsx7(
|
|
1435
|
+
BlockRenderer,
|
|
1436
|
+
{
|
|
1437
|
+
block: { ...cell.block, layers: cell.layers },
|
|
1438
|
+
blockTime: 0,
|
|
1439
|
+
basePath,
|
|
1440
|
+
viewport: { width: cell.viewport.width, height: cell.viewport.height },
|
|
1441
|
+
isPlaying: false,
|
|
1442
|
+
muted,
|
|
1443
|
+
animationsEnabled,
|
|
1444
|
+
theme: activeTheme
|
|
1445
|
+
}
|
|
1446
|
+
),
|
|
1447
|
+
cell.frame && cell.frame.overlayLayers.length > 0 && // Borders and accents ride above the block: a template that
|
|
1448
|
+
// paints its own opaque surface would bury them. Same box, so
|
|
1449
|
+
// the cell's clip rounds them to the card's corners.
|
|
1450
|
+
/* @__PURE__ */ jsx7("div", { style: { position: "absolute", inset: 0, pointerEvents: "none" }, children: /* @__PURE__ */ jsx7(
|
|
1451
|
+
BlockRenderer,
|
|
1452
|
+
{
|
|
1453
|
+
block: syntheticBlock(
|
|
1454
|
+
`dashboard-frame-overlay-${cell.index}`,
|
|
1455
|
+
cell.frame.overlayLayers
|
|
1456
|
+
),
|
|
1457
|
+
blockTime: 0,
|
|
1458
|
+
basePath,
|
|
1459
|
+
viewport: {
|
|
1460
|
+
width: cell.frame.overlayViewport.width,
|
|
1461
|
+
height: cell.frame.overlayViewport.height
|
|
1462
|
+
},
|
|
1463
|
+
isPlaying: false,
|
|
1464
|
+
muted: true,
|
|
1465
|
+
animationsEnabled,
|
|
1466
|
+
theme: activeTheme
|
|
1467
|
+
}
|
|
1468
|
+
) })
|
|
1469
|
+
]
|
|
1470
|
+
}
|
|
1471
|
+
)
|
|
1472
|
+
] }, `${cell.index}-${cell.block.id}`)),
|
|
1473
|
+
materialization.title && titleBlock && /* @__PURE__ */ jsx7(
|
|
1474
|
+
"div",
|
|
1475
|
+
{
|
|
1476
|
+
className: "squisq-dashboard__title",
|
|
1477
|
+
style: {
|
|
1478
|
+
position: "absolute",
|
|
1479
|
+
left: materialization.title.rectPct.left,
|
|
1480
|
+
top: materialization.title.rectPct.top,
|
|
1481
|
+
width: materialization.title.rectPct.width,
|
|
1482
|
+
height: materialization.title.rectPct.height
|
|
1483
|
+
},
|
|
1484
|
+
children: /* @__PURE__ */ jsx7(
|
|
1485
|
+
BlockRenderer,
|
|
1486
|
+
{
|
|
1487
|
+
block: titleBlock,
|
|
1488
|
+
blockTime: 0,
|
|
1489
|
+
basePath,
|
|
1490
|
+
viewport: {
|
|
1491
|
+
width: materialization.title.viewport.width,
|
|
1492
|
+
height: materialization.title.viewport.height
|
|
1493
|
+
},
|
|
1494
|
+
isPlaying: false,
|
|
1495
|
+
muted: true,
|
|
1496
|
+
animationsEnabled,
|
|
1497
|
+
theme: activeTheme
|
|
1498
|
+
}
|
|
1499
|
+
)
|
|
1500
|
+
}
|
|
1501
|
+
),
|
|
1502
|
+
backdropTop && /* @__PURE__ */ jsx7("div", { style: { ...coverStyle, pointerEvents: "none" }, "aria-hidden": "true", children: /* @__PURE__ */ jsx7(
|
|
1503
|
+
BlockRenderer,
|
|
1504
|
+
{
|
|
1505
|
+
block: backdropTop,
|
|
1506
|
+
blockTime: 0,
|
|
1507
|
+
basePath,
|
|
1508
|
+
viewport: canvasDimensions,
|
|
1509
|
+
isPlaying: false,
|
|
1510
|
+
muted: true,
|
|
1511
|
+
animationsEnabled,
|
|
1512
|
+
theme: activeTheme
|
|
1513
|
+
}
|
|
1514
|
+
) })
|
|
1515
|
+
]
|
|
1516
|
+
}
|
|
1517
|
+
);
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
// src/FlashcardView.tsx
|
|
1521
|
+
import {
|
|
1522
|
+
useCallback as useCallback3,
|
|
1523
|
+
useEffect as useEffect5,
|
|
1524
|
+
useMemo as useMemo4,
|
|
1525
|
+
useRef as useRef5,
|
|
1526
|
+
useState as useState4
|
|
1527
|
+
} from "react";
|
|
1528
|
+
import { resolveFontFamily as resolveFontFamily2, VIEWPORT_PRESETS as VIEWPORT_PRESETS2 } from "@bendyline/squisq/schemas";
|
|
1529
|
+
import {
|
|
1530
|
+
materializeBlockLayers,
|
|
1531
|
+
materializeFlashcards,
|
|
1532
|
+
resolvePageBlock,
|
|
1533
|
+
resolveThemeForDoc as resolveThemeForDoc2
|
|
1534
|
+
} from "@bendyline/squisq/doc";
|
|
1535
|
+
import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1536
|
+
var VISUAL_TEMPLATES = /* @__PURE__ */ new Set([
|
|
1537
|
+
"diagram",
|
|
1538
|
+
"tree",
|
|
1539
|
+
"timeline",
|
|
1540
|
+
"map",
|
|
1541
|
+
"drawing",
|
|
1542
|
+
"layout",
|
|
1543
|
+
"barChart",
|
|
1544
|
+
"columnChart",
|
|
1545
|
+
"pieChart",
|
|
1546
|
+
"donutChart",
|
|
1547
|
+
"lineChart",
|
|
1548
|
+
"areaChart",
|
|
1549
|
+
"scatterChart"
|
|
1550
|
+
]);
|
|
1551
|
+
function resolveVisualBlock(block, theme, viewport, customTemplates) {
|
|
1552
|
+
const resolved = resolvePageBlock(block);
|
|
1553
|
+
const visualTemplate = !!resolved.templateName && (VISUAL_TEMPLATES.has(resolved.templateName) || !!customTemplates?.some((definition) => definition.name === resolved.templateName));
|
|
1554
|
+
if (!visualTemplate) return null;
|
|
1555
|
+
const materializationBlock = resolved.templateBlock ?? block;
|
|
1556
|
+
const { layers, source } = materializeBlockLayers(materializationBlock, {
|
|
1557
|
+
theme,
|
|
1558
|
+
viewport,
|
|
1559
|
+
customTemplates,
|
|
1560
|
+
persistentLayers: false
|
|
1561
|
+
});
|
|
1562
|
+
if (layers.length === 0 || source === "fallback") return null;
|
|
1563
|
+
return { ...materializationBlock, layers };
|
|
1564
|
+
}
|
|
1565
|
+
function FaceBlock({
|
|
1566
|
+
block,
|
|
1567
|
+
depth,
|
|
1568
|
+
theme,
|
|
1569
|
+
basePath,
|
|
1570
|
+
showCodeCopyButton,
|
|
1571
|
+
onCopyCode,
|
|
1572
|
+
fenceRenderers,
|
|
1573
|
+
viewport,
|
|
1574
|
+
customTemplates
|
|
1575
|
+
}) {
|
|
1576
|
+
const Heading = depth === 0 ? "h2" : depth === 1 ? "h3" : "h4";
|
|
1577
|
+
const visualBlock = useMemo4(
|
|
1578
|
+
() => resolveVisualBlock(block, theme, viewport, customTemplates),
|
|
1579
|
+
[block, customTemplates, theme, viewport]
|
|
1580
|
+
);
|
|
1581
|
+
return /* @__PURE__ */ jsxs5("section", { className: "squisq-flashcards__content-block", "data-source-block-id": block.id, children: [
|
|
1582
|
+
!visualBlock && block.title && /* @__PURE__ */ jsx8(Heading, { className: "squisq-flashcards__content-title", children: block.title }),
|
|
1583
|
+
!visualBlock && block.contents && block.contents.length > 0 && /* @__PURE__ */ jsx8(
|
|
1584
|
+
MarkdownRenderer,
|
|
1585
|
+
{
|
|
1586
|
+
nodes: block.contents,
|
|
1587
|
+
theme,
|
|
1588
|
+
showCodeCopyButton,
|
|
1589
|
+
onCopyCode,
|
|
1590
|
+
fenceRenderers
|
|
1591
|
+
}
|
|
1592
|
+
),
|
|
1593
|
+
(visualBlock || block.layers && block.layers.length > 0) && /* @__PURE__ */ jsx8(
|
|
1594
|
+
"div",
|
|
1595
|
+
{
|
|
1596
|
+
className: "squisq-flashcards__canvas",
|
|
1597
|
+
style: { aspectRatio: `${viewport.width} / ${viewport.height}` },
|
|
1598
|
+
children: /* @__PURE__ */ jsx8(
|
|
1599
|
+
BlockRenderer,
|
|
1600
|
+
{
|
|
1601
|
+
block: visualBlock ?? block,
|
|
1602
|
+
blockTime: Math.max(0, block.duration ?? 0),
|
|
1603
|
+
basePath,
|
|
1604
|
+
viewport,
|
|
1605
|
+
animationsEnabled: false,
|
|
1606
|
+
theme,
|
|
1607
|
+
muted: true
|
|
1608
|
+
}
|
|
1609
|
+
)
|
|
1610
|
+
}
|
|
1611
|
+
),
|
|
1612
|
+
!visualBlock && block.children?.map((child) => /* @__PURE__ */ jsx8(
|
|
1613
|
+
FaceBlock,
|
|
1614
|
+
{
|
|
1615
|
+
block: child,
|
|
1616
|
+
depth: depth + 1,
|
|
1617
|
+
theme,
|
|
1618
|
+
basePath,
|
|
1619
|
+
showCodeCopyButton,
|
|
1620
|
+
onCopyCode,
|
|
1621
|
+
fenceRenderers,
|
|
1622
|
+
viewport,
|
|
1623
|
+
customTemplates
|
|
1624
|
+
},
|
|
1625
|
+
child.id
|
|
1626
|
+
))
|
|
1627
|
+
] });
|
|
1628
|
+
}
|
|
1629
|
+
function FaceContent(props) {
|
|
1630
|
+
return /* @__PURE__ */ jsx8("div", { className: "squisq-flashcards__face-content", children: props.face.blocks.map((block) => /* @__PURE__ */ jsx8(FaceBlock, { block, depth: 0, ...props }, block.id)) });
|
|
1631
|
+
}
|
|
1632
|
+
function FlashcardFaceView(props) {
|
|
1633
|
+
return /* @__PURE__ */ jsx8(FaceContent, { ...props, viewport: props.viewport ?? VIEWPORT_PRESETS2.landscape });
|
|
1634
|
+
}
|
|
1635
|
+
function hashSeed(value) {
|
|
1636
|
+
let hash = 2166136261;
|
|
1637
|
+
for (let index = 0; index < value.length; index++) {
|
|
1638
|
+
hash ^= value.charCodeAt(index);
|
|
1639
|
+
hash = Math.imul(hash, 16777619);
|
|
1640
|
+
}
|
|
1641
|
+
return hash >>> 0;
|
|
1642
|
+
}
|
|
1643
|
+
function shuffled(values, seed) {
|
|
1644
|
+
const result = [...values];
|
|
1645
|
+
let state = hashSeed(seed) || 1;
|
|
1646
|
+
const random = () => {
|
|
1647
|
+
state += 1831565813;
|
|
1648
|
+
let next = state;
|
|
1649
|
+
next = Math.imul(next ^ next >>> 15, next | 1);
|
|
1650
|
+
next ^= next + Math.imul(next ^ next >>> 7, next | 61);
|
|
1651
|
+
return ((next ^ next >>> 14) >>> 0) / 4294967296;
|
|
1652
|
+
};
|
|
1653
|
+
for (let index = result.length - 1; index > 0; index--) {
|
|
1654
|
+
const other = Math.floor(random() * (index + 1));
|
|
1655
|
+
[result[index], result[other]] = [result[other], result[index]];
|
|
1656
|
+
}
|
|
1657
|
+
return result;
|
|
1658
|
+
}
|
|
1659
|
+
function ChoiceContent(props) {
|
|
1660
|
+
return /* @__PURE__ */ jsx8(FaceContent, { ...props, face: props.choice.content });
|
|
1661
|
+
}
|
|
1662
|
+
function isInteractiveTarget(target) {
|
|
1663
|
+
return target instanceof Element && !!target.closest('button, a, input, select, textarea, [contenteditable="true"]');
|
|
1664
|
+
}
|
|
1665
|
+
function FlashcardView({
|
|
1666
|
+
doc,
|
|
1667
|
+
theme,
|
|
1668
|
+
basePath = ".",
|
|
1669
|
+
source = "auto",
|
|
1670
|
+
shuffle: initialShuffle = false,
|
|
1671
|
+
globalKeyboardShortcuts = false,
|
|
1672
|
+
showCodeCopyButton = false,
|
|
1673
|
+
onCopyCode,
|
|
1674
|
+
fenceRenderers,
|
|
1675
|
+
viewport = VIEWPORT_PRESETS2.landscape,
|
|
1676
|
+
className
|
|
1677
|
+
}) {
|
|
1678
|
+
const activeTheme = useMemo4(() => theme ?? resolveThemeForDoc2(doc), [doc, theme]);
|
|
1679
|
+
const deck = useMemo4(() => materializeFlashcards(doc, { source }), [doc, source]);
|
|
1680
|
+
const [shuffleEnabled, setShuffleEnabled] = useState4(initialShuffle);
|
|
1681
|
+
const [sessionSeed, setSessionSeed] = useState4(1);
|
|
1682
|
+
const [cardIndex, setCardIndex] = useState4(0);
|
|
1683
|
+
const [revealed, setRevealed] = useState4(false);
|
|
1684
|
+
const [selectedChoiceId, setSelectedChoiceId] = useState4(null);
|
|
1685
|
+
const [ratings, setRatings] = useState4({});
|
|
1686
|
+
const [retryIds, setRetryIds] = useState4(null);
|
|
1687
|
+
const cardViewportRef = useRef5(null);
|
|
1688
|
+
const orderedCards = useMemo4(
|
|
1689
|
+
() => shuffleEnabled ? shuffled(deck.cards, `${doc.articleId}:${sessionSeed}`) : [...deck.cards],
|
|
1690
|
+
[deck.cards, doc.articleId, sessionSeed, shuffleEnabled]
|
|
1691
|
+
);
|
|
1692
|
+
const sessionCards = useMemo4(
|
|
1693
|
+
() => retryIds ? retryIds.map((id) => orderedCards.find((card) => card.id === id)).filter((card) => !!card) : orderedCards,
|
|
1694
|
+
[orderedCards, retryIds]
|
|
1695
|
+
);
|
|
1696
|
+
const currentCard = sessionCards[cardIndex];
|
|
1697
|
+
const finished = sessionCards.length > 0 && cardIndex >= sessionCards.length;
|
|
1698
|
+
const resetPosition = useCallback3(() => {
|
|
1699
|
+
setCardIndex(0);
|
|
1700
|
+
setRevealed(false);
|
|
1701
|
+
setSelectedChoiceId(null);
|
|
1702
|
+
}, []);
|
|
1703
|
+
const restart = useCallback3(() => {
|
|
1704
|
+
setRatings({});
|
|
1705
|
+
setRetryIds(null);
|
|
1706
|
+
resetPosition();
|
|
1707
|
+
setSessionSeed((seed) => seed + 1);
|
|
1708
|
+
}, [resetPosition]);
|
|
1709
|
+
useEffect5(() => {
|
|
1710
|
+
setRatings({});
|
|
1711
|
+
setRetryIds(null);
|
|
1712
|
+
resetPosition();
|
|
1713
|
+
}, [deck, resetPosition]);
|
|
1714
|
+
useEffect5(() => {
|
|
1715
|
+
if (cardViewportRef.current) cardViewportRef.current.scrollTop = 0;
|
|
1716
|
+
}, [cardIndex, retryIds]);
|
|
1717
|
+
const revealAnswer = useCallback3(() => {
|
|
1718
|
+
if (!currentCard) return;
|
|
1719
|
+
setRevealed(true);
|
|
1720
|
+
if (currentCard.kind === "multiple-choice" && selectedChoiceId === null) {
|
|
1721
|
+
setRatings((current) => ({ ...current, [currentCard.id]: "again" }));
|
|
1722
|
+
}
|
|
1723
|
+
}, [currentCard, selectedChoiceId]);
|
|
1724
|
+
const nextCard = useCallback3(() => {
|
|
1725
|
+
if (!currentCard) return;
|
|
1726
|
+
if (!revealed) {
|
|
1727
|
+
revealAnswer();
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1730
|
+
setCardIndex((index) => index + 1);
|
|
1731
|
+
setRevealed(false);
|
|
1732
|
+
setSelectedChoiceId(null);
|
|
1733
|
+
}, [currentCard, revealAnswer, revealed]);
|
|
1734
|
+
const previousCard = useCallback3(() => {
|
|
1735
|
+
if (finished) {
|
|
1736
|
+
setCardIndex(Math.max(0, sessionCards.length - 1));
|
|
1737
|
+
setRevealed(true);
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1740
|
+
if (revealed) {
|
|
1741
|
+
setRevealed(false);
|
|
1742
|
+
setSelectedChoiceId(null);
|
|
1743
|
+
return;
|
|
1744
|
+
}
|
|
1745
|
+
if (cardIndex > 0) {
|
|
1746
|
+
setCardIndex((index) => index - 1);
|
|
1747
|
+
setRevealed(true);
|
|
1748
|
+
setSelectedChoiceId(null);
|
|
1749
|
+
}
|
|
1750
|
+
}, [cardIndex, finished, revealed, sessionCards.length]);
|
|
1751
|
+
const choose = useCallback3(
|
|
1752
|
+
(choice) => {
|
|
1753
|
+
if (!currentCard || revealed) return;
|
|
1754
|
+
setSelectedChoiceId(choice.id);
|
|
1755
|
+
setRevealed(true);
|
|
1756
|
+
setRatings((current) => ({
|
|
1757
|
+
...current,
|
|
1758
|
+
[currentCard.id]: choice.correct ? "got-it" : "again"
|
|
1759
|
+
}));
|
|
1760
|
+
},
|
|
1761
|
+
[currentCard, revealed]
|
|
1762
|
+
);
|
|
1763
|
+
const rate = useCallback3(
|
|
1764
|
+
(rating) => {
|
|
1765
|
+
if (!currentCard) return;
|
|
1766
|
+
setRatings((current) => ({ ...current, [currentCard.id]: rating }));
|
|
1767
|
+
setCardIndex((index) => index + 1);
|
|
1768
|
+
setRevealed(false);
|
|
1769
|
+
setSelectedChoiceId(null);
|
|
1770
|
+
},
|
|
1771
|
+
[currentCard]
|
|
1772
|
+
);
|
|
1773
|
+
const handleShortcut = useCallback3(
|
|
1774
|
+
(event) => {
|
|
1775
|
+
if (event.defaultPrevented || isInteractiveTarget(event.target)) return;
|
|
1776
|
+
if (/^[1-9]$/.test(event.key) && currentCard?.kind === "multiple-choice" && !revealed) {
|
|
1777
|
+
const choice = currentCard.choices?.[Number(event.key) - 1];
|
|
1778
|
+
if (choice) {
|
|
1779
|
+
event.preventDefault();
|
|
1780
|
+
choose(choice);
|
|
1781
|
+
}
|
|
1782
|
+
return;
|
|
1783
|
+
}
|
|
1784
|
+
if (event.key === "ArrowLeft") {
|
|
1785
|
+
event.preventDefault();
|
|
1786
|
+
previousCard();
|
|
1787
|
+
} else if (event.key === "ArrowRight" || event.key === " " || event.key === "Enter") {
|
|
1788
|
+
event.preventDefault();
|
|
1789
|
+
nextCard();
|
|
1790
|
+
}
|
|
1791
|
+
},
|
|
1792
|
+
[choose, currentCard, nextCard, previousCard, revealed]
|
|
1793
|
+
);
|
|
1794
|
+
useEffect5(() => {
|
|
1795
|
+
if (!globalKeyboardShortcuts) return;
|
|
1796
|
+
const listener = (event) => handleShortcut(event);
|
|
1797
|
+
document.addEventListener("keydown", listener);
|
|
1798
|
+
return () => document.removeEventListener("keydown", listener);
|
|
1799
|
+
}, [globalKeyboardShortcuts, handleShortcut]);
|
|
1800
|
+
const faceProps = {
|
|
1801
|
+
theme: activeTheme,
|
|
1802
|
+
basePath,
|
|
1803
|
+
showCodeCopyButton,
|
|
1804
|
+
onCopyCode,
|
|
1805
|
+
fenceRenderers,
|
|
1806
|
+
viewport,
|
|
1807
|
+
customTemplates: doc.customTemplates
|
|
1808
|
+
};
|
|
1809
|
+
const titleFont = resolveFontFamily2(activeTheme.typography.titleFont, "Georgia, serif");
|
|
1810
|
+
const bodyFont = resolveFontFamily2(activeTheme.typography.bodyFont, "system-ui, sans-serif");
|
|
1811
|
+
const rootStyle = {
|
|
1812
|
+
"--squisq-flashcards-bg": activeTheme.colors.background,
|
|
1813
|
+
"--squisq-flashcards-surface": activeTheme.colors.backgroundLight,
|
|
1814
|
+
"--squisq-flashcards-text": activeTheme.colors.text,
|
|
1815
|
+
"--squisq-flashcards-muted": activeTheme.colors.textMuted,
|
|
1816
|
+
"--squisq-flashcards-primary": activeTheme.colors.primary,
|
|
1817
|
+
"--squisq-flashcards-secondary": activeTheme.colors.secondary,
|
|
1818
|
+
"--squisq-flashcards-highlight": activeTheme.colors.highlight,
|
|
1819
|
+
"--squisq-flashcards-warning": activeTheme.colors.warning,
|
|
1820
|
+
"--squisq-flashcards-radius": `${activeTheme.style.borderRadius ?? 18}px`,
|
|
1821
|
+
"--squisq-flashcards-title-font": titleFont,
|
|
1822
|
+
"--squisq-flashcards-body-font": bodyFont
|
|
1823
|
+
};
|
|
1824
|
+
const missedIds = deck.cards.filter((card) => ratings[card.id] === "again").map((card) => card.id);
|
|
1825
|
+
const gotItCount = deck.cards.filter((card) => ratings[card.id] === "got-it").length;
|
|
1826
|
+
if (deck.cards.length === 0) {
|
|
1827
|
+
return /* @__PURE__ */ jsx8(
|
|
1828
|
+
"div",
|
|
1829
|
+
{
|
|
1830
|
+
className: `squisq-flashcards squisq-flashcards--empty${className ? ` ${className}` : ""}`,
|
|
1831
|
+
style: rootStyle,
|
|
1832
|
+
role: "region",
|
|
1833
|
+
"aria-label": "Flashcards",
|
|
1834
|
+
children: /* @__PURE__ */ jsxs5("div", { className: "squisq-flashcards__empty-card", children: [
|
|
1835
|
+
/* @__PURE__ */ jsx8("h2", { children: "No complete flashcards yet" }),
|
|
1836
|
+
/* @__PURE__ */ jsx8("p", { children: "Add an answer beneath a heading, or nest an answer block under a question." }),
|
|
1837
|
+
deck.diagnostics.length > 0 && /* @__PURE__ */ jsx8("ul", { children: deck.diagnostics.map((diagnostic, index) => /* @__PURE__ */ jsx8("li", { children: diagnostic.message }, `${diagnostic.blockId}-${diagnostic.code}-${index}`)) })
|
|
1838
|
+
] })
|
|
1839
|
+
}
|
|
1840
|
+
);
|
|
1841
|
+
}
|
|
1842
|
+
if (finished) {
|
|
1843
|
+
return /* @__PURE__ */ jsx8(
|
|
1844
|
+
"div",
|
|
1845
|
+
{
|
|
1846
|
+
className: `squisq-flashcards${className ? ` ${className}` : ""}`,
|
|
1847
|
+
style: rootStyle,
|
|
1848
|
+
role: "region",
|
|
1849
|
+
"aria-label": "Flashcard session summary",
|
|
1850
|
+
tabIndex: 0,
|
|
1851
|
+
onKeyDown: globalKeyboardShortcuts ? void 0 : handleShortcut,
|
|
1852
|
+
children: /* @__PURE__ */ jsxs5("div", { className: "squisq-flashcards__summary", children: [
|
|
1853
|
+
/* @__PURE__ */ jsx8("span", { className: "squisq-flashcards__eyebrow", children: "Session complete" }),
|
|
1854
|
+
/* @__PURE__ */ jsxs5("h2", { children: [
|
|
1855
|
+
gotItCount,
|
|
1856
|
+
" remembered"
|
|
1857
|
+
] }),
|
|
1858
|
+
/* @__PURE__ */ jsx8("p", { children: missedIds.length === 0 ? `You completed all ${deck.cards.length} cards.` : `${missedIds.length} ${missedIds.length === 1 ? "card needs" : "cards need"} another look.` }),
|
|
1859
|
+
/* @__PURE__ */ jsxs5("div", { className: "squisq-flashcards__summary-actions", children: [
|
|
1860
|
+
missedIds.length > 0 && /* @__PURE__ */ jsx8(
|
|
1861
|
+
"button",
|
|
1862
|
+
{
|
|
1863
|
+
type: "button",
|
|
1864
|
+
className: "squisq-flashcards__button squisq-flashcards__button--primary",
|
|
1865
|
+
onClick: () => {
|
|
1866
|
+
setRetryIds(missedIds);
|
|
1867
|
+
resetPosition();
|
|
1868
|
+
},
|
|
1869
|
+
children: "Retry missed"
|
|
1870
|
+
}
|
|
1871
|
+
),
|
|
1872
|
+
/* @__PURE__ */ jsx8("button", { type: "button", className: "squisq-flashcards__button", onClick: restart, children: "Study again" }),
|
|
1873
|
+
/* @__PURE__ */ jsx8("button", { type: "button", className: "squisq-flashcards__button", onClick: previousCard, children: "Previous card" })
|
|
1874
|
+
] })
|
|
1875
|
+
] })
|
|
1876
|
+
}
|
|
1877
|
+
);
|
|
1878
|
+
}
|
|
1879
|
+
const choices = currentCard?.choices ? shuffled(currentCard.choices, `${currentCard.id}:${sessionSeed}`) : [];
|
|
1880
|
+
const selectedChoice = choices.find((choice) => choice.id === selectedChoiceId);
|
|
1881
|
+
return /* @__PURE__ */ jsxs5(
|
|
1882
|
+
"div",
|
|
1883
|
+
{
|
|
1884
|
+
className: `squisq-flashcards${className ? ` ${className}` : ""}`,
|
|
1885
|
+
style: rootStyle,
|
|
1886
|
+
role: "region",
|
|
1887
|
+
"aria-label": "Flashcards",
|
|
1888
|
+
tabIndex: 0,
|
|
1889
|
+
onKeyDown: globalKeyboardShortcuts ? void 0 : handleShortcut,
|
|
1890
|
+
children: [
|
|
1891
|
+
/* @__PURE__ */ jsxs5("header", { className: "squisq-flashcards__header", children: [
|
|
1892
|
+
/* @__PURE__ */ jsxs5("div", { className: "squisq-flashcards__deck-copy", children: [
|
|
1893
|
+
/* @__PURE__ */ jsx8("span", { className: "squisq-flashcards__eyebrow", children: "Flashcards" }),
|
|
1894
|
+
deck.title && /* @__PURE__ */ jsx8("h1", { children: deck.title })
|
|
1895
|
+
] }),
|
|
1896
|
+
/* @__PURE__ */ jsxs5("div", { className: "squisq-flashcards__tools", children: [
|
|
1897
|
+
/* @__PURE__ */ jsx8(
|
|
1898
|
+
"button",
|
|
1899
|
+
{
|
|
1900
|
+
type: "button",
|
|
1901
|
+
className: "squisq-flashcards__tool",
|
|
1902
|
+
"aria-pressed": shuffleEnabled,
|
|
1903
|
+
onClick: () => {
|
|
1904
|
+
setShuffleEnabled((enabled) => !enabled);
|
|
1905
|
+
restart();
|
|
1906
|
+
},
|
|
1907
|
+
children: "Shuffle"
|
|
1908
|
+
}
|
|
1909
|
+
),
|
|
1910
|
+
/* @__PURE__ */ jsx8("button", { type: "button", className: "squisq-flashcards__tool", onClick: restart, children: "Restart" })
|
|
1911
|
+
] })
|
|
1912
|
+
] }),
|
|
1913
|
+
/* @__PURE__ */ jsxs5("div", { className: "squisq-flashcards__progress-row", children: [
|
|
1914
|
+
/* @__PURE__ */ jsxs5("span", { children: [
|
|
1915
|
+
"Card ",
|
|
1916
|
+
cardIndex + 1,
|
|
1917
|
+
" of ",
|
|
1918
|
+
sessionCards.length
|
|
1919
|
+
] }),
|
|
1920
|
+
/* @__PURE__ */ jsx8("span", { children: revealed ? "Answer revealed" : "Question" })
|
|
1921
|
+
] }),
|
|
1922
|
+
/* @__PURE__ */ jsx8("div", { className: "squisq-flashcards__progress", "aria-hidden": "true", children: /* @__PURE__ */ jsx8(
|
|
1923
|
+
"span",
|
|
1924
|
+
{
|
|
1925
|
+
style: { width: `${(cardIndex + (revealed ? 1 : 0)) / sessionCards.length * 100}%` }
|
|
1926
|
+
}
|
|
1927
|
+
) }),
|
|
1928
|
+
/* @__PURE__ */ jsxs5(
|
|
1929
|
+
"main",
|
|
1930
|
+
{
|
|
1931
|
+
ref: cardViewportRef,
|
|
1932
|
+
className: "squisq-flashcards__card",
|
|
1933
|
+
"data-card-kind": currentCard.kind,
|
|
1934
|
+
"aria-label": "Scrollable flashcard content",
|
|
1935
|
+
tabIndex: 0,
|
|
1936
|
+
children: [
|
|
1937
|
+
currentCard.label && /* @__PURE__ */ jsx8("div", { className: "squisq-flashcards__label", children: currentCard.label }),
|
|
1938
|
+
/* @__PURE__ */ jsx8("section", { className: "squisq-flashcards__front", "aria-label": "Question", children: /* @__PURE__ */ jsx8(FaceContent, { ...faceProps, face: currentCard.front }) }),
|
|
1939
|
+
currentCard.kind === "multiple-choice" && /* @__PURE__ */ jsx8("div", { className: "squisq-flashcards__choices", role: "group", "aria-label": "Answer choices", children: choices.map((choice, index) => {
|
|
1940
|
+
const selected = selectedChoiceId === choice.id;
|
|
1941
|
+
const status = revealed ? choice.correct ? "correct" : selected ? "incorrect" : "idle" : "idle";
|
|
1942
|
+
return /* @__PURE__ */ jsxs5(
|
|
1943
|
+
"button",
|
|
1944
|
+
{
|
|
1945
|
+
type: "button",
|
|
1946
|
+
className: "squisq-flashcards__choice",
|
|
1947
|
+
"data-choice-status": status,
|
|
1948
|
+
"aria-pressed": selected,
|
|
1949
|
+
disabled: revealed,
|
|
1950
|
+
onClick: () => choose(choice),
|
|
1951
|
+
children: [
|
|
1952
|
+
/* @__PURE__ */ jsx8("span", { className: "squisq-flashcards__choice-key", "aria-hidden": "true", children: index + 1 }),
|
|
1953
|
+
/* @__PURE__ */ jsx8(ChoiceContent, { ...faceProps, choice })
|
|
1954
|
+
]
|
|
1955
|
+
},
|
|
1956
|
+
choice.id
|
|
1957
|
+
);
|
|
1958
|
+
}) }),
|
|
1959
|
+
revealed && currentCard.kind === "basic" && /* @__PURE__ */ jsxs5("section", { className: "squisq-flashcards__answer", "aria-label": "Answer", children: [
|
|
1960
|
+
/* @__PURE__ */ jsx8("span", { className: "squisq-flashcards__answer-label", children: "Answer" }),
|
|
1961
|
+
/* @__PURE__ */ jsx8(FaceContent, { ...faceProps, face: currentCard.back })
|
|
1962
|
+
] }),
|
|
1963
|
+
revealed && currentCard.kind === "multiple-choice" && /* @__PURE__ */ jsxs5(
|
|
1964
|
+
"div",
|
|
1965
|
+
{
|
|
1966
|
+
className: "squisq-flashcards__feedback",
|
|
1967
|
+
"data-correct": selectedChoice?.correct === true,
|
|
1968
|
+
"aria-live": "polite",
|
|
1969
|
+
children: [
|
|
1970
|
+
/* @__PURE__ */ jsx8("strong", { children: selectedChoice === void 0 ? "Answer revealed" : selectedChoice.correct ? "Correct" : "Not quite" }),
|
|
1971
|
+
!selectedChoice?.correct && /* @__PURE__ */ jsxs5("div", { className: "squisq-flashcards__correct-answer", children: [
|
|
1972
|
+
/* @__PURE__ */ jsx8("span", { children: "The correct answer is" }),
|
|
1973
|
+
/* @__PURE__ */ jsx8(FaceContent, { ...faceProps, face: currentCard.back })
|
|
1974
|
+
] })
|
|
1975
|
+
]
|
|
1976
|
+
}
|
|
1977
|
+
),
|
|
1978
|
+
revealed && currentCard.explanation && /* @__PURE__ */ jsxs5("section", { className: "squisq-flashcards__explanation", "aria-label": "Explanation", children: [
|
|
1979
|
+
/* @__PURE__ */ jsx8("span", { className: "squisq-flashcards__answer-label", children: "Explanation" }),
|
|
1980
|
+
/* @__PURE__ */ jsx8(FaceContent, { ...faceProps, face: currentCard.explanation })
|
|
1981
|
+
] })
|
|
1982
|
+
]
|
|
1983
|
+
}
|
|
1984
|
+
),
|
|
1985
|
+
/* @__PURE__ */ jsxs5("footer", { className: "squisq-flashcards__footer", children: [
|
|
1986
|
+
/* @__PURE__ */ jsx8(
|
|
1987
|
+
"button",
|
|
1988
|
+
{
|
|
1989
|
+
type: "button",
|
|
1990
|
+
className: "squisq-flashcards__button",
|
|
1991
|
+
disabled: cardIndex === 0 && !revealed,
|
|
1992
|
+
onClick: previousCard,
|
|
1993
|
+
children: "Previous"
|
|
1994
|
+
}
|
|
1995
|
+
),
|
|
1996
|
+
/* @__PURE__ */ jsx8("div", { className: "squisq-flashcards__primary-actions", children: revealed && currentCard.kind === "basic" ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
1997
|
+
/* @__PURE__ */ jsx8(
|
|
1998
|
+
"button",
|
|
1999
|
+
{
|
|
2000
|
+
type: "button",
|
|
2001
|
+
className: "squisq-flashcards__button",
|
|
2002
|
+
onClick: () => rate("again"),
|
|
2003
|
+
children: "Again"
|
|
2004
|
+
}
|
|
2005
|
+
),
|
|
2006
|
+
/* @__PURE__ */ jsx8(
|
|
2007
|
+
"button",
|
|
2008
|
+
{
|
|
2009
|
+
type: "button",
|
|
2010
|
+
className: "squisq-flashcards__button squisq-flashcards__button--primary",
|
|
2011
|
+
onClick: () => rate("got-it"),
|
|
2012
|
+
children: "Got it"
|
|
2013
|
+
}
|
|
2014
|
+
)
|
|
2015
|
+
] }) : /* @__PURE__ */ jsx8(
|
|
2016
|
+
"button",
|
|
2017
|
+
{
|
|
2018
|
+
type: "button",
|
|
2019
|
+
className: "squisq-flashcards__button squisq-flashcards__button--primary",
|
|
2020
|
+
onClick: nextCard,
|
|
2021
|
+
children: revealed ? cardIndex === sessionCards.length - 1 ? "Finish" : "Next card" : "Reveal answer"
|
|
2022
|
+
}
|
|
2023
|
+
) })
|
|
2024
|
+
] }),
|
|
2025
|
+
/* @__PURE__ */ jsxs5("p", { className: "squisq-flashcards__shortcut-hint", children: [
|
|
2026
|
+
"Use \u2190 and \u2192 to navigate, Space to reveal",
|
|
2027
|
+
currentCard.kind === "multiple-choice" ? ", or 1\u20139 to answer" : "",
|
|
2028
|
+
"."
|
|
2029
|
+
] })
|
|
2030
|
+
]
|
|
2031
|
+
}
|
|
2032
|
+
);
|
|
2033
|
+
}
|
|
2034
|
+
|
|
1245
2035
|
// src/docPlayer/playerAppearance.ts
|
|
1246
2036
|
import {
|
|
1247
2037
|
resolveCoverSlideSettings,
|
|
1248
|
-
resolveThemeForDoc
|
|
2038
|
+
resolveThemeForDoc as resolveThemeForDoc3
|
|
1249
2039
|
} from "@bendyline/squisq/doc";
|
|
1250
2040
|
function readFrontmatterSetting(frontmatter, canonical, legacy) {
|
|
1251
2041
|
if (!frontmatter) return void 0;
|
|
@@ -1303,7 +2093,7 @@ function resolveDocPlayerAppearance(doc, overrides = {}) {
|
|
|
1303
2093
|
...overrides.coverSlidePlayback !== void 0 ? { playback: overrides.coverSlidePlayback } : {}
|
|
1304
2094
|
});
|
|
1305
2095
|
return {
|
|
1306
|
-
theme: overrides.theme ??
|
|
2096
|
+
theme: overrides.theme ?? resolveThemeForDoc3(doc),
|
|
1307
2097
|
videoPresentation: overrides.videoPresentation ?? resolveVideoPresentation(
|
|
1308
2098
|
readFrontmatterSetting(frontmatter, "squisq-video-presentation", "video-presentation")
|
|
1309
2099
|
) ?? "background",
|
|
@@ -1321,14 +2111,14 @@ function resolveDocPlayerAppearance(doc, overrides = {}) {
|
|
|
1321
2111
|
|
|
1322
2112
|
// src/DocPlayer.tsx
|
|
1323
2113
|
import {
|
|
1324
|
-
Fragment as
|
|
2114
|
+
Fragment as Fragment4,
|
|
1325
2115
|
useId as useId2,
|
|
1326
|
-
useRef as
|
|
1327
|
-
useState as
|
|
1328
|
-
useEffect as
|
|
2116
|
+
useRef as useRef7,
|
|
2117
|
+
useState as useState6,
|
|
2118
|
+
useEffect as useEffect7,
|
|
1329
2119
|
useLayoutEffect as useLayoutEffect2,
|
|
1330
|
-
useCallback as
|
|
1331
|
-
useMemo as
|
|
2120
|
+
useCallback as useCallback5,
|
|
2121
|
+
useMemo as useMemo5
|
|
1332
2122
|
} from "react";
|
|
1333
2123
|
import { flushSync } from "react-dom";
|
|
1334
2124
|
import {
|
|
@@ -1340,7 +2130,7 @@ import {
|
|
|
1340
2130
|
import { applySurface, pipStyleVars } from "@bendyline/squisq/schemas";
|
|
1341
2131
|
|
|
1342
2132
|
// src/hooks/useSlideSwipe.ts
|
|
1343
|
-
import { useCallback as
|
|
2133
|
+
import { useCallback as useCallback4, useEffect as useEffect6, useRef as useRef6, useState as useState5 } from "react";
|
|
1344
2134
|
var DISTANCE_RATIO = 0.3;
|
|
1345
2135
|
var FLICK_VELOCITY = 0.5;
|
|
1346
2136
|
var MIN_FLICK_DISTANCE = 12;
|
|
@@ -1364,16 +2154,16 @@ function decideSwipe({
|
|
|
1364
2154
|
}
|
|
1365
2155
|
function useSlideSwipe(opts) {
|
|
1366
2156
|
const settleMs = opts.settleMs ?? DEFAULT_SETTLE_MS;
|
|
1367
|
-
const [offsetPx, setOffsetPx] =
|
|
1368
|
-
const [phase, setPhase] =
|
|
1369
|
-
const optsRef =
|
|
2157
|
+
const [offsetPx, setOffsetPx] = useState5(0);
|
|
2158
|
+
const [phase, setPhase] = useState5("idle");
|
|
2159
|
+
const optsRef = useRef6(opts);
|
|
1370
2160
|
optsRef.current = opts;
|
|
1371
|
-
const dragRef =
|
|
1372
|
-
const phaseRef =
|
|
2161
|
+
const dragRef = useRef6(null);
|
|
2162
|
+
const phaseRef = useRef6("idle");
|
|
1373
2163
|
phaseRef.current = phase;
|
|
1374
|
-
const settleTimer =
|
|
1375
|
-
const settleRaf =
|
|
1376
|
-
const clearPending =
|
|
2164
|
+
const settleTimer = useRef6(null);
|
|
2165
|
+
const settleRaf = useRef6(null);
|
|
2166
|
+
const clearPending = useCallback4(() => {
|
|
1377
2167
|
if (settleTimer.current != null) {
|
|
1378
2168
|
clearTimeout(settleTimer.current);
|
|
1379
2169
|
settleTimer.current = null;
|
|
@@ -1383,7 +2173,7 @@ function useSlideSwipe(opts) {
|
|
|
1383
2173
|
settleRaf.current = null;
|
|
1384
2174
|
}
|
|
1385
2175
|
}, []);
|
|
1386
|
-
const onPointerDown =
|
|
2176
|
+
const onPointerDown = useCallback4((e) => {
|
|
1387
2177
|
const o = optsRef.current;
|
|
1388
2178
|
if (!o.enabled) return;
|
|
1389
2179
|
if (phaseRef.current === "settling") return;
|
|
@@ -1403,7 +2193,7 @@ function useSlideSwipe(opts) {
|
|
|
1403
2193
|
setPhase("dragging");
|
|
1404
2194
|
setOffsetPx(0);
|
|
1405
2195
|
}, []);
|
|
1406
|
-
|
|
2196
|
+
useEffect6(() => {
|
|
1407
2197
|
function currentWidth() {
|
|
1408
2198
|
return optsRef.current.containerRef.current?.getBoundingClientRect().width ?? 0;
|
|
1409
2199
|
}
|
|
@@ -1473,7 +2263,7 @@ function useSlideSwipe(opts) {
|
|
|
1473
2263
|
window.removeEventListener("pointercancel", onCancel);
|
|
1474
2264
|
};
|
|
1475
2265
|
}, [settleMs]);
|
|
1476
|
-
|
|
2266
|
+
useEffect6(() => {
|
|
1477
2267
|
if (!opts.enabled) {
|
|
1478
2268
|
dragRef.current = null;
|
|
1479
2269
|
clearPending();
|
|
@@ -1481,7 +2271,7 @@ function useSlideSwipe(opts) {
|
|
|
1481
2271
|
setOffsetPx(0);
|
|
1482
2272
|
}
|
|
1483
2273
|
}, [opts.enabled, clearPending]);
|
|
1484
|
-
|
|
2274
|
+
useEffect6(() => clearPending, [clearPending]);
|
|
1485
2275
|
return { offsetPx, phase, onPointerDown };
|
|
1486
2276
|
}
|
|
1487
2277
|
|
|
@@ -1490,7 +2280,7 @@ import {
|
|
|
1490
2280
|
expandCoverBlock,
|
|
1491
2281
|
createTemplateContext,
|
|
1492
2282
|
markdownToDoc,
|
|
1493
|
-
VIEWPORT_PRESETS
|
|
2283
|
+
VIEWPORT_PRESETS as VIEWPORT_PRESETS3
|
|
1494
2284
|
} from "@bendyline/squisq/doc";
|
|
1495
2285
|
import { parseMarkdown } from "@bendyline/squisq/markdown";
|
|
1496
2286
|
|
|
@@ -1780,7 +2570,7 @@ function seekVideoToFrame(video, targetTime, timeoutMs = DEFAULT_VIDEO_FRAME_TIM
|
|
|
1780
2570
|
}
|
|
1781
2571
|
|
|
1782
2572
|
// src/DocPlayer.tsx
|
|
1783
|
-
import { jsx as
|
|
2573
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1784
2574
|
function isDevEnvironment() {
|
|
1785
2575
|
try {
|
|
1786
2576
|
return typeof process !== "undefined" && process.env.NODE_ENV !== "production";
|
|
@@ -1812,15 +2602,30 @@ function waitForVisualUpdate() {
|
|
|
1812
2602
|
}
|
|
1813
2603
|
function DocPlayer(props) {
|
|
1814
2604
|
const { doc, markdown } = props;
|
|
1815
|
-
const markdownDoc =
|
|
2605
|
+
const markdownDoc = useMemo5(
|
|
1816
2606
|
() => !doc && markdown !== void 0 ? markdownToDoc(parseMarkdown(markdown)) : void 0,
|
|
1817
2607
|
[doc, markdown]
|
|
1818
2608
|
);
|
|
1819
2609
|
const resolvedDoc = doc ?? markdownDoc;
|
|
1820
2610
|
if (!resolvedDoc) {
|
|
1821
|
-
return /* @__PURE__ */
|
|
2611
|
+
return /* @__PURE__ */ jsx9("div", { className: "doc-player doc-player--empty" });
|
|
1822
2612
|
}
|
|
1823
|
-
|
|
2613
|
+
if (props.displayMode === "flashcards") {
|
|
2614
|
+
return /* @__PURE__ */ jsx9("div", { className: "doc-player doc-player--flashcards", children: /* @__PURE__ */ jsx9(
|
|
2615
|
+
FlashcardView,
|
|
2616
|
+
{
|
|
2617
|
+
doc: resolvedDoc,
|
|
2618
|
+
basePath: props.basePath,
|
|
2619
|
+
theme: props.theme,
|
|
2620
|
+
globalKeyboardShortcuts: props.globalKeyboardShortcuts,
|
|
2621
|
+
showCodeCopyButton: props.showCodeCopyButton,
|
|
2622
|
+
onCopyCode: props.onCopyCode,
|
|
2623
|
+
fenceRenderers: props.fenceRenderers,
|
|
2624
|
+
viewport: props.forceViewport
|
|
2625
|
+
}
|
|
2626
|
+
) });
|
|
2627
|
+
}
|
|
2628
|
+
return /* @__PURE__ */ jsx9(DocPlayerContent, { ...props, doc: resolvedDoc });
|
|
1824
2629
|
}
|
|
1825
2630
|
function DocPlayerContent({
|
|
1826
2631
|
doc,
|
|
@@ -1846,6 +2651,10 @@ function DocPlayerContent({
|
|
|
1846
2651
|
onBlockMarkers,
|
|
1847
2652
|
forceViewport,
|
|
1848
2653
|
displayMode = "video",
|
|
2654
|
+
dashboardLayout,
|
|
2655
|
+
dashboardShowTitle,
|
|
2656
|
+
dashboardStyle,
|
|
2657
|
+
dashboardDocumentTitle,
|
|
1849
2658
|
showCoverSlide,
|
|
1850
2659
|
coverSlideTemplate,
|
|
1851
2660
|
coverSlideDuration,
|
|
@@ -1866,20 +2675,21 @@ function DocPlayerContent({
|
|
|
1866
2675
|
}) {
|
|
1867
2676
|
const isSlideshowMode = displayMode === "slideshow";
|
|
1868
2677
|
const isLinearMode = displayMode === "linear";
|
|
1869
|
-
const
|
|
1870
|
-
const
|
|
2678
|
+
const isDashboardMode = displayMode === "dashboard";
|
|
2679
|
+
const audioRef = useRef7(null);
|
|
2680
|
+
const containerRef = useRef7(null);
|
|
1871
2681
|
const playerId = `squisq-player-${useId2().replace(/:/g, "")}`;
|
|
1872
|
-
const [tapFeedback, setTapFeedback] =
|
|
1873
|
-
const tapFeedbackTimer =
|
|
2682
|
+
const [tapFeedback, setTapFeedback] = useState6(null);
|
|
2683
|
+
const tapFeedbackTimer = useRef7();
|
|
1874
2684
|
const { viewport } = useViewportOrientation();
|
|
1875
|
-
const activeViewport = forceViewport || (renderMode ?
|
|
2685
|
+
const activeViewport = forceViewport || (renderMode ? VIEWPORT_PRESETS3.landscape : viewport);
|
|
1876
2686
|
const activeOrientation = activeViewport.height > activeViewport.width ? "portrait" : "landscape";
|
|
1877
|
-
const isDebugMode =
|
|
2687
|
+
const isDebugMode = useMemo5(() => {
|
|
1878
2688
|
if (typeof window === "undefined") return false;
|
|
1879
2689
|
const params = new URLSearchParams(window.location.search);
|
|
1880
2690
|
return params.get("debug") === "true";
|
|
1881
2691
|
}, []);
|
|
1882
|
-
const syntheticDuration =
|
|
2692
|
+
const syntheticDuration = useMemo5(
|
|
1883
2693
|
() => audioMode === "synthetic" ? getDocPlaybackDuration(doc) : 0,
|
|
1884
2694
|
[audioMode, doc]
|
|
1885
2695
|
);
|
|
@@ -1892,7 +2702,7 @@ function DocPlayerContent({
|
|
|
1892
2702
|
syntheticDuration
|
|
1893
2703
|
);
|
|
1894
2704
|
const audio = externalAudioController || internalAudio;
|
|
1895
|
-
|
|
2705
|
+
useEffect7(() => {
|
|
1896
2706
|
if (warnedMissingStyles || !isDevEnvironment()) return;
|
|
1897
2707
|
const el = containerRef.current;
|
|
1898
2708
|
if (!el || typeof getComputedStyle !== "function") return;
|
|
@@ -1920,16 +2730,16 @@ function DocPlayerContent({
|
|
|
1920
2730
|
skipToSegment: _skipToSegment,
|
|
1921
2731
|
restart
|
|
1922
2732
|
} = audio;
|
|
1923
|
-
const [renderClock, setRenderClock] =
|
|
2733
|
+
const [renderClock, setRenderClock] = useState6(null);
|
|
1924
2734
|
const renderTimeOverride = renderClock?.doc === doc ? renderClock.time : null;
|
|
1925
2735
|
const currentTime = renderMode ? renderTimeOverride ?? audioCurrentTime : audioCurrentTime;
|
|
1926
|
-
const rawSchedule =
|
|
2736
|
+
const rawSchedule = useMemo5(() => resolveMediaSchedule(doc), [doc]);
|
|
1927
2737
|
const clipDurations = useMediaClipDurations(rawSchedule, basePath);
|
|
1928
|
-
const mediaSchedule =
|
|
2738
|
+
const mediaSchedule = useMemo5(
|
|
1929
2739
|
() => resolveMediaSchedule(doc, { intrinsicDuration: (clip) => clipDurations.get(clip.src) }),
|
|
1930
2740
|
[doc, clipDurations]
|
|
1931
2741
|
);
|
|
1932
|
-
const startActiveTimelineMedia =
|
|
2742
|
+
const startActiveTimelineMedia = useCallback5(() => {
|
|
1933
2743
|
if (renderMode) return;
|
|
1934
2744
|
const root = containerRef.current;
|
|
1935
2745
|
if (!root) return;
|
|
@@ -1942,21 +2752,21 @@ function DocPlayerContent({
|
|
|
1942
2752
|
});
|
|
1943
2753
|
});
|
|
1944
2754
|
}, [renderMode]);
|
|
1945
|
-
const playWithTimelineMedia =
|
|
2755
|
+
const playWithTimelineMedia = useCallback5(() => {
|
|
1946
2756
|
startActiveTimelineMedia();
|
|
1947
2757
|
return play();
|
|
1948
2758
|
}, [play, startActiveTimelineMedia]);
|
|
1949
|
-
const toggleWithTimelineMedia =
|
|
2759
|
+
const toggleWithTimelineMedia = useCallback5(() => {
|
|
1950
2760
|
if (!isPlaying) startActiveTimelineMedia();
|
|
1951
2761
|
return toggle();
|
|
1952
2762
|
}, [isPlaying, startActiveTimelineMedia, toggle]);
|
|
1953
|
-
const currentTimeRef =
|
|
2763
|
+
const currentTimeRef = useRef7(currentTime);
|
|
1954
2764
|
currentTimeRef.current = currentTime;
|
|
1955
|
-
const committedRenderTimeRef =
|
|
1956
|
-
const renderCommitWaitersRef =
|
|
1957
|
-
const totalDurationRef =
|
|
2765
|
+
const committedRenderTimeRef = useRef7(currentTime);
|
|
2766
|
+
const renderCommitWaitersRef = useRef7([]);
|
|
2767
|
+
const totalDurationRef = useRef7(totalDuration);
|
|
1958
2768
|
totalDurationRef.current = totalDuration;
|
|
1959
|
-
const expandedBlocksLenRef =
|
|
2769
|
+
const expandedBlocksLenRef = useRef7(0);
|
|
1960
2770
|
useLayoutEffect2(() => {
|
|
1961
2771
|
committedRenderTimeRef.current = currentTime;
|
|
1962
2772
|
const pending = renderCommitWaitersRef.current;
|
|
@@ -1966,14 +2776,14 @@ function DocPlayerContent({
|
|
|
1966
2776
|
return false;
|
|
1967
2777
|
});
|
|
1968
2778
|
}, [currentTime]);
|
|
1969
|
-
|
|
2779
|
+
useEffect7(
|
|
1970
2780
|
() => () => {
|
|
1971
2781
|
const error = new Error("DocPlayer unmounted before the requested frame committed.");
|
|
1972
2782
|
renderCommitWaitersRef.current.splice(0).forEach((waiter) => waiter.reject(error));
|
|
1973
2783
|
},
|
|
1974
2784
|
[]
|
|
1975
2785
|
);
|
|
1976
|
-
const waitForRenderCommit =
|
|
2786
|
+
const waitForRenderCommit = useCallback5((time) => {
|
|
1977
2787
|
if (Math.abs(committedRenderTimeRef.current - time) <= RENDER_TIME_EPSILON_SECONDS) {
|
|
1978
2788
|
return Promise.resolve();
|
|
1979
2789
|
}
|
|
@@ -1981,7 +2791,7 @@ function DocPlayerContent({
|
|
|
1981
2791
|
renderCommitWaitersRef.current.push({ time, resolve, reject });
|
|
1982
2792
|
});
|
|
1983
2793
|
}, []);
|
|
1984
|
-
const handleContainerClick =
|
|
2794
|
+
const handleContainerClick = useCallback5(
|
|
1985
2795
|
(e) => {
|
|
1986
2796
|
if (renderMode || isLinearMode) return;
|
|
1987
2797
|
const target = e.target;
|
|
@@ -2006,7 +2816,7 @@ function DocPlayerContent({
|
|
|
2006
2816
|
);
|
|
2007
2817
|
const autoSurface = useAutoSurface(surface === "auto");
|
|
2008
2818
|
const resolvedSurface = surface === "auto" ? autoSurface : surface;
|
|
2009
|
-
const appearance =
|
|
2819
|
+
const appearance = useMemo5(
|
|
2010
2820
|
() => resolveDocPlayerAppearance(doc, {
|
|
2011
2821
|
theme,
|
|
2012
2822
|
videoPresentation,
|
|
@@ -2031,13 +2841,13 @@ function DocPlayerContent({
|
|
|
2031
2841
|
coverSlidePlayback
|
|
2032
2842
|
]
|
|
2033
2843
|
);
|
|
2034
|
-
const effectiveTheme =
|
|
2844
|
+
const effectiveTheme = useMemo5(() => {
|
|
2035
2845
|
const base = appearance.theme;
|
|
2036
2846
|
return resolvedSurface ? applySurface(base, resolvedSurface) : base;
|
|
2037
2847
|
}, [appearance.theme, resolvedSurface]);
|
|
2038
|
-
const resolvedPipStyle =
|
|
2848
|
+
const resolvedPipStyle = useMemo5(() => pipStyleVars(effectiveTheme), [effectiveTheme]);
|
|
2039
2849
|
const pipVars = resolvedPipStyle;
|
|
2040
|
-
const pipFrameStyle =
|
|
2850
|
+
const pipFrameStyle = useMemo5(
|
|
2041
2851
|
() => ({
|
|
2042
2852
|
border: resolvedPipStyle["--squisq-pip-border"],
|
|
2043
2853
|
borderRadius: resolvedPipStyle["--squisq-pip-radius"],
|
|
@@ -2067,7 +2877,7 @@ function DocPlayerContent({
|
|
|
2067
2877
|
// remove authored slides from the default loss-averse projection.
|
|
2068
2878
|
useAudioSegmentTiming: audioMode !== "synthetic"
|
|
2069
2879
|
});
|
|
2070
|
-
const coverBlock =
|
|
2880
|
+
const coverBlock = useMemo5(() => {
|
|
2071
2881
|
const startBlockConfig = doc.startBlock;
|
|
2072
2882
|
if (!appearance.showCoverSlide) return null;
|
|
2073
2883
|
if (!startBlockConfig) return null;
|
|
@@ -2090,13 +2900,13 @@ function DocPlayerContent({
|
|
|
2090
2900
|
appearance.coverSlideTemplate
|
|
2091
2901
|
]);
|
|
2092
2902
|
const hasManagedCover = !!coverBlock;
|
|
2093
|
-
const [slideshowCoverVisible, setSlideshowCoverVisible] =
|
|
2094
|
-
const [isSlideshowPickerOpen, setIsSlideshowPickerOpen] =
|
|
2095
|
-
const slideshowCoverInitKeyRef =
|
|
2096
|
-
|
|
2903
|
+
const [slideshowCoverVisible, setSlideshowCoverVisible] = useState6(false);
|
|
2904
|
+
const [isSlideshowPickerOpen, setIsSlideshowPickerOpen] = useState6(false);
|
|
2905
|
+
const slideshowCoverInitKeyRef = useRef7("");
|
|
2906
|
+
useEffect7(() => {
|
|
2097
2907
|
slideshowCoverInitKeyRef.current = "";
|
|
2098
2908
|
}, [doc]);
|
|
2099
|
-
|
|
2909
|
+
useEffect7(() => {
|
|
2100
2910
|
const initKey = `${isSlideshowMode}:${hasManagedCover}:${renderMode}`;
|
|
2101
2911
|
if (slideshowCoverInitKeyRef.current === initKey) return;
|
|
2102
2912
|
slideshowCoverInitKeyRef.current = initKey;
|
|
@@ -2107,12 +2917,12 @@ function DocPlayerContent({
|
|
|
2107
2917
|
setSlideshowCoverVisible(false);
|
|
2108
2918
|
}
|
|
2109
2919
|
}, [isSlideshowMode, hasManagedCover, renderMode, pause]);
|
|
2110
|
-
const [coverForced, setCoverForced] =
|
|
2111
|
-
const [coverGraceActive, setCoverGraceActive] =
|
|
2112
|
-
const coverGraceTimer =
|
|
2113
|
-
const coverWasShowing =
|
|
2114
|
-
const hasPlayedOnce =
|
|
2115
|
-
|
|
2920
|
+
const [coverForced, setCoverForced] = useState6(false);
|
|
2921
|
+
const [coverGraceActive, setCoverGraceActive] = useState6(false);
|
|
2922
|
+
const coverGraceTimer = useRef7();
|
|
2923
|
+
const coverWasShowing = useRef7(false);
|
|
2924
|
+
const hasPlayedOnce = useRef7(false);
|
|
2925
|
+
useEffect7(() => {
|
|
2116
2926
|
hasPlayedOnce.current = false;
|
|
2117
2927
|
coverWasShowing.current = false;
|
|
2118
2928
|
clearTimeout(coverGraceTimer.current);
|
|
@@ -2121,7 +2931,7 @@ function DocPlayerContent({
|
|
|
2121
2931
|
}, [doc]);
|
|
2122
2932
|
const atRest = !!(coverBlock && !isSlideshowMode && !isPlaying && currentTime === 0 && !hasPlayedOnce.current && !renderMode && !autoPlay);
|
|
2123
2933
|
if (atRest) coverWasShowing.current = true;
|
|
2124
|
-
|
|
2934
|
+
useEffect7(() => {
|
|
2125
2935
|
if (isPlaying && coverWasShowing.current && coverBlock && !renderMode && !isSlideshowMode) {
|
|
2126
2936
|
coverWasShowing.current = false;
|
|
2127
2937
|
hasPlayedOnce.current = true;
|
|
@@ -2132,8 +2942,8 @@ function DocPlayerContent({
|
|
|
2132
2942
|
);
|
|
2133
2943
|
}
|
|
2134
2944
|
}, [isPlaying, coverBlock, renderMode, isSlideshowMode, appearance.coverSlideDuration]);
|
|
2135
|
-
|
|
2136
|
-
|
|
2945
|
+
useEffect7(() => () => clearTimeout(coverGraceTimer.current), []);
|
|
2946
|
+
useEffect7(() => () => clearTimeout(tapFeedbackTimer.current), []);
|
|
2137
2947
|
const showVideoCoverBlock = !isSlideshowMode && !isLinearMode && !!coverBlock && (coverForced || coverGraceActive || !isPlaying && currentTime === 0 && !hasPlayedOnce.current && !renderMode && !autoPlay);
|
|
2138
2948
|
const effectiveSlideshowCoverVisible = coverVisible ?? slideshowCoverVisible;
|
|
2139
2949
|
const showSlideshowCover = !!(isSlideshowMode && !isLinearMode && !renderMode && coverBlock && effectiveSlideshowCoverVisible);
|
|
@@ -2141,29 +2951,29 @@ function DocPlayerContent({
|
|
|
2141
2951
|
const slideshowHasCover = !!(isSlideshowMode && !renderMode && coverBlock);
|
|
2142
2952
|
const slideshowSlideIndex = slideshowHasCover ? effectiveSlideshowCoverVisible ? 0 : currentBlockIndex + 1 : currentBlockIndex;
|
|
2143
2953
|
const slideshowTotalSlides = slideshowHasCover ? expandedBlocks.length + 1 : expandedBlocks.length;
|
|
2144
|
-
const hasAutoPlayed =
|
|
2145
|
-
|
|
2954
|
+
const hasAutoPlayed = useRef7(false);
|
|
2955
|
+
useEffect7(() => {
|
|
2146
2956
|
hasAutoPlayed.current = false;
|
|
2147
2957
|
}, [doc]);
|
|
2148
|
-
|
|
2958
|
+
useEffect7(() => {
|
|
2149
2959
|
if (isAudioReady && autoPlay && !hasAutoPlayed.current) {
|
|
2150
2960
|
hasAutoPlayed.current = true;
|
|
2151
2961
|
playWithTimelineMedia();
|
|
2152
2962
|
}
|
|
2153
2963
|
}, [isAudioReady, autoPlay, playWithTimelineMedia]);
|
|
2154
|
-
|
|
2964
|
+
useEffect7(() => {
|
|
2155
2965
|
onTimeUpdate?.(currentTime);
|
|
2156
2966
|
}, [currentTime, onTimeUpdate]);
|
|
2157
|
-
|
|
2967
|
+
useEffect7(() => {
|
|
2158
2968
|
if (isEnded) {
|
|
2159
2969
|
onEnded?.();
|
|
2160
|
-
if (loop && !isSlideshowMode && !isLinearMode) {
|
|
2970
|
+
if (loop && !isSlideshowMode && !isLinearMode && !isDashboardMode) {
|
|
2161
2971
|
void restart();
|
|
2162
2972
|
}
|
|
2163
2973
|
}
|
|
2164
|
-
}, [isEnded, isLinearMode, isSlideshowMode, loop, onEnded, restart]);
|
|
2165
|
-
const liveRenderAPIRef =
|
|
2166
|
-
const stableRenderAPIRef =
|
|
2974
|
+
}, [isEnded, isDashboardMode, isLinearMode, isSlideshowMode, loop, onEnded, restart]);
|
|
2975
|
+
const liveRenderAPIRef = useRef7(null);
|
|
2976
|
+
const stableRenderAPIRef = useRef7(null);
|
|
2167
2977
|
if (!stableRenderAPIRef.current) {
|
|
2168
2978
|
const current = () => {
|
|
2169
2979
|
const api = liveRenderAPIRef.current;
|
|
@@ -2184,8 +2994,8 @@ function DocPlayerContent({
|
|
|
2184
2994
|
};
|
|
2185
2995
|
}
|
|
2186
2996
|
const stableRenderAPI = stableRenderAPIRef.current;
|
|
2187
|
-
|
|
2188
|
-
if (!renderMode && !isDebugMode) {
|
|
2997
|
+
useEffect7(() => {
|
|
2998
|
+
if (isDashboardMode || !renderMode && !isDebugMode) {
|
|
2189
2999
|
liveRenderAPIRef.current = null;
|
|
2190
3000
|
return;
|
|
2191
3001
|
}
|
|
@@ -2311,31 +3121,33 @@ function DocPlayerContent({
|
|
|
2311
3121
|
coverBlock,
|
|
2312
3122
|
doc,
|
|
2313
3123
|
externalAudioController,
|
|
2314
|
-
waitForRenderCommit
|
|
3124
|
+
waitForRenderCommit,
|
|
3125
|
+
isDashboardMode
|
|
2315
3126
|
]);
|
|
2316
|
-
|
|
3127
|
+
useEffect7(() => {
|
|
3128
|
+
if (isDashboardMode) return;
|
|
2317
3129
|
if (!renderMode && !isDebugMode || !containerRef.current) {
|
|
2318
3130
|
onRenderAPIReady?.(null);
|
|
2319
3131
|
return;
|
|
2320
3132
|
}
|
|
2321
3133
|
onRenderAPIReady?.(stableRenderAPI);
|
|
2322
3134
|
return () => onRenderAPIReady?.(null);
|
|
2323
|
-
}, [renderMode, isDebugMode, onRenderAPIReady, stableRenderAPI]);
|
|
3135
|
+
}, [renderMode, isDebugMode, isDashboardMode, onRenderAPIReady, stableRenderAPI]);
|
|
2324
3136
|
const defaultMode = captionsEnabledProp === false ? "off" : captionStyle || "standard";
|
|
2325
|
-
const [captionMode, setCaptionMode] =
|
|
2326
|
-
|
|
3137
|
+
const [captionMode, setCaptionMode] = useState6(defaultMode);
|
|
3138
|
+
useEffect7(() => {
|
|
2327
3139
|
setCaptionMode(defaultMode);
|
|
2328
3140
|
}, [defaultMode]);
|
|
2329
3141
|
const captionsEnabled = captionMode !== "off";
|
|
2330
3142
|
const activeCaptionStyle = captionMode === "social" ? "social" : "standard";
|
|
2331
|
-
const setCaptionsEnabled =
|
|
3143
|
+
const setCaptionsEnabled = useCallback5(
|
|
2332
3144
|
(enabled) => {
|
|
2333
3145
|
setCaptionMode(enabled ? captionStyle || "standard" : "off");
|
|
2334
3146
|
onCaptionsToggle?.(enabled);
|
|
2335
3147
|
},
|
|
2336
3148
|
[onCaptionsToggle, captionStyle]
|
|
2337
3149
|
);
|
|
2338
|
-
const cycleCaptionMode =
|
|
3150
|
+
const cycleCaptionMode = useCallback5(() => {
|
|
2339
3151
|
setCaptionMode((prev) => {
|
|
2340
3152
|
const next = prev === "off" ? "standard" : prev === "standard" ? "social" : "off";
|
|
2341
3153
|
onCaptionsToggle?.(next !== "off");
|
|
@@ -2343,8 +3155,8 @@ function DocPlayerContent({
|
|
|
2343
3155
|
});
|
|
2344
3156
|
}, [onCaptionsToggle]);
|
|
2345
3157
|
const hasCaptions = doc.captions && doc.captions.phrases.length > 0;
|
|
2346
|
-
const segmentTitleMap =
|
|
2347
|
-
const playbackState =
|
|
3158
|
+
const segmentTitleMap = useMemo5(() => buildSegmentTitleMap(doc), [doc]);
|
|
3159
|
+
const playbackState = useMemo5(
|
|
2348
3160
|
() => ({
|
|
2349
3161
|
isPlaying,
|
|
2350
3162
|
currentTime,
|
|
@@ -2387,7 +3199,7 @@ function DocPlayerContent({
|
|
|
2387
3199
|
expandedBlocks.length
|
|
2388
3200
|
]
|
|
2389
3201
|
);
|
|
2390
|
-
const playbackActions =
|
|
3202
|
+
const playbackActions = useMemo5(
|
|
2391
3203
|
() => ({
|
|
2392
3204
|
toggle: toggleWithTimelineMedia,
|
|
2393
3205
|
restart,
|
|
@@ -2405,7 +3217,7 @@ function DocPlayerContent({
|
|
|
2405
3217
|
onFullscreenToggle
|
|
2406
3218
|
]
|
|
2407
3219
|
);
|
|
2408
|
-
const slideNavActions =
|
|
3220
|
+
const slideNavActions = useMemo5(
|
|
2409
3221
|
() => ({
|
|
2410
3222
|
nextSlide: () => {
|
|
2411
3223
|
if (slideshowHasCover && slideshowCoverVisible) {
|
|
@@ -2470,7 +3282,7 @@ function DocPlayerContent({
|
|
|
2470
3282
|
[currentBlockIndex, expandedBlocks, seekTo, pause, slideshowHasCover, slideshowCoverVisible]
|
|
2471
3283
|
);
|
|
2472
3284
|
const swipeEnabled = isSlideshowMode && !isLinearMode && !renderMode && enableSwipe;
|
|
2473
|
-
const armContextFreeSwipeEntry =
|
|
3285
|
+
const armContextFreeSwipeEntry = useCallback5(
|
|
2474
3286
|
(destinationSlideIndex) => {
|
|
2475
3287
|
const destinationBlockIndex = destinationSlideIndex - (slideshowHasCover ? 1 : 0);
|
|
2476
3288
|
const destinationBlock = expandedBlocks[destinationBlockIndex];
|
|
@@ -2478,11 +3290,11 @@ function DocPlayerContent({
|
|
|
2478
3290
|
},
|
|
2479
3291
|
[expandedBlocks, slideshowHasCover, suppressOutgoingForNextBlock]
|
|
2480
3292
|
);
|
|
2481
|
-
const handleSwipeNext =
|
|
3293
|
+
const handleSwipeNext = useCallback5(() => {
|
|
2482
3294
|
armContextFreeSwipeEntry(slideshowSlideIndex + 1);
|
|
2483
3295
|
slideNavActions.nextSlide();
|
|
2484
3296
|
}, [armContextFreeSwipeEntry, slideshowSlideIndex, slideNavActions]);
|
|
2485
|
-
const handleSwipePrev =
|
|
3297
|
+
const handleSwipePrev = useCallback5(() => {
|
|
2486
3298
|
armContextFreeSwipeEntry(slideshowSlideIndex - 1);
|
|
2487
3299
|
slideNavActions.prevSlide();
|
|
2488
3300
|
}, [armContextFreeSwipeEntry, slideshowSlideIndex, slideNavActions]);
|
|
@@ -2494,13 +3306,13 @@ function DocPlayerContent({
|
|
|
2494
3306
|
onNext: handleSwipeNext,
|
|
2495
3307
|
onPrev: handleSwipePrev
|
|
2496
3308
|
});
|
|
2497
|
-
|
|
3309
|
+
useEffect7(() => {
|
|
2498
3310
|
onPlaybackStateChange?.(playbackState);
|
|
2499
3311
|
}, [playbackState, onPlaybackStateChange]);
|
|
2500
|
-
|
|
3312
|
+
useEffect7(() => {
|
|
2501
3313
|
onControlsReady?.({ play: playWithTimelineMedia, pause, ...playbackActions });
|
|
2502
3314
|
}, [playWithTimelineMedia, pause, playbackActions, onControlsReady]);
|
|
2503
|
-
const getBlockTitle =
|
|
3315
|
+
const getBlockTitle = useCallback5((block) => {
|
|
2504
3316
|
const docBlock = block;
|
|
2505
3317
|
if (isTemplateBlock2(docBlock)) {
|
|
2506
3318
|
const props = docBlock;
|
|
@@ -2524,7 +3336,7 @@ function DocPlayerContent({
|
|
|
2524
3336
|
}
|
|
2525
3337
|
return block.id.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
2526
3338
|
}, []);
|
|
2527
|
-
const slideshowPickerItems =
|
|
3339
|
+
const slideshowPickerItems = useMemo5(() => {
|
|
2528
3340
|
const blockItems = expandedBlocks.map((block, index) => ({
|
|
2529
3341
|
id: block.id,
|
|
2530
3342
|
label: String(index + 1),
|
|
@@ -2540,7 +3352,7 @@ function DocPlayerContent({
|
|
|
2540
3352
|
...blockItems
|
|
2541
3353
|
];
|
|
2542
3354
|
}, [coverBlock, expandedBlocks, getBlockTitle, slideshowHasCover]);
|
|
2543
|
-
const blockMarkers =
|
|
3355
|
+
const blockMarkers = useMemo5(() => {
|
|
2544
3356
|
if (!totalDuration || !expandedBlocks.length) return [];
|
|
2545
3357
|
let prevSegment = -1;
|
|
2546
3358
|
return expandedBlocks.map((block, index) => {
|
|
@@ -2555,13 +3367,13 @@ function DocPlayerContent({
|
|
|
2555
3367
|
};
|
|
2556
3368
|
});
|
|
2557
3369
|
}, [expandedBlocks, totalDuration, getBlockTitle]);
|
|
2558
|
-
|
|
3370
|
+
useEffect7(() => {
|
|
2559
3371
|
if (blockMarkers.length > 0) {
|
|
2560
3372
|
onBlockMarkers?.(blockMarkers);
|
|
2561
3373
|
}
|
|
2562
3374
|
}, [blockMarkers, onBlockMarkers]);
|
|
2563
3375
|
expandedBlocksLenRef.current = isSlideshowMode ? slideshowTotalSlides : expandedBlocks.length;
|
|
2564
|
-
const handleKeyboardShortcut =
|
|
3376
|
+
const handleKeyboardShortcut = useCallback5(
|
|
2565
3377
|
(e, global) => {
|
|
2566
3378
|
if (e.defaultPrevented || e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;
|
|
2567
3379
|
const target = e.target instanceof Element ? e.target : null;
|
|
@@ -2577,7 +3389,7 @@ function DocPlayerContent({
|
|
|
2577
3389
|
) && !isSlideshowToolbarTarget) {
|
|
2578
3390
|
return;
|
|
2579
3391
|
}
|
|
2580
|
-
if (isLinearMode) return;
|
|
3392
|
+
if (isLinearMode || isDashboardMode) return;
|
|
2581
3393
|
if (e.key === "f" || e.key === "F") {
|
|
2582
3394
|
if (!onFullscreenToggle) return;
|
|
2583
3395
|
e.preventDefault();
|
|
@@ -2629,26 +3441,27 @@ function DocPlayerContent({
|
|
|
2629
3441
|
[
|
|
2630
3442
|
isSlideshowMode,
|
|
2631
3443
|
isLinearMode,
|
|
3444
|
+
isDashboardMode,
|
|
2632
3445
|
toggleWithTimelineMedia,
|
|
2633
3446
|
seekTo,
|
|
2634
3447
|
slideNavActions,
|
|
2635
3448
|
onFullscreenToggle
|
|
2636
3449
|
]
|
|
2637
3450
|
);
|
|
2638
|
-
const handleKeyDown =
|
|
3451
|
+
const handleKeyDown = useCallback5(
|
|
2639
3452
|
(e) => handleKeyboardShortcut(e, false),
|
|
2640
3453
|
[handleKeyboardShortcut]
|
|
2641
3454
|
);
|
|
2642
|
-
|
|
2643
|
-
if (!globalKeyboardShortcuts || renderMode || isLinearMode) return;
|
|
3455
|
+
useEffect7(() => {
|
|
3456
|
+
if (!globalKeyboardShortcuts || renderMode || isLinearMode || isDashboardMode) return;
|
|
2644
3457
|
const handleDocumentKeyDown = (event) => {
|
|
2645
3458
|
handleKeyboardShortcut(event, true);
|
|
2646
3459
|
};
|
|
2647
3460
|
document.addEventListener("keydown", handleDocumentKeyDown);
|
|
2648
3461
|
return () => document.removeEventListener("keydown", handleDocumentKeyDown);
|
|
2649
|
-
}, [globalKeyboardShortcuts, handleKeyboardShortcut, isLinearMode, renderMode]);
|
|
3462
|
+
}, [globalKeyboardShortcuts, handleKeyboardShortcut, isDashboardMode, isLinearMode, renderMode]);
|
|
2650
3463
|
if (isLinearMode) {
|
|
2651
|
-
return /* @__PURE__ */
|
|
3464
|
+
return /* @__PURE__ */ jsx9(
|
|
2652
3465
|
"div",
|
|
2653
3466
|
{
|
|
2654
3467
|
ref: containerRef,
|
|
@@ -2660,7 +3473,7 @@ function DocPlayerContent({
|
|
|
2660
3473
|
height: "100%",
|
|
2661
3474
|
overflow: "hidden"
|
|
2662
3475
|
},
|
|
2663
|
-
children: /* @__PURE__ */
|
|
3476
|
+
children: /* @__PURE__ */ jsx9(
|
|
2664
3477
|
LinearDocView,
|
|
2665
3478
|
{
|
|
2666
3479
|
doc,
|
|
@@ -2677,7 +3490,41 @@ function DocPlayerContent({
|
|
|
2677
3490
|
}
|
|
2678
3491
|
);
|
|
2679
3492
|
}
|
|
2680
|
-
|
|
3493
|
+
if (isDashboardMode) {
|
|
3494
|
+
return /* @__PURE__ */ jsx9(
|
|
3495
|
+
"div",
|
|
3496
|
+
{
|
|
3497
|
+
ref: containerRef,
|
|
3498
|
+
"data-player-id": playerId,
|
|
3499
|
+
className: "doc-player doc-player--dashboard",
|
|
3500
|
+
style: {
|
|
3501
|
+
position: "relative",
|
|
3502
|
+
width: "100%",
|
|
3503
|
+
aspectRatio: `${activeViewport.width} / ${activeViewport.height}`,
|
|
3504
|
+
margin: "0 auto",
|
|
3505
|
+
overflow: "hidden"
|
|
3506
|
+
},
|
|
3507
|
+
children: /* @__PURE__ */ jsx9(
|
|
3508
|
+
DashboardView,
|
|
3509
|
+
{
|
|
3510
|
+
doc,
|
|
3511
|
+
theme,
|
|
3512
|
+
viewport: activeViewport,
|
|
3513
|
+
layout: dashboardLayout,
|
|
3514
|
+
showTitle: dashboardShowTitle,
|
|
3515
|
+
style: dashboardStyle,
|
|
3516
|
+
documentTitle: dashboardDocumentTitle,
|
|
3517
|
+
basePath,
|
|
3518
|
+
animationsEnabled,
|
|
3519
|
+
muted: renderMode || muted,
|
|
3520
|
+
renderMode: renderMode || isDebugMode,
|
|
3521
|
+
onRenderAPIReady
|
|
3522
|
+
}
|
|
3523
|
+
)
|
|
3524
|
+
}
|
|
3525
|
+
);
|
|
3526
|
+
}
|
|
3527
|
+
return /* @__PURE__ */ jsxs6(
|
|
2681
3528
|
"div",
|
|
2682
3529
|
{
|
|
2683
3530
|
ref: containerRef,
|
|
@@ -2705,8 +3552,8 @@ function DocPlayerContent({
|
|
|
2705
3552
|
touchAction: swipeEnabled ? "pan-y" : void 0
|
|
2706
3553
|
},
|
|
2707
3554
|
children: [
|
|
2708
|
-
/* @__PURE__ */
|
|
2709
|
-
/* @__PURE__ */
|
|
3555
|
+
/* @__PURE__ */ jsx9("audio", { ref: audioRef, preload: "auto", muted }),
|
|
3556
|
+
/* @__PURE__ */ jsx9(
|
|
2710
3557
|
MediaClipLayer,
|
|
2711
3558
|
{
|
|
2712
3559
|
schedule: mediaSchedule,
|
|
@@ -2723,8 +3570,8 @@ function DocPlayerContent({
|
|
|
2723
3570
|
pipFrameStyle
|
|
2724
3571
|
}
|
|
2725
3572
|
),
|
|
2726
|
-
/* @__PURE__ */
|
|
2727
|
-
showCoverBlock && coverBlock && /* @__PURE__ */
|
|
3573
|
+
/* @__PURE__ */ jsxs6("div", { className: "doc-player__viewport", children: [
|
|
3574
|
+
showCoverBlock && coverBlock && /* @__PURE__ */ jsx9("div", { className: "doc-player__block doc-player__block--cover", children: /* @__PURE__ */ jsx9(
|
|
2728
3575
|
BlockRenderer,
|
|
2729
3576
|
{
|
|
2730
3577
|
block: coverBlock,
|
|
@@ -2741,7 +3588,7 @@ function DocPlayerContent({
|
|
|
2741
3588
|
// reconciles one block's layers onto another's (templates reuse layer
|
|
2742
3589
|
// ids like `title`/`background`), which would otherwise reuse stale
|
|
2743
3590
|
// DOM / skip entrance animations mid-transition.
|
|
2744
|
-
/* @__PURE__ */
|
|
3591
|
+
/* @__PURE__ */ jsx9("div", { className: "doc-player__block doc-player__block--previous", children: /* @__PURE__ */ jsx9(
|
|
2745
3592
|
BlockRenderer,
|
|
2746
3593
|
{
|
|
2747
3594
|
block: previousBlock,
|
|
@@ -2755,7 +3602,7 @@ function DocPlayerContent({
|
|
|
2755
3602
|
theme: effectiveTheme
|
|
2756
3603
|
}
|
|
2757
3604
|
) }, previousBlock.id),
|
|
2758
|
-
currentBlock && /* @__PURE__ */
|
|
3605
|
+
currentBlock && /* @__PURE__ */ jsx9(
|
|
2759
3606
|
"div",
|
|
2760
3607
|
{
|
|
2761
3608
|
className: `doc-player__block doc-player__block--active${swipe.phase !== "idle" ? ` doc-player__block--${swipe.phase}` : ""}`,
|
|
@@ -2764,7 +3611,7 @@ function DocPlayerContent({
|
|
|
2764
3611
|
...swipe.phase !== "idle" ? { transform: `translateX(${swipe.offsetPx}px)` } : {},
|
|
2765
3612
|
...showCoverBlock ? { opacity: 0, pointerEvents: "none" } : {}
|
|
2766
3613
|
} : void 0,
|
|
2767
|
-
children: /* @__PURE__ */
|
|
3614
|
+
children: /* @__PURE__ */ jsx9(
|
|
2768
3615
|
BlockRenderer,
|
|
2769
3616
|
{
|
|
2770
3617
|
block: currentBlock,
|
|
@@ -2781,7 +3628,7 @@ function DocPlayerContent({
|
|
|
2781
3628
|
},
|
|
2782
3629
|
currentBlock.id
|
|
2783
3630
|
),
|
|
2784
|
-
hasCaptions && (renderMode ? captionsEnabled : true) && /* @__PURE__ */
|
|
3631
|
+
hasCaptions && (renderMode ? captionsEnabled : true) && /* @__PURE__ */ jsx9(
|
|
2785
3632
|
CaptionOverlay,
|
|
2786
3633
|
{
|
|
2787
3634
|
captions: doc.captions,
|
|
@@ -2793,7 +3640,7 @@ function DocPlayerContent({
|
|
|
2793
3640
|
viewport: activeViewport
|
|
2794
3641
|
}
|
|
2795
3642
|
),
|
|
2796
|
-
isDebugMode && /* @__PURE__ */
|
|
3643
|
+
isDebugMode && /* @__PURE__ */ jsxs6(
|
|
2797
3644
|
"div",
|
|
2798
3645
|
{
|
|
2799
3646
|
className: "doc-player__debug",
|
|
@@ -2814,27 +3661,27 @@ function DocPlayerContent({
|
|
|
2814
3661
|
textAlign: "left"
|
|
2815
3662
|
},
|
|
2816
3663
|
children: [
|
|
2817
|
-
/* @__PURE__ */
|
|
2818
|
-
/* @__PURE__ */
|
|
2819
|
-
/* @__PURE__ */
|
|
3664
|
+
/* @__PURE__ */ jsx9("div", { style: { color: "#ffcc00", fontWeight: "bold", marginBottom: "4px" }, children: "DEBUG MODE" }),
|
|
3665
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
3666
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "#888" }, children: "template:" }),
|
|
2820
3667
|
" ",
|
|
2821
|
-
/* @__PURE__ */
|
|
3668
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "#ff6b6b" }, children: currentBlock?.template ?? "raw" })
|
|
2822
3669
|
] }),
|
|
2823
|
-
/* @__PURE__ */
|
|
2824
|
-
/* @__PURE__ */
|
|
3670
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
3671
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "#888" }, children: "block:" }),
|
|
2825
3672
|
" ",
|
|
2826
3673
|
currentBlockIndex + 1,
|
|
2827
3674
|
"/",
|
|
2828
3675
|
expandedBlocks.length,
|
|
2829
3676
|
" ",
|
|
2830
|
-
/* @__PURE__ */
|
|
3677
|
+
/* @__PURE__ */ jsxs6("span", { style: { color: "#666" }, children: [
|
|
2831
3678
|
"(",
|
|
2832
3679
|
currentBlock?.id || "none",
|
|
2833
3680
|
")"
|
|
2834
3681
|
] })
|
|
2835
3682
|
] }),
|
|
2836
|
-
/* @__PURE__ */
|
|
2837
|
-
/* @__PURE__ */
|
|
3683
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
3684
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "#888" }, children: "time:" }),
|
|
2838
3685
|
" ",
|
|
2839
3686
|
currentTime.toFixed(2),
|
|
2840
3687
|
"s /",
|
|
@@ -2842,7 +3689,7 @@ function DocPlayerContent({
|
|
|
2842
3689
|
totalDuration.toFixed(1),
|
|
2843
3690
|
"s",
|
|
2844
3691
|
" ",
|
|
2845
|
-
/* @__PURE__ */
|
|
3692
|
+
/* @__PURE__ */ jsxs6("span", { style: { color: "#666" }, children: [
|
|
2846
3693
|
"(progress: ",
|
|
2847
3694
|
(docProgress * 100).toFixed(1),
|
|
2848
3695
|
"%, scriptDur: ",
|
|
@@ -2850,8 +3697,8 @@ function DocPlayerContent({
|
|
|
2850
3697
|
")"
|
|
2851
3698
|
] })
|
|
2852
3699
|
] }),
|
|
2853
|
-
/* @__PURE__ */
|
|
2854
|
-
/* @__PURE__ */
|
|
3700
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
3701
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "#888" }, children: "blockTime:" }),
|
|
2855
3702
|
" ",
|
|
2856
3703
|
blockTime.toFixed(2),
|
|
2857
3704
|
"s /",
|
|
@@ -2859,58 +3706,58 @@ function DocPlayerContent({
|
|
|
2859
3706
|
(currentBlock?.duration || 0).toFixed(1),
|
|
2860
3707
|
"s"
|
|
2861
3708
|
] }),
|
|
2862
|
-
/* @__PURE__ */
|
|
2863
|
-
/* @__PURE__ */
|
|
3709
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
3710
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "#888" }, children: "segment:" }),
|
|
2864
3711
|
" ",
|
|
2865
3712
|
currentSegment,
|
|
2866
3713
|
"/",
|
|
2867
3714
|
doc.audio.segments.length - 1,
|
|
2868
3715
|
" ",
|
|
2869
|
-
/* @__PURE__ */
|
|
3716
|
+
/* @__PURE__ */ jsxs6("span", { style: { color: "#666" }, children: [
|
|
2870
3717
|
"(",
|
|
2871
3718
|
doc.audio.segments[currentSegment]?.name || "none",
|
|
2872
3719
|
")"
|
|
2873
3720
|
] })
|
|
2874
3721
|
] }),
|
|
2875
|
-
/* @__PURE__ */
|
|
2876
|
-
/* @__PURE__ */
|
|
3722
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
3723
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "#888" }, children: "viewport:" }),
|
|
2877
3724
|
" ",
|
|
2878
3725
|
activeViewport.name || `${activeViewport.width}x${activeViewport.height}`,
|
|
2879
3726
|
" ",
|
|
2880
|
-
/* @__PURE__ */
|
|
3727
|
+
/* @__PURE__ */ jsxs6("span", { style: { color: "#666" }, children: [
|
|
2881
3728
|
"(",
|
|
2882
3729
|
activeOrientation,
|
|
2883
3730
|
")"
|
|
2884
3731
|
] })
|
|
2885
3732
|
] }),
|
|
2886
|
-
/* @__PURE__ */
|
|
2887
|
-
/* @__PURE__ */
|
|
3733
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
3734
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "#888" }, children: "playing:" }),
|
|
2888
3735
|
" ",
|
|
2889
|
-
/* @__PURE__ */
|
|
2890
|
-
showCoverBlock && /* @__PURE__ */
|
|
3736
|
+
/* @__PURE__ */ jsx9("span", { style: { color: isPlaying ? "#4ade80" : "#f87171" }, children: isPlaying ? "yes" : "no" }),
|
|
3737
|
+
showCoverBlock && /* @__PURE__ */ jsx9("span", { style: { color: "#60a5fa" }, children: " (cover)" })
|
|
2891
3738
|
] }),
|
|
2892
3739
|
hasCaptions && (() => {
|
|
2893
3740
|
const debugPhrase = getCaptionAtTime2(doc.captions, currentTime);
|
|
2894
3741
|
const debugEnabled = captionsEnabled && (isPlaying || currentTime > 0);
|
|
2895
|
-
return /* @__PURE__ */
|
|
2896
|
-
/* @__PURE__ */
|
|
2897
|
-
/* @__PURE__ */
|
|
3742
|
+
return /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
3743
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
3744
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "#888" }, children: "captions:" }),
|
|
2898
3745
|
" ",
|
|
2899
3746
|
doc.captions?.phrases.length || 0,
|
|
2900
3747
|
" phrases",
|
|
2901
3748
|
" ",
|
|
2902
|
-
/* @__PURE__ */
|
|
3749
|
+
/* @__PURE__ */ jsxs6("span", { style: { color: captionsEnabled ? "#4ade80" : "#666" }, children: [
|
|
2903
3750
|
"(",
|
|
2904
3751
|
captionsEnabled ? "on" : "off",
|
|
2905
3752
|
")"
|
|
2906
3753
|
] })
|
|
2907
3754
|
] }),
|
|
2908
|
-
/* @__PURE__ */
|
|
2909
|
-
/* @__PURE__ */
|
|
3755
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
3756
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "#888" }, children: "cc.enabled:" }),
|
|
2910
3757
|
" ",
|
|
2911
|
-
/* @__PURE__ */
|
|
3758
|
+
/* @__PURE__ */ jsx9("span", { style: { color: debugEnabled ? "#4ade80" : "#f87171" }, children: String(debugEnabled) }),
|
|
2912
3759
|
" ",
|
|
2913
|
-
/* @__PURE__ */
|
|
3760
|
+
/* @__PURE__ */ jsxs6("span", { style: { color: "#666" }, children: [
|
|
2914
3761
|
"(playing=",
|
|
2915
3762
|
String(isPlaying),
|
|
2916
3763
|
" t>0=",
|
|
@@ -2918,15 +3765,15 @@ function DocPlayerContent({
|
|
|
2918
3765
|
")"
|
|
2919
3766
|
] })
|
|
2920
3767
|
] }),
|
|
2921
|
-
/* @__PURE__ */
|
|
2922
|
-
/* @__PURE__ */
|
|
3768
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
3769
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "#888" }, children: "cc.phrase:" }),
|
|
2923
3770
|
" ",
|
|
2924
|
-
/* @__PURE__ */
|
|
3771
|
+
/* @__PURE__ */ jsx9("span", { style: { color: debugPhrase ? "#4ade80" : "#f87171" }, children: debugPhrase ? `"${debugPhrase.text.slice(0, 30)}..."` : "null" })
|
|
2925
3772
|
] }),
|
|
2926
|
-
debugPhrase && /* @__PURE__ */
|
|
2927
|
-
/* @__PURE__ */
|
|
3773
|
+
debugPhrase && /* @__PURE__ */ jsxs6("div", { children: [
|
|
3774
|
+
/* @__PURE__ */ jsx9("span", { style: { color: "#888" }, children: "cc.range:" }),
|
|
2928
3775
|
" ",
|
|
2929
|
-
/* @__PURE__ */
|
|
3776
|
+
/* @__PURE__ */ jsxs6("span", { style: { color: "#60a5fa" }, children: [
|
|
2930
3777
|
debugPhrase.startTime.toFixed(2),
|
|
2931
3778
|
"-",
|
|
2932
3779
|
debugPhrase.endTime.toFixed(2)
|
|
@@ -2938,7 +3785,7 @@ function DocPlayerContent({
|
|
|
2938
3785
|
}
|
|
2939
3786
|
)
|
|
2940
3787
|
] }),
|
|
2941
|
-
!isAvailable && unavailableMessage && /* @__PURE__ */
|
|
3788
|
+
!isAvailable && unavailableMessage && /* @__PURE__ */ jsxs6(
|
|
2942
3789
|
"div",
|
|
2943
3790
|
{
|
|
2944
3791
|
className: "doc-player__unavailable",
|
|
@@ -2959,12 +3806,12 @@ function DocPlayerContent({
|
|
|
2959
3806
|
zIndex: 50
|
|
2960
3807
|
},
|
|
2961
3808
|
children: [
|
|
2962
|
-
/* @__PURE__ */
|
|
2963
|
-
/* @__PURE__ */
|
|
3809
|
+
/* @__PURE__ */ jsx9("span", { style: { fontSize: "32px" }, children: "\u{1F50A}" }),
|
|
3810
|
+
/* @__PURE__ */ jsx9("span", { children: unavailableMessage })
|
|
2964
3811
|
]
|
|
2965
3812
|
}
|
|
2966
3813
|
),
|
|
2967
|
-
!renderMode && !isSlideshowMode && showControls && /* @__PURE__ */
|
|
3814
|
+
!renderMode && !isSlideshowMode && showControls && /* @__PURE__ */ jsx9(
|
|
2968
3815
|
DocControlsOverlay,
|
|
2969
3816
|
{
|
|
2970
3817
|
state: playbackState,
|
|
@@ -2974,7 +3821,7 @@ function DocPlayerContent({
|
|
|
2974
3821
|
getBlockTitle
|
|
2975
3822
|
}
|
|
2976
3823
|
),
|
|
2977
|
-
!renderMode && !isSlideshowMode && !showControls && showScrubber && /* @__PURE__ */
|
|
3824
|
+
!renderMode && !isSlideshowMode && !showControls && showScrubber && /* @__PURE__ */ jsx9(
|
|
2978
3825
|
"div",
|
|
2979
3826
|
{
|
|
2980
3827
|
className: "doc-player__scrubber",
|
|
@@ -2989,7 +3836,7 @@ function DocPlayerContent({
|
|
|
2989
3836
|
alignItems: "center",
|
|
2990
3837
|
zIndex: 100
|
|
2991
3838
|
},
|
|
2992
|
-
children: /* @__PURE__ */
|
|
3839
|
+
children: /* @__PURE__ */ jsx9(
|
|
2993
3840
|
DocProgressBar,
|
|
2994
3841
|
{
|
|
2995
3842
|
state: playbackState,
|
|
@@ -3001,7 +3848,7 @@ function DocPlayerContent({
|
|
|
3001
3848
|
)
|
|
3002
3849
|
}
|
|
3003
3850
|
),
|
|
3004
|
-
!renderMode && isSlideshowMode && showControls && /* @__PURE__ */
|
|
3851
|
+
!renderMode && isSlideshowMode && showControls && /* @__PURE__ */ jsx9(
|
|
3005
3852
|
DocControlsSlideshow,
|
|
3006
3853
|
{
|
|
3007
3854
|
state: playbackState,
|
|
@@ -3011,14 +3858,14 @@ function DocPlayerContent({
|
|
|
3011
3858
|
onPickerOpenChange: setIsSlideshowPickerOpen
|
|
3012
3859
|
}
|
|
3013
3860
|
),
|
|
3014
|
-
!isSlideshowMode && tapFeedback && /* @__PURE__ */
|
|
3861
|
+
!isSlideshowMode && tapFeedback && /* @__PURE__ */ jsx9("div", { className: "doc-player__tap-feedback", children: /* @__PURE__ */ jsx9("svg", { viewBox: "0 0 24 24", fill: "white", width: "48", height: "48", children: tapFeedback === "pause" ? /* @__PURE__ */ jsx9("path", { d: "M6 19h4V5H6v14zm8-14v14h4V5h-4z" }) : /* @__PURE__ */ jsx9("path", { d: "M8 5v14l11-7z" }) }) }, tapFeedback)
|
|
3015
3862
|
]
|
|
3016
3863
|
}
|
|
3017
3864
|
);
|
|
3018
3865
|
}
|
|
3019
3866
|
|
|
3020
3867
|
// src/DocControlsBottom.tsx
|
|
3021
|
-
import { jsx as
|
|
3868
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
3022
3869
|
function DocControlsBottom({
|
|
3023
3870
|
state,
|
|
3024
3871
|
actions,
|
|
@@ -3026,32 +3873,32 @@ function DocControlsBottom({
|
|
|
3026
3873
|
expandedBlocks,
|
|
3027
3874
|
getBlockTitle
|
|
3028
3875
|
}) {
|
|
3029
|
-
return /* @__PURE__ */
|
|
3030
|
-
/* @__PURE__ */
|
|
3876
|
+
return /* @__PURE__ */ jsxs7("div", { className: "doc-controls-bottom", children: [
|
|
3877
|
+
/* @__PURE__ */ jsx10(
|
|
3031
3878
|
"button",
|
|
3032
3879
|
{
|
|
3033
3880
|
className: "bottom-ctrl-btn",
|
|
3034
3881
|
onClick: actions.restart,
|
|
3035
3882
|
title: "Restart",
|
|
3036
3883
|
"aria-label": "Restart from beginning",
|
|
3037
|
-
children: /* @__PURE__ */
|
|
3884
|
+
children: /* @__PURE__ */ jsx10("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", 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" }) })
|
|
3038
3885
|
}
|
|
3039
3886
|
),
|
|
3040
|
-
/* @__PURE__ */
|
|
3887
|
+
/* @__PURE__ */ jsx10(
|
|
3041
3888
|
"button",
|
|
3042
3889
|
{
|
|
3043
3890
|
className: "bottom-ctrl-btn bottom-play-btn",
|
|
3044
3891
|
onClick: actions.toggle,
|
|
3045
3892
|
"aria-label": state.isPlaying ? "Pause" : "Play",
|
|
3046
|
-
children: state.isPlaying ? /* @__PURE__ */
|
|
3893
|
+
children: state.isPlaying ? /* @__PURE__ */ jsx10("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx10("path", { d: "M6 19h4V5H6v14zm8-14v14h4V5h-4z" }) }) : /* @__PURE__ */ jsx10("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx10("path", { d: "M8 5v14l11-7z" }) })
|
|
3047
3894
|
}
|
|
3048
3895
|
),
|
|
3049
|
-
/* @__PURE__ */
|
|
3896
|
+
/* @__PURE__ */ jsxs7("span", { className: "bottom-time", children: [
|
|
3050
3897
|
formatTime(state.currentTime),
|
|
3051
3898
|
" / ",
|
|
3052
3899
|
formatTime(state.totalDuration)
|
|
3053
3900
|
] }),
|
|
3054
|
-
/* @__PURE__ */
|
|
3901
|
+
/* @__PURE__ */ jsx10(
|
|
3055
3902
|
DocProgressBar,
|
|
3056
3903
|
{
|
|
3057
3904
|
state,
|
|
@@ -3061,92 +3908,92 @@ function DocControlsBottom({
|
|
|
3061
3908
|
getBlockTitle
|
|
3062
3909
|
}
|
|
3063
3910
|
),
|
|
3064
|
-
/* @__PURE__ */
|
|
3911
|
+
/* @__PURE__ */ jsxs7("span", { className: "bottom-segment", children: [
|
|
3065
3912
|
state.currentBlockIndex + 1,
|
|
3066
3913
|
"/",
|
|
3067
3914
|
state.totalBlocks
|
|
3068
3915
|
] }),
|
|
3069
|
-
state.hasCaptions && /* @__PURE__ */
|
|
3916
|
+
state.hasCaptions && /* @__PURE__ */ jsx10(
|
|
3070
3917
|
"button",
|
|
3071
3918
|
{
|
|
3072
3919
|
className: `bottom-ctrl-btn ${state.captionMode !== "off" ? "bottom-ctrl-btn--active" : ""}`,
|
|
3073
3920
|
onClick: () => actions.cycleCaptionMode(),
|
|
3074
3921
|
title: state.captionMode === "off" ? "Captions: Off" : state.captionMode === "standard" ? "Captions: Standard" : "Captions: Social",
|
|
3075
3922
|
"aria-label": "Cycle caption style",
|
|
3076
|
-
children: /* @__PURE__ */
|
|
3923
|
+
children: /* @__PURE__ */ jsx10("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", 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" }) })
|
|
3077
3924
|
}
|
|
3078
3925
|
),
|
|
3079
|
-
actions.toggleFullscreen && /* @__PURE__ */
|
|
3926
|
+
actions.toggleFullscreen && /* @__PURE__ */ jsx10(
|
|
3080
3927
|
"button",
|
|
3081
3928
|
{
|
|
3082
3929
|
className: `bottom-ctrl-btn ${state.isFullscreen ? "bottom-ctrl-btn--active" : ""}`,
|
|
3083
3930
|
onClick: actions.toggleFullscreen,
|
|
3084
3931
|
title: state.isFullscreen ? "Exit fullscreen (F)" : "Fullscreen (F)",
|
|
3085
3932
|
"aria-label": state.isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
|
|
3086
|
-
children: state.isFullscreen ? /* @__PURE__ */
|
|
3933
|
+
children: state.isFullscreen ? /* @__PURE__ */ jsx10("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "18", height: "18", 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: "18", height: "18", children: /* @__PURE__ */ jsx10("path", { d: "M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" }) })
|
|
3087
3934
|
}
|
|
3088
3935
|
)
|
|
3089
3936
|
] });
|
|
3090
3937
|
}
|
|
3091
3938
|
|
|
3092
3939
|
// src/DocControlsSidebar.tsx
|
|
3093
|
-
import { jsx as
|
|
3940
|
+
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
3094
3941
|
function DocControlsSidebar({ state, actions }) {
|
|
3095
|
-
return /* @__PURE__ */
|
|
3096
|
-
/* @__PURE__ */
|
|
3942
|
+
return /* @__PURE__ */ jsxs8("div", { className: "doc-controls-sidebar", children: [
|
|
3943
|
+
/* @__PURE__ */ jsx11(
|
|
3097
3944
|
"button",
|
|
3098
3945
|
{
|
|
3099
3946
|
className: "sidebar-ctrl-btn",
|
|
3100
3947
|
onClick: actions.restart,
|
|
3101
3948
|
title: "Restart",
|
|
3102
3949
|
"aria-label": "Restart from beginning",
|
|
3103
|
-
children: /* @__PURE__ */
|
|
3950
|
+
children: /* @__PURE__ */ jsx11("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx11("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
3951
|
}
|
|
3105
3952
|
),
|
|
3106
|
-
/* @__PURE__ */
|
|
3953
|
+
/* @__PURE__ */ jsx11(
|
|
3107
3954
|
"button",
|
|
3108
3955
|
{
|
|
3109
3956
|
className: "sidebar-ctrl-btn sidebar-play-btn",
|
|
3110
3957
|
onClick: actions.toggle,
|
|
3111
3958
|
"aria-label": state.isPlaying ? "Pause" : "Play",
|
|
3112
|
-
children: state.isPlaying ? /* @__PURE__ */
|
|
3959
|
+
children: state.isPlaying ? /* @__PURE__ */ jsx11("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "22", height: "22", children: /* @__PURE__ */ jsx11("path", { d: "M6 19h4V5H6v14zm8-14v14h4V5h-4z" }) }) : /* @__PURE__ */ jsx11("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "22", height: "22", children: /* @__PURE__ */ jsx11("path", { d: "M8 5v14l11-7z" }) })
|
|
3113
3960
|
}
|
|
3114
3961
|
),
|
|
3115
|
-
/* @__PURE__ */
|
|
3116
|
-
/* @__PURE__ */
|
|
3117
|
-
/* @__PURE__ */
|
|
3962
|
+
/* @__PURE__ */ jsxs8("div", { className: "sidebar-time", children: [
|
|
3963
|
+
/* @__PURE__ */ jsx11("div", { children: formatTime(state.currentTime) }),
|
|
3964
|
+
/* @__PURE__ */ jsx11("div", { className: "sidebar-time-total", children: formatTime(state.totalDuration) })
|
|
3118
3965
|
] }),
|
|
3119
|
-
/* @__PURE__ */
|
|
3966
|
+
/* @__PURE__ */ jsxs8("div", { className: "sidebar-segment", children: [
|
|
3120
3967
|
state.currentBlockIndex + 1,
|
|
3121
3968
|
"/",
|
|
3122
3969
|
state.totalBlocks
|
|
3123
3970
|
] }),
|
|
3124
|
-
state.hasCaptions && /* @__PURE__ */
|
|
3971
|
+
state.hasCaptions && /* @__PURE__ */ jsx11(
|
|
3125
3972
|
"button",
|
|
3126
3973
|
{
|
|
3127
3974
|
className: `sidebar-ctrl-btn ${state.captionMode !== "off" ? "sidebar-ctrl-btn--active" : ""}`,
|
|
3128
3975
|
onClick: () => actions.cycleCaptionMode(),
|
|
3129
3976
|
title: state.captionMode === "off" ? "Captions: Off" : state.captionMode === "standard" ? "Captions: Standard" : "Captions: Social",
|
|
3130
3977
|
"aria-label": "Cycle caption style",
|
|
3131
|
-
children: /* @__PURE__ */
|
|
3978
|
+
children: /* @__PURE__ */ jsx11("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx11("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
3979
|
}
|
|
3133
3980
|
),
|
|
3134
|
-
actions.toggleFullscreen && /* @__PURE__ */
|
|
3981
|
+
actions.toggleFullscreen && /* @__PURE__ */ jsx11(
|
|
3135
3982
|
"button",
|
|
3136
3983
|
{
|
|
3137
3984
|
className: `sidebar-ctrl-btn ${state.isFullscreen ? "sidebar-ctrl-btn--active" : ""}`,
|
|
3138
3985
|
onClick: actions.toggleFullscreen,
|
|
3139
3986
|
title: state.isFullscreen ? "Exit fullscreen (F)" : "Fullscreen (F)",
|
|
3140
3987
|
"aria-label": state.isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
|
|
3141
|
-
children: state.isFullscreen ? /* @__PURE__ */
|
|
3988
|
+
children: state.isFullscreen ? /* @__PURE__ */ jsx11("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx11("path", { d: "M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z" }) }) : /* @__PURE__ */ jsx11("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "20", height: "20", children: /* @__PURE__ */ jsx11("path", { d: "M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" }) })
|
|
3142
3989
|
}
|
|
3143
3990
|
)
|
|
3144
3991
|
] });
|
|
3145
3992
|
}
|
|
3146
3993
|
|
|
3147
3994
|
// src/DocPlayerWithSidebar.tsx
|
|
3148
|
-
import { useRef as
|
|
3149
|
-
import { jsx as
|
|
3995
|
+
import { useRef as useRef8, useState as useState7, useCallback as useCallback6, useEffect as useEffect8 } from "react";
|
|
3996
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3150
3997
|
var DEFAULT_STATE = {
|
|
3151
3998
|
isPlaying: false,
|
|
3152
3999
|
currentTime: 0,
|
|
@@ -3178,11 +4025,11 @@ function DocPlayerWithSidebar({
|
|
|
3178
4025
|
onPlayingChange,
|
|
3179
4026
|
theme
|
|
3180
4027
|
}) {
|
|
3181
|
-
const stateRef =
|
|
3182
|
-
const actionsRef =
|
|
3183
|
-
const wasPlayingRef =
|
|
3184
|
-
const [, setTick] =
|
|
3185
|
-
const handleStateChange =
|
|
4028
|
+
const stateRef = useRef8(DEFAULT_STATE);
|
|
4029
|
+
const actionsRef = useRef8(null);
|
|
4030
|
+
const wasPlayingRef = useRef8(false);
|
|
4031
|
+
const [, setTick] = useState7(0);
|
|
4032
|
+
const handleStateChange = useCallback6(
|
|
3186
4033
|
(state) => {
|
|
3187
4034
|
stateRef.current = state;
|
|
3188
4035
|
if (onPlayingChange && state.isPlaying !== wasPlayingRef.current) {
|
|
@@ -3193,7 +4040,7 @@ function DocPlayerWithSidebar({
|
|
|
3193
4040
|
},
|
|
3194
4041
|
[onPlayingChange]
|
|
3195
4042
|
);
|
|
3196
|
-
const handleControlsReady =
|
|
4043
|
+
const handleControlsReady = useCallback6(
|
|
3197
4044
|
(controls) => {
|
|
3198
4045
|
const isFirst = !actionsRef.current;
|
|
3199
4046
|
actionsRef.current = controls;
|
|
@@ -3201,15 +4048,15 @@ function DocPlayerWithSidebar({
|
|
|
3201
4048
|
},
|
|
3202
4049
|
[]
|
|
3203
4050
|
);
|
|
3204
|
-
|
|
4051
|
+
useEffect8(() => {
|
|
3205
4052
|
const interval = setInterval(() => {
|
|
3206
4053
|
if (!stateRef.current.isPlaying) return;
|
|
3207
4054
|
setTick((t) => t + 1);
|
|
3208
4055
|
}, 250);
|
|
3209
4056
|
return () => clearInterval(interval);
|
|
3210
4057
|
}, []);
|
|
3211
|
-
return /* @__PURE__ */
|
|
3212
|
-
/* @__PURE__ */
|
|
4058
|
+
return /* @__PURE__ */ jsxs9("div", { className: "doc-player-sidebar-layout", children: [
|
|
4059
|
+
/* @__PURE__ */ jsx12("div", { className: "doc-player-sidebar-layout__video", children: /* @__PURE__ */ jsx12(
|
|
3213
4060
|
DocPlayer,
|
|
3214
4061
|
{
|
|
3215
4062
|
doc,
|
|
@@ -3232,7 +4079,7 @@ function DocPlayerWithSidebar({
|
|
|
3232
4079
|
forceViewport
|
|
3233
4080
|
}
|
|
3234
4081
|
) }),
|
|
3235
|
-
actionsRef.current && /* @__PURE__ */
|
|
4082
|
+
actionsRef.current && /* @__PURE__ */ jsx12(DocControlsSidebar, { state: stateRef.current, actions: actionsRef.current })
|
|
3236
4083
|
] });
|
|
3237
4084
|
}
|
|
3238
4085
|
|
|
@@ -3245,6 +4092,9 @@ export {
|
|
|
3245
4092
|
DocProgressBar,
|
|
3246
4093
|
DocControlsOverlay,
|
|
3247
4094
|
DocControlsSlideshow,
|
|
4095
|
+
DashboardView,
|
|
4096
|
+
FlashcardFaceView,
|
|
4097
|
+
FlashcardView,
|
|
3248
4098
|
resolveDocPlayerAppearance,
|
|
3249
4099
|
DocPlayer,
|
|
3250
4100
|
DocControlsBottom,
|