@drawnagency/primitives 0.1.118 → 0.1.120
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-O37AV27P.js → chunk-5JYHTHVR.js} +28 -0
- package/dist/{chunk-W72BPGR3.js → chunk-BZKHHUIN.js} +44 -8
- package/dist/{chunk-4NSOKEA7.js → chunk-HFHM4MNK.js} +12 -7
- package/dist/{chunk-CEFFP3CH.js → chunk-HZTPF6OK.js} +304 -83
- package/dist/{chunk-RIITGTV3.js → chunk-LQHBC7C6.js} +37 -2
- package/dist/{chunk-VY3IFGE3.js → chunk-QAMAIDXZ.js} +1 -1
- package/dist/{chunk-HRX3XJBU.js → chunk-RIN2QCYJ.js} +9 -11
- package/dist/{chunk-ZOTRHHUB.js → chunk-UNFPATDE.js} +8 -10
- package/dist/{chunk-ERLIL4RU.js → chunk-UZBFVVTC.js} +35 -37
- package/dist/{chunk-67P34WNW.js → chunk-ZKVQMIMJ.js} +3 -20
- package/dist/collab/rebase.js +4 -5
- package/dist/components/chat/ChatComposer.d.ts +0 -4
- package/dist/components/chat/ChatComposer.d.ts.map +1 -1
- package/dist/components/chat/ChatPanel.d.ts +2 -3
- package/dist/components/chat/ChatPanel.d.ts.map +1 -1
- package/dist/components/chat/markdown.d.ts +2 -3
- package/dist/components/chat/markdown.d.ts.map +1 -1
- package/dist/components/editor/AudienceIndicator.d.ts +3 -1
- package/dist/components/editor/AudienceIndicator.d.ts.map +1 -1
- package/dist/components/editor/IndicatorPill.d.ts +3 -1
- package/dist/components/editor/IndicatorPill.d.ts.map +1 -1
- package/dist/components/editor/PagesModal.d.ts +0 -2
- package/dist/components/editor/PagesModal.d.ts.map +1 -1
- package/dist/components/editor/SectionBulkEditModal.d.ts +25 -0
- package/dist/components/editor/SectionBulkEditModal.d.ts.map +1 -0
- package/dist/components/editor/StatusIndicator.d.ts +3 -1
- package/dist/components/editor/StatusIndicator.d.ts.map +1 -1
- package/dist/components/editor/index.js +28 -26
- package/dist/components/primitives/index.js +11 -15
- package/dist/components/sections/brand-guide.js +10 -13
- package/dist/components/sections/register-schemas.js +16 -21
- package/dist/components/sections/register.js +16 -21
- package/dist/components/shared/Popover.d.ts +1 -1
- package/dist/components/shared/Popover.d.ts.map +1 -1
- package/dist/components/shared/SectionSummaryRow.d.ts +1 -1
- package/dist/components/shell/AudienceChips.d.ts +1 -3
- package/dist/components/shell/AudienceChips.d.ts.map +1 -1
- package/dist/components/shell/EditorModal.d.ts.map +1 -1
- package/dist/components/shell/EditorShell.d.ts +0 -34
- package/dist/components/shell/EditorShell.d.ts.map +1 -1
- package/dist/components/shell/SiteSettingsModal.d.ts.map +1 -1
- package/dist/hooks/useSortableNavRow.d.ts +1 -1
- package/dist/hooks/useSortableRow.d.ts +1 -1
- package/dist/index.js +83 -90
- package/dist/lib/index-ops.js +5 -6
- package/dist/lib/index.js +27 -32
- package/dist/lib/pages.d.ts +0 -2
- package/dist/lib/pages.d.ts.map +1 -1
- package/dist/lib/sidecars.js +2 -2
- package/dist/lib/site-validation.js +13 -14
- package/dist/lib/storage-tier.js +4 -4
- package/dist/schemas/index.js +42 -45
- package/dist/schemas/site-config.d.ts +1 -277
- package/dist/schemas/site-config.d.ts.map +1 -1
- package/package.json +2 -42
- package/src/components/chat/ChatComposer.tsx +0 -4
- package/src/components/chat/ChatPanel.tsx +2 -3
- package/src/components/chat/markdown.ts +2 -3
- package/src/components/editor/AudienceIndicator.tsx +8 -4
- package/src/components/editor/IndicatorPill.tsx +4 -0
- package/src/components/editor/PagesModal.tsx +1 -15
- package/src/components/editor/SectionBulkEditModal.tsx +328 -0
- package/src/components/editor/StatusIndicator.tsx +7 -6
- package/src/components/shared/Popover.tsx +17 -4
- package/src/components/shared/SectionSummaryRow.tsx +1 -1
- package/src/components/shell/AudienceChips.tsx +1 -3
- package/src/components/shell/EditorModal.tsx +5 -2
- package/src/components/shell/EditorShell.tsx +15 -119
- package/src/components/shell/SiteSettingsModal.tsx +0 -11
- package/src/lib/pages.ts +0 -22
- package/src/schemas/index.ts +0 -4
- package/src/schemas/site-config.ts +4 -32
- package/dist/chunk-4TZJZU2T.js +0 -92
- package/dist/chunk-DIMDRBFK.js +0 -11
- package/dist/chunk-FV7JQRCN.js +0 -94
- package/dist/chunk-IIDKW7AV.js +0 -41
- package/dist/chunk-JCDZAFX2.js +0 -224
- package/dist/chunk-MM7KZS5C.js +0 -30
- package/dist/chunk-QQ3S3P5P.js +0 -38
- package/dist/chunk-TEOAKGZA.js +0 -784
- package/dist/chunk-VAYZJKVR.js +0 -209
- package/dist/components/editor/SectionOrderingModal.d.ts +0 -10
- package/dist/components/editor/SectionOrderingModal.d.ts.map +0 -1
- package/dist/components/shell/DocInspector.d.ts +0 -18
- package/dist/components/shell/DocInspector.d.ts.map +0 -1
- package/dist/components/shell/DocumentEditorOverlay.d.ts +0 -29
- package/dist/components/shell/DocumentEditorOverlay.d.ts.map +0 -1
- package/dist/components/shell/DocumentPresentOverlay.d.ts +0 -30
- package/dist/components/shell/DocumentPresentOverlay.d.ts.map +0 -1
- package/dist/components/shell/SiteSettingsDecks.d.ts +0 -13
- package/dist/components/shell/SiteSettingsDecks.d.ts.map +0 -1
- package/dist/deck/DeckComponentView.d.ts +0 -13
- package/dist/deck/DeckComponentView.d.ts.map +0 -1
- package/dist/deck/DeckPlayer.d.ts +0 -26
- package/dist/deck/DeckPlayer.d.ts.map +0 -1
- package/dist/deck/DeckSlideView.d.ts +0 -17
- package/dist/deck/DeckSlideView.d.ts.map +0 -1
- package/dist/deck/DeckStage.d.ts +0 -16
- package/dist/deck/DeckStage.d.ts.map +0 -1
- package/dist/deck/components/DeckImage.d.ts +0 -14
- package/dist/deck/components/DeckImage.d.ts.map +0 -1
- package/dist/deck/components/DeckImageGrid.d.ts +0 -27
- package/dist/deck/components/DeckImageGrid.d.ts.map +0 -1
- package/dist/deck/components/DeckRichText.d.ts +0 -22
- package/dist/deck/components/DeckRichText.d.ts.map +0 -1
- package/dist/deck/components/DeckVideo.d.ts +0 -15
- package/dist/deck/components/DeckVideo.d.ts.map +0 -1
- package/dist/deck/editing.d.ts +0 -50
- package/dist/deck/editing.d.ts.map +0 -1
- package/dist/deck/flip.d.ts +0 -11
- package/dist/deck/flip.d.ts.map +0 -1
- package/dist/deck/index.d.ts +0 -24
- package/dist/deck/index.d.ts.map +0 -1
- package/dist/deck/index.js +0 -51
- package/dist/deck/layouts/CenteredTextLayout.d.ts +0 -12
- package/dist/deck/layouts/CenteredTextLayout.d.ts.map +0 -1
- package/dist/deck/layouts/ColumnSplitLayout.d.ts +0 -14
- package/dist/deck/layouts/ColumnSplitLayout.d.ts.map +0 -1
- package/dist/deck/layouts/FullBleedImageLayout.d.ts +0 -14
- package/dist/deck/layouts/FullBleedImageLayout.d.ts.map +0 -1
- package/dist/deck/media.d.ts +0 -33
- package/dist/deck/media.d.ts.map +0 -1
- package/dist/deck/tokens.d.ts +0 -22
- package/dist/deck/tokens.d.ts.map +0 -1
- package/dist/deck/useStageScale.d.ts +0 -10
- package/dist/deck/useStageScale.d.ts.map +0 -1
- package/dist/deck-builder/DeckBuilderApp.d.ts +0 -30
- package/dist/deck-builder/DeckBuilderApp.d.ts.map +0 -1
- package/dist/deck-builder/DeckBuilderTopBar.d.ts +0 -24
- package/dist/deck-builder/DeckBuilderTopBar.d.ts.map +0 -1
- package/dist/deck-builder/DeckChatPanel.d.ts +0 -45
- package/dist/deck-builder/DeckChatPanel.d.ts.map +0 -1
- package/dist/deck-builder/DeckEditor.d.ts +0 -37
- package/dist/deck-builder/DeckEditor.d.ts.map +0 -1
- package/dist/deck-builder/DeckLibrary.d.ts +0 -22
- package/dist/deck-builder/DeckLibrary.d.ts.map +0 -1
- package/dist/deck-builder/DeckSlideSurface.d.ts +0 -31
- package/dist/deck-builder/DeckSlideSurface.d.ts.map +0 -1
- package/dist/deck-builder/deck-api.d.ts +0 -76
- package/dist/deck-builder/deck-api.d.ts.map +0 -1
- package/dist/deck-builder/deck-chat-client.d.ts +0 -44
- package/dist/deck-builder/deck-chat-client.d.ts.map +0 -1
- package/dist/deck-builder/deck-chat-history.d.ts +0 -10
- package/dist/deck-builder/deck-chat-history.d.ts.map +0 -1
- package/dist/deck-builder/index.d.ts +0 -13
- package/dist/deck-builder/index.d.ts.map +0 -1
- package/dist/deck-builder/index.js +0 -1498
- package/dist/deck-builder/starter-deck.d.ts +0 -23
- package/dist/deck-builder/starter-deck.d.ts.map +0 -1
- package/dist/deck-builder/types.d.ts +0 -29
- package/dist/deck-builder/types.d.ts.map +0 -1
- package/dist/deck-builder/useSortableSlide.d.ts +0 -29
- package/dist/deck-builder/useSortableSlide.d.ts.map +0 -1
- package/dist/document/assets/fonts/albra-grotesk-bold.woff +0 -0
- package/dist/document/assets/fonts/albra-grotesk-regular.woff +0 -0
- package/dist/document/assets/fonts/kapra-neue-expanded-medium.woff +0 -0
- package/dist/document/assets/fonts/kapra-neue-expanded-regular.woff +0 -0
- package/dist/document/components/DocCoverPage.d.ts +0 -11
- package/dist/document/components/DocCoverPage.d.ts.map +0 -1
- package/dist/document/components/DocPage.d.ts +0 -10
- package/dist/document/components/DocPage.d.ts.map +0 -1
- package/dist/document/components/DocRail.d.ts +0 -28
- package/dist/document/components/DocRail.d.ts.map +0 -1
- package/dist/document/components/DocSectionPage.d.ts +0 -12
- package/dist/document/components/DocSectionPage.d.ts.map +0 -1
- package/dist/document/components/DocViewer.d.ts +0 -21
- package/dist/document/components/DocViewer.d.ts.map +0 -1
- package/dist/document/components/Wordmark.d.ts +0 -4
- package/dist/document/components/Wordmark.d.ts.map +0 -1
- package/dist/document/components/measure.d.ts +0 -7
- package/dist/document/components/measure.d.ts.map +0 -1
- package/dist/document/components/useDocPages.d.ts +0 -12
- package/dist/document/components/useDocPages.d.ts.map +0 -1
- package/dist/document/engine/blocks.d.ts +0 -2
- package/dist/document/engine/blocks.d.ts.map +0 -1
- package/dist/document/engine/harvest.d.ts +0 -3
- package/dist/document/engine/harvest.d.ts.map +0 -1
- package/dist/document/engine/masonry.d.ts +0 -26
- package/dist/document/engine/masonry.d.ts.map +0 -1
- package/dist/document/engine/paginate.d.ts +0 -43
- package/dist/document/engine/paginate.d.ts.map +0 -1
- package/dist/document/engine/settings.d.ts +0 -91
- package/dist/document/engine/settings.d.ts.map +0 -1
- package/dist/document/engine/types.d.ts +0 -44
- package/dist/document/engine/types.d.ts.map +0 -1
- package/dist/document/index.d.ts +0 -13
- package/dist/document/index.d.ts.map +0 -1
- package/dist/document/index.js +0 -1030
- package/dist/document/styles/document.css +0 -217
- package/dist/lib/deck-access.d.ts +0 -86
- package/dist/lib/deck-access.d.ts.map +0 -1
- package/dist/lib/deck-access.js +0 -58
- package/dist/lib/deck-dexie.d.ts +0 -88
- package/dist/lib/deck-dexie.d.ts.map +0 -1
- package/dist/lib/deck-dexie.js +0 -22
- package/dist/lib/deck-edit.d.ts +0 -67
- package/dist/lib/deck-edit.d.ts.map +0 -1
- package/dist/lib/deck-media-assets.d.ts +0 -27
- package/dist/lib/deck-media-assets.d.ts.map +0 -1
- package/dist/lib/deck-media-assets.js +0 -25
- package/dist/lib/deck-media-refs.d.ts +0 -35
- package/dist/lib/deck-media-refs.d.ts.map +0 -1
- package/dist/lib/deck-media-refs.js +0 -36
- package/dist/lib/deck-tool.d.ts +0 -25
- package/dist/lib/deck-tool.d.ts.map +0 -1
- package/dist/lib/deck-tool.js +0 -58
- package/dist/lib/document-input.d.ts +0 -25
- package/dist/lib/document-input.d.ts.map +0 -1
- package/dist/schemas/deck-meta.d.ts +0 -85
- package/dist/schemas/deck-meta.d.ts.map +0 -1
- package/dist/schemas/deck-meta.js +0 -64
- package/dist/schemas/deck.d.ts +0 -954
- package/dist/schemas/deck.d.ts.map +0 -1
- package/dist/schemas/deck.js +0 -65
- package/src/components/editor/SectionOrderingModal.tsx +0 -80
- package/src/components/shell/DocInspector.tsx +0 -314
- package/src/components/shell/DocumentEditorOverlay.tsx +0 -179
- package/src/components/shell/DocumentPresentOverlay.tsx +0 -87
- package/src/components/shell/SiteSettingsDecks.tsx +0 -41
- package/src/deck/DeckComponentView.tsx +0 -28
- package/src/deck/DeckPlayer.tsx +0 -166
- package/src/deck/DeckSlideView.tsx +0 -38
- package/src/deck/DeckStage.tsx +0 -39
- package/src/deck/components/DeckImage.tsx +0 -38
- package/src/deck/components/DeckImageGrid.tsx +0 -254
- package/src/deck/components/DeckRichText.tsx +0 -111
- package/src/deck/components/DeckVideo.tsx +0 -81
- package/src/deck/editing.tsx +0 -201
- package/src/deck/flip.ts +0 -70
- package/src/deck/index.ts +0 -30
- package/src/deck/layouts/CenteredTextLayout.tsx +0 -29
- package/src/deck/layouts/ColumnSplitLayout.tsx +0 -69
- package/src/deck/layouts/FullBleedImageLayout.tsx +0 -58
- package/src/deck/media.tsx +0 -46
- package/src/deck/tokens.ts +0 -57
- package/src/deck/useStageScale.ts +0 -44
- package/src/deck-builder/DeckBuilderApp.tsx +0 -572
- package/src/deck-builder/DeckBuilderTopBar.tsx +0 -62
- package/src/deck-builder/DeckChatPanel.tsx +0 -334
- package/src/deck-builder/DeckEditor.tsx +0 -258
- package/src/deck-builder/DeckLibrary.tsx +0 -195
- package/src/deck-builder/DeckSlideSurface.tsx +0 -55
- package/src/deck-builder/deck-api.ts +0 -177
- package/src/deck-builder/deck-chat-client.ts +0 -129
- package/src/deck-builder/deck-chat-history.ts +0 -62
- package/src/deck-builder/index.ts +0 -12
- package/src/deck-builder/starter-deck.ts +0 -86
- package/src/deck-builder/types.ts +0 -24
- package/src/deck-builder/useSortableSlide.ts +0 -102
- package/src/document/assets/fonts/albra-grotesk-bold.woff +0 -0
- package/src/document/assets/fonts/albra-grotesk-regular.woff +0 -0
- package/src/document/assets/fonts/kapra-neue-expanded-medium.woff +0 -0
- package/src/document/assets/fonts/kapra-neue-expanded-regular.woff +0 -0
- package/src/document/components/DocCoverPage.tsx +0 -45
- package/src/document/components/DocPage.tsx +0 -40
- package/src/document/components/DocRail.tsx +0 -189
- package/src/document/components/DocSectionPage.tsx +0 -48
- package/src/document/components/DocViewer.tsx +0 -313
- package/src/document/components/Wordmark.tsx +0 -18
- package/src/document/components/measure.tsx +0 -133
- package/src/document/components/useDocPages.ts +0 -95
- package/src/document/engine/blocks.ts +0 -116
- package/src/document/engine/harvest.ts +0 -95
- package/src/document/engine/masonry.ts +0 -158
- package/src/document/engine/paginate.ts +0 -232
- package/src/document/engine/settings.ts +0 -125
- package/src/document/engine/types.ts +0 -64
- package/src/document/index.ts +0 -18
- package/src/document/styles/document.css +0 -217
- package/src/lib/deck-access.ts +0 -132
- package/src/lib/deck-dexie.ts +0 -190
- package/src/lib/deck-edit.ts +0 -196
- package/src/lib/deck-media-assets.ts +0 -57
- package/src/lib/deck-media-refs.ts +0 -67
- package/src/lib/deck-tool.ts +0 -95
- package/src/lib/document-input.ts +0 -57
- package/src/schemas/deck-meta.ts +0 -88
- package/src/schemas/deck.ts +0 -478
- package/dist/{chunk-DJABADOO.js → chunk-AJ2QOAZI.js} +3 -3
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { useEffect, useMemo } from "react";
|
|
2
|
-
import type { Page } from "../../schemas/site-config";
|
|
3
|
-
import type { MediaManifest } from "../../media/types";
|
|
4
|
-
import type { LoadedSection } from "../../lib/loader";
|
|
5
|
-
import { DocViewer, documentOptionsSchema, type DocHost } from "../../document";
|
|
6
|
-
import { buildDraftDocumentInput } from "../../lib/document-input";
|
|
7
|
-
// Same sealed document stylesheet the editor overlay ships (see
|
|
8
|
-
// DocumentEditorOverlay). Vitest stubs CSS imports, so it stays out of the jsdom
|
|
9
|
-
// test graph regardless.
|
|
10
|
-
import "../../document/styles/document.css";
|
|
11
|
-
|
|
12
|
-
export interface DocumentPresentOverlayProps {
|
|
13
|
-
/** The active page — its `document` block supplies cover/meta/section settings. */
|
|
14
|
-
page: Page;
|
|
15
|
-
/**
|
|
16
|
-
* The sections currently on the canvas (already page-ordered and filtered to
|
|
17
|
-
* the branch being previewed). The shell derives these from the same
|
|
18
|
-
* `computeDisplaySections` call the history/branch canvas renders.
|
|
19
|
-
*/
|
|
20
|
-
sections: LoadedSection[];
|
|
21
|
-
manifest: MediaManifest;
|
|
22
|
-
onClose: () => void;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Read-only, full-viewport document PRESENTATION of the content currently being
|
|
27
|
-
* viewed — used when the shell is previewing a non-draft version (the published
|
|
28
|
-
* branch). It is `DocViewer` in `present` mode: no inspector, no update path.
|
|
29
|
-
*
|
|
30
|
-
* Product decision (Drew): history/branch views are the record — we present them
|
|
31
|
-
* but never open the editor over them. Document SETTINGS come from the current
|
|
32
|
-
* draft's `page.document`; the previewed branch's own document index is not
|
|
33
|
-
* carried in the shell's `viewSections`, so cover/meta/exclusions here reflect
|
|
34
|
-
* the draft, not the historical commit. This is an accepted approximation: we
|
|
35
|
-
* are rendering historical *content* with the draft's presentation settings.
|
|
36
|
-
*/
|
|
37
|
-
export function DocumentPresentOverlay({
|
|
38
|
-
page,
|
|
39
|
-
sections,
|
|
40
|
-
manifest,
|
|
41
|
-
onClose,
|
|
42
|
-
}: DocumentPresentOverlayProps) {
|
|
43
|
-
// page.document is optional on the type; the caller only mounts this when it
|
|
44
|
-
// is enabled, but parse-with-defaults keeps us total either way.
|
|
45
|
-
const doc = useMemo(() => documentOptionsSchema.parse(page.document ?? {}), [page.document]);
|
|
46
|
-
|
|
47
|
-
const source = useMemo(
|
|
48
|
-
() => buildDraftDocumentInput({ page, sections, manifest }),
|
|
49
|
-
[page, sections, manifest],
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
// All media bytes come from /api/media — the same host shape the present route
|
|
53
|
-
// and the editor overlay use.
|
|
54
|
-
const host: DocHost = useMemo(
|
|
55
|
-
() => ({
|
|
56
|
-
variant: "preview",
|
|
57
|
-
imageSrc: (image, variant) =>
|
|
58
|
-
`/api/media/${image.imageId}/${variant === "print" ? image.printFile : image.previewFile}`,
|
|
59
|
-
}),
|
|
60
|
-
[],
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
// Escape closes, matching the editor overlay. DocViewer owns arrow paging on
|
|
64
|
-
// its own window listener; Escape doesn't collide with it.
|
|
65
|
-
useEffect(() => {
|
|
66
|
-
const onKey = (e: KeyboardEvent) => {
|
|
67
|
-
if (e.key !== "Escape") return;
|
|
68
|
-
e.preventDefault();
|
|
69
|
-
onClose();
|
|
70
|
-
};
|
|
71
|
-
window.addEventListener("keydown", onKey);
|
|
72
|
-
return () => window.removeEventListener("keydown", onKey);
|
|
73
|
-
}, [onClose]);
|
|
74
|
-
|
|
75
|
-
return (
|
|
76
|
-
<div
|
|
77
|
-
className="fixed inset-0 z-50 flex flex-col bg-base"
|
|
78
|
-
role="dialog"
|
|
79
|
-
aria-modal="true"
|
|
80
|
-
aria-label="Document presentation"
|
|
81
|
-
>
|
|
82
|
-
<div className="flex min-h-0 flex-1">
|
|
83
|
-
<DocViewer source={source} document={doc} host={host} mode="present" onClose={onClose} />
|
|
84
|
-
</div>
|
|
85
|
-
</div>
|
|
86
|
-
);
|
|
87
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { AudienceChips } from "./AudienceChips";
|
|
2
|
-
import type { SiteConfig } from "../../schemas/site-config";
|
|
3
|
-
import type { Audience } from "../../auth/types";
|
|
4
|
-
|
|
5
|
-
interface Props {
|
|
6
|
-
siteConfig: SiteConfig;
|
|
7
|
-
onSiteConfigChange: (config: SiteConfig) => void;
|
|
8
|
-
audiences: Audience[];
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/** Deck Builder settings. One control today — the creation opt-in — because
|
|
12
|
-
* that is the only `deckBuilder` key that exists; public sharing (#37) is the
|
|
13
|
-
* next one and belongs on this tab. */
|
|
14
|
-
export function SiteSettingsDecks({ siteConfig, onSiteConfigChange, audiences }: Props) {
|
|
15
|
-
const selected = siteConfig.deckBuilder.audiences;
|
|
16
|
-
|
|
17
|
-
function toggle(name: string) {
|
|
18
|
-
const next = selected.includes(name) ? selected.filter((n) => n !== name) : [...selected, name];
|
|
19
|
-
onSiteConfigChange({ ...siteConfig, deckBuilder: { ...siteConfig.deckBuilder, audiences: next } });
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return (
|
|
23
|
-
<div className="space-y-3">
|
|
24
|
-
<div>
|
|
25
|
-
<h3 className="mb-1 text-sm font-medium text-base-contrast">Who can build decks</h3>
|
|
26
|
-
<p className="mb-2 text-xs text-base-contrast-light">
|
|
27
|
-
Members of the selected audiences get the Decks button and can create and publish their own presentations.
|
|
28
|
-
None selected means no viewer can start a new one. Editors always can.
|
|
29
|
-
</p>
|
|
30
|
-
<AudienceChips audiences={audiences} selected={selected} onToggle={toggle} />
|
|
31
|
-
</div>
|
|
32
|
-
<p className="text-xs text-base-contrast-light">
|
|
33
|
-
Removing an audience here stops its members starting new decks. Decks they already own stay theirs — they can
|
|
34
|
-
still open, edit and delete them — so remove the deck itself if that is what you want gone.
|
|
35
|
-
</p>
|
|
36
|
-
<p className="text-xs text-base-contrast-light">
|
|
37
|
-
A deck is private to the person who made it. Sharing it with an audience, or by public link, comes later.
|
|
38
|
-
</p>
|
|
39
|
-
</div>
|
|
40
|
-
);
|
|
41
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { DeckTextSlot } from "../lib/deck-edit";
|
|
2
|
-
import type { DeckComponent } from "../schemas/deck";
|
|
3
|
-
import { DeckImage } from "./components/DeckImage";
|
|
4
|
-
import { DeckImageGrid } from "./components/DeckImageGrid";
|
|
5
|
-
import { DeckRichText } from "./components/DeckRichText";
|
|
6
|
-
import { DeckVideo } from "./components/DeckVideo";
|
|
7
|
-
|
|
8
|
-
interface Props {
|
|
9
|
-
component: DeckComponent;
|
|
10
|
-
/** The Layout slot this component fills — carried only so text leaves can
|
|
11
|
-
* address themselves for inline editing (#39). Optional: a caller that omits
|
|
12
|
-
* it gets the read-only render. */
|
|
13
|
-
slot?: DeckTextSlot;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** Dispatches a Deck Component onto its runtime implementation. */
|
|
17
|
-
export function DeckComponentView({ component, slot }: Props) {
|
|
18
|
-
switch (component.type) {
|
|
19
|
-
case "richText":
|
|
20
|
-
return <DeckRichText content={component} slot={slot} />;
|
|
21
|
-
case "image":
|
|
22
|
-
return <DeckImage content={component} />;
|
|
23
|
-
case "imageGrid":
|
|
24
|
-
return <DeckImageGrid content={component} />;
|
|
25
|
-
case "video":
|
|
26
|
-
return <DeckVideo content={component} />;
|
|
27
|
-
}
|
|
28
|
-
}
|
package/src/deck/DeckPlayer.tsx
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
2
|
-
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
3
|
-
import { cn } from "../lib/cn";
|
|
4
|
-
import type { Deck, DeckMediaAsset, DeckMediaResolver } from "../schemas/deck";
|
|
5
|
-
import { DeckMediaProvider } from "./media";
|
|
6
|
-
import { DeckStage } from "./DeckStage";
|
|
7
|
-
import { DeckSlideView } from "./DeckSlideView";
|
|
8
|
-
|
|
9
|
-
interface Props {
|
|
10
|
-
deck: Deck;
|
|
11
|
-
/** Slide to open on. Out-of-range values clamp into the deck. */
|
|
12
|
-
initialSlide?: number;
|
|
13
|
-
/** Window-level arrow/space/Home/End navigation. Off for thumbnails. */
|
|
14
|
-
keyboard?: boolean;
|
|
15
|
-
/** Turns media references into bytes. The Deck Builder injects the real one. */
|
|
16
|
-
resolveMedia?: DeckMediaResolver;
|
|
17
|
-
/**
|
|
18
|
-
* Pre-resolved portal media, keyed by media id. The serializable form of the
|
|
19
|
-
* same seam, for callers that cross an Astro island boundary — a function
|
|
20
|
-
* prop cannot survive that trip. Ignored when `resolveMedia` is given.
|
|
21
|
-
*/
|
|
22
|
-
mediaAssets?: Record<string, DeckMediaAsset>;
|
|
23
|
-
className?: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function clamp(index: number, length: number): number {
|
|
27
|
-
return Math.min(Math.max(index, 0), length - 1);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Arrow keys must not steal typing from a chat panel docked beside the stage. */
|
|
31
|
-
function isTypingTarget(target: EventTarget | null): boolean {
|
|
32
|
-
if (!(target instanceof HTMLElement)) return false;
|
|
33
|
-
return target.isContentEditable || ["INPUT", "TEXTAREA", "SELECT"].includes(target.tagName);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* A native button activates on Space *keyup*; the keydown only marks it active
|
|
38
|
-
* and suppresses scrolling. Calling preventDefault on that keydown cancels the
|
|
39
|
-
* activation — so Space on a focused "Previous slide" used to swallow the click
|
|
40
|
-
* and step FORWARD instead. Enter needs no such guard: it has no case below, so
|
|
41
|
-
* it never reaches preventDefault.
|
|
42
|
-
*/
|
|
43
|
-
function isActivatableTarget(target: EventTarget | null): boolean {
|
|
44
|
-
if (!(target instanceof HTMLElement)) return false;
|
|
45
|
-
if (target.tagName === "BUTTON" || target.tagName === "SUMMARY") return true;
|
|
46
|
-
if (target.tagName === "A" && target.hasAttribute("href")) return true;
|
|
47
|
-
return target.getAttribute("role") === "button";
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const NAV_BUTTON =
|
|
51
|
-
"flex size-[38px] items-center justify-center rounded-[var(--radius-outer)] border border-base-200 text-base-contrast transition-colors hover:bg-base-accent disabled:cursor-not-allowed disabled:opacity-35 disabled:hover:bg-transparent";
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* The deck runtime's presentation surface: one 16:9 stage plus slide
|
|
55
|
-
* navigation. Deliberately self-contained — the Deck Builder, the in-portal
|
|
56
|
-
* deck view and the Public Link view all mount this same component, so slide
|
|
57
|
-
* state lives here rather than in any one of those shells.
|
|
58
|
-
*/
|
|
59
|
-
export function DeckPlayer({ deck, initialSlide = 0, keyboard = true, resolveMedia, mediaAssets, className }: Props) {
|
|
60
|
-
const total = deck.slides.length;
|
|
61
|
-
const [index, setIndex] = useState(() => clamp(initialSlide, total));
|
|
62
|
-
// `Object.hasOwn`, not indexing: a media id is author-supplied, and a plain
|
|
63
|
-
// object answers `"constructor"` and `"toString"` with inherited members that
|
|
64
|
-
// are not assets at all. The schema's charset rules those ids out too — this
|
|
65
|
-
// is the second lock on the same door. The `kind` check keeps the map form
|
|
66
|
-
// honest the day a second media kind lands: it resolves portal ids, and says
|
|
67
|
-
// so by refusing everything else rather than looking the id up anyway.
|
|
68
|
-
const resolve = useMemo<DeckMediaResolver>(
|
|
69
|
-
() =>
|
|
70
|
-
resolveMedia ??
|
|
71
|
-
((ref) =>
|
|
72
|
-
ref.kind === "portal" && mediaAssets !== undefined && Object.hasOwn(mediaAssets, ref.id)
|
|
73
|
-
? mediaAssets[ref.id]
|
|
74
|
-
: null),
|
|
75
|
-
[resolveMedia, mediaAssets],
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
const current = clamp(index, total);
|
|
79
|
-
const slide = deck.slides[current];
|
|
80
|
-
|
|
81
|
-
const goTo = useCallback((next: number) => setIndex(clamp(next, total)), [total]);
|
|
82
|
-
// `prev` is clamped BEFORE the delta: the builder live-replaces the deck every
|
|
83
|
-
// LLM turn, so a shrunk deck can leave the stored index past the end. Without
|
|
84
|
-
// the inner clamp the first Previous press would land back on the slide
|
|
85
|
-
// already showing — a visible no-op.
|
|
86
|
-
const step = useCallback(
|
|
87
|
-
(delta: number) => setIndex((prev) => clamp(clamp(prev, total) + delta, total)),
|
|
88
|
-
[total],
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
useEffect(() => {
|
|
92
|
-
if (!keyboard) return;
|
|
93
|
-
const onKeyDown = (event: KeyboardEvent) => {
|
|
94
|
-
if (event.metaKey || event.ctrlKey || event.altKey) return;
|
|
95
|
-
if (isTypingTarget(event.target)) return;
|
|
96
|
-
switch (event.key) {
|
|
97
|
-
case " ":
|
|
98
|
-
if (isActivatableTarget(event.target)) return;
|
|
99
|
-
event.preventDefault();
|
|
100
|
-
step(1);
|
|
101
|
-
break;
|
|
102
|
-
case "ArrowRight":
|
|
103
|
-
case "PageDown":
|
|
104
|
-
event.preventDefault();
|
|
105
|
-
step(1);
|
|
106
|
-
break;
|
|
107
|
-
case "ArrowLeft":
|
|
108
|
-
case "PageUp":
|
|
109
|
-
event.preventDefault();
|
|
110
|
-
step(-1);
|
|
111
|
-
break;
|
|
112
|
-
case "Home":
|
|
113
|
-
event.preventDefault();
|
|
114
|
-
setIndex(0);
|
|
115
|
-
break;
|
|
116
|
-
case "End":
|
|
117
|
-
event.preventDefault();
|
|
118
|
-
setIndex(total - 1);
|
|
119
|
-
break;
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
window.addEventListener("keydown", onKeyDown);
|
|
123
|
-
return () => window.removeEventListener("keydown", onKeyDown);
|
|
124
|
-
}, [keyboard, step, total]);
|
|
125
|
-
|
|
126
|
-
return (
|
|
127
|
-
<div data-deck-player={deck.id} className={cn("flex h-full min-h-0 w-full flex-col gap-4 bg-base p-4", className)}>
|
|
128
|
-
<DeckStage className="flex-1">
|
|
129
|
-
<DeckMediaProvider resolve={resolve}>
|
|
130
|
-
<DeckSlideView slide={slide} />
|
|
131
|
-
</DeckMediaProvider>
|
|
132
|
-
</DeckStage>
|
|
133
|
-
|
|
134
|
-
<nav aria-label={`${deck.title} slides`} className="flex shrink-0 items-center justify-center gap-4">
|
|
135
|
-
<button type="button" className={NAV_BUTTON} onClick={() => step(-1)} disabled={current === 0} aria-label="Previous slide">
|
|
136
|
-
<ChevronLeft className="size-5" aria-hidden="true" />
|
|
137
|
-
</button>
|
|
138
|
-
|
|
139
|
-
<ol className="flex items-center gap-2">
|
|
140
|
-
{deck.slides.map((s, i) => (
|
|
141
|
-
<li key={s.id}>
|
|
142
|
-
<button
|
|
143
|
-
type="button"
|
|
144
|
-
onClick={() => goTo(i)}
|
|
145
|
-
aria-current={i === current ? "true" : undefined}
|
|
146
|
-
aria-label={s.title ? `Slide ${i + 1}: ${s.title}` : `Slide ${i + 1}`}
|
|
147
|
-
className={cn(
|
|
148
|
-
"size-[10px] rounded-full transition-colors",
|
|
149
|
-
i === current ? "bg-primary" : "bg-base-300 hover:bg-base-contrast-light",
|
|
150
|
-
)}
|
|
151
|
-
/>
|
|
152
|
-
</li>
|
|
153
|
-
))}
|
|
154
|
-
</ol>
|
|
155
|
-
|
|
156
|
-
<button type="button" className={NAV_BUTTON} onClick={() => step(1)} disabled={current === total - 1} aria-label="Next slide">
|
|
157
|
-
<ChevronRight className="size-5" aria-hidden="true" />
|
|
158
|
-
</button>
|
|
159
|
-
|
|
160
|
-
<p aria-live="polite" className="ml-2 text-sm tabular-nums text-base-contrast-light">
|
|
161
|
-
{current + 1} / {total}
|
|
162
|
-
</p>
|
|
163
|
-
</nav>
|
|
164
|
-
</div>
|
|
165
|
-
);
|
|
166
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { DeckSlide } from "../schemas/deck";
|
|
2
|
-
import { CenteredTextLayout } from "./layouts/CenteredTextLayout";
|
|
3
|
-
import { ColumnSplitLayout } from "./layouts/ColumnSplitLayout";
|
|
4
|
-
import { FullBleedImageLayout } from "./layouts/FullBleedImageLayout";
|
|
5
|
-
|
|
6
|
-
interface Props {
|
|
7
|
-
slide: DeckSlide;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function LayoutView({ slide }: Props) {
|
|
11
|
-
const { layout } = slide;
|
|
12
|
-
switch (layout.type) {
|
|
13
|
-
case "centeredText":
|
|
14
|
-
return <CenteredTextLayout layout={layout} />;
|
|
15
|
-
case "fullBleedImage":
|
|
16
|
-
return <FullBleedImageLayout layout={layout} />;
|
|
17
|
-
case "columnSplit":
|
|
18
|
-
return <ColumnSplitLayout layout={layout} />;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Dispatches a slide onto its Layout. One slide uses exactly one Layout.
|
|
24
|
-
*
|
|
25
|
-
* Keyed by slide id, and that key is load-bearing rather than a lint nicety:
|
|
26
|
-
* two slides sharing a Layout shape reconcile onto the SAME component
|
|
27
|
-
* instances, so an expanded image-grid tile or a playing video on slide 1 was
|
|
28
|
-
* inherited by slide 2 the moment you pressed the arrow key. The key forces the
|
|
29
|
-
* subtree to remount, which is the only thing that makes a slide's interaction
|
|
30
|
-
* state belong to that slide.
|
|
31
|
-
*/
|
|
32
|
-
export function DeckSlideView({ slide }: Props) {
|
|
33
|
-
return (
|
|
34
|
-
<div key={slide.id} data-deck-slide={slide.id} className="size-full">
|
|
35
|
-
<LayoutView slide={slide} />
|
|
36
|
-
</div>
|
|
37
|
-
);
|
|
38
|
-
}
|
package/src/deck/DeckStage.tsx
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { useRef, type ReactNode } from "react";
|
|
2
|
-
import { cn } from "../lib/cn";
|
|
3
|
-
import { DECK_STAGE_HEIGHT, DECK_STAGE_WIDTH } from "../schemas/deck";
|
|
4
|
-
import { useStageScale } from "./useStageScale";
|
|
5
|
-
|
|
6
|
-
interface Props {
|
|
7
|
-
children: ReactNode;
|
|
8
|
-
/** Applied to the fit box, which is what the stage is scaled to fill. */
|
|
9
|
-
className?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* The 16:9 stage: a fixed logical canvas centered in — and scaled to fit — its
|
|
14
|
-
* container, so slide contents are authored in px against one coordinate system
|
|
15
|
-
* regardless of the viewport. Scaling by transform (rather than by a font-size
|
|
16
|
-
* cascade) keeps every measurement, including line breaks, identical at every
|
|
17
|
-
* size, which is what makes a screenshared deck look the same as its preview.
|
|
18
|
-
*/
|
|
19
|
-
export function DeckStage({ children, className }: Props) {
|
|
20
|
-
const fitRef = useRef<HTMLDivElement>(null);
|
|
21
|
-
const scale = useStageScale(fitRef);
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<div ref={fitRef} className={cn("relative min-h-0 w-full overflow-hidden", className)} data-deck-fit="">
|
|
25
|
-
<div
|
|
26
|
-
data-deck-stage=""
|
|
27
|
-
data-deck-scale={scale === null ? undefined : scale.toFixed(4)}
|
|
28
|
-
className="absolute top-1/2 left-1/2 origin-center overflow-hidden rounded-[var(--radius-outer)] font-body"
|
|
29
|
-
style={{
|
|
30
|
-
width: DECK_STAGE_WIDTH,
|
|
31
|
-
height: DECK_STAGE_HEIGHT,
|
|
32
|
-
transform: scale === null ? "translate(-50%, -50%)" : `translate(-50%, -50%) scale(${scale})`,
|
|
33
|
-
}}
|
|
34
|
-
>
|
|
35
|
-
{children}
|
|
36
|
-
</div>
|
|
37
|
-
</div>
|
|
38
|
-
);
|
|
39
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { DeckImage as DeckImageContent } from "../../schemas/deck";
|
|
2
|
-
import { DeckMissingMedia, useDeckMedia } from "../media";
|
|
3
|
-
import { surfaceInk } from "../tokens";
|
|
4
|
-
|
|
5
|
-
interface Props {
|
|
6
|
-
content: DeckImageContent;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Deck Component — image.
|
|
11
|
-
*
|
|
12
|
-
* Fills its slot and crops. The caption is a solid brand block sitting on the
|
|
13
|
-
* image's bottom edge rather than a gradient scrim: a scrim needs a literal
|
|
14
|
-
* color to darken toward, and legibility here comes from the block.
|
|
15
|
-
*/
|
|
16
|
-
export function DeckImage({ content }: Props) {
|
|
17
|
-
const asset = useDeckMedia(content.media);
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<figure data-deck-component="image" className="relative size-full overflow-hidden bg-base-200">
|
|
21
|
-
{asset === null ? (
|
|
22
|
-
<DeckMissingMedia />
|
|
23
|
-
) : (
|
|
24
|
-
<img src={asset.src} alt={asset.alt} className="size-full object-cover" />
|
|
25
|
-
)}
|
|
26
|
-
|
|
27
|
-
{content.caption !== undefined && (
|
|
28
|
-
<figcaption
|
|
29
|
-
data-deck-surface="brand"
|
|
30
|
-
style={surfaceInk("brand")}
|
|
31
|
-
className="absolute right-0 bottom-0 left-0 bg-primary px-[28px] py-[18px] text-[18px] tracking-[0.06em] text-[var(--deck-ink)] [text-transform:var(--nav-text-transform)]"
|
|
32
|
-
>
|
|
33
|
-
{content.caption}
|
|
34
|
-
</figcaption>
|
|
35
|
-
)}
|
|
36
|
-
</figure>
|
|
37
|
-
);
|
|
38
|
-
}
|