@drawnagency/primitives 0.1.117 → 0.1.119

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.
Files changed (263) hide show
  1. package/dist/{chunk-O37AV27P.js → chunk-5JYHTHVR.js} +28 -0
  2. package/dist/{chunk-W72BPGR3.js → chunk-BZKHHUIN.js} +44 -8
  3. package/dist/{chunk-CEFFP3CH.js → chunk-G6O3TYPJ.js} +297 -83
  4. package/dist/{chunk-L7WTERU5.js → chunk-HFHM4MNK.js} +33 -10
  5. package/dist/{chunk-RIITGTV3.js → chunk-LQHBC7C6.js} +37 -2
  6. package/dist/{chunk-VY3IFGE3.js → chunk-QAMAIDXZ.js} +1 -1
  7. package/dist/{chunk-LNQUUC2S.js → chunk-RIN2QCYJ.js} +9 -11
  8. package/dist/{chunk-HUOW3ZV2.js → chunk-UNFPATDE.js} +8 -10
  9. package/dist/{chunk-MSBHMY3C.js → chunk-YKKGVSJH.js} +35 -37
  10. package/dist/{chunk-67P34WNW.js → chunk-ZKVQMIMJ.js} +3 -20
  11. package/dist/collab/rebase.js +4 -5
  12. package/dist/components/chat/ChatComposer.d.ts +0 -4
  13. package/dist/components/chat/ChatComposer.d.ts.map +1 -1
  14. package/dist/components/chat/ChatPanel.d.ts +2 -3
  15. package/dist/components/chat/ChatPanel.d.ts.map +1 -1
  16. package/dist/components/chat/markdown.d.ts +2 -3
  17. package/dist/components/chat/markdown.d.ts.map +1 -1
  18. package/dist/components/editor/PagesModal.d.ts +0 -2
  19. package/dist/components/editor/PagesModal.d.ts.map +1 -1
  20. package/dist/components/editor/index.js +15 -19
  21. package/dist/components/primitives/EditablePlainText.d.ts.map +1 -1
  22. package/dist/components/primitives/index.js +11 -15
  23. package/dist/components/sections/brand-guide.js +10 -13
  24. package/dist/components/sections/register-schemas.js +16 -21
  25. package/dist/components/sections/register.js +16 -21
  26. package/dist/components/shell/AudienceChips.d.ts +1 -3
  27. package/dist/components/shell/AudienceChips.d.ts.map +1 -1
  28. package/dist/components/shell/AudienceDetailsPanel.d.ts +3 -1
  29. package/dist/components/shell/AudienceDetailsPanel.d.ts.map +1 -1
  30. package/dist/components/shell/EditorShell.d.ts +0 -34
  31. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  32. package/dist/components/shell/SiteSettingsModal.d.ts.map +1 -1
  33. package/dist/hooks/useSortableNavRow.d.ts +1 -1
  34. package/dist/hooks/useSortableRow.d.ts +1 -1
  35. package/dist/index.js +83 -90
  36. package/dist/lib/index-ops.js +5 -6
  37. package/dist/lib/index.js +27 -32
  38. package/dist/lib/pages.d.ts +0 -2
  39. package/dist/lib/pages.d.ts.map +1 -1
  40. package/dist/lib/sidecars.js +2 -2
  41. package/dist/lib/site-validation.js +13 -14
  42. package/dist/lib/storage-tier.js +4 -4
  43. package/dist/schemas/index.js +42 -45
  44. package/dist/schemas/site-config.d.ts +1 -277
  45. package/dist/schemas/site-config.d.ts.map +1 -1
  46. package/package.json +2 -42
  47. package/src/components/chat/ChatComposer.tsx +0 -4
  48. package/src/components/chat/ChatPanel.tsx +2 -3
  49. package/src/components/chat/markdown.ts +2 -3
  50. package/src/components/editor/PagesModal.tsx +1 -15
  51. package/src/components/editor/StatusIndicator.tsx +4 -4
  52. package/src/components/primitives/EditablePlainText.tsx +27 -3
  53. package/src/components/shell/AudienceChips.tsx +1 -3
  54. package/src/components/shell/AudienceDetailsPanel.tsx +6 -4
  55. package/src/components/shell/EditorShell.tsx +18 -114
  56. package/src/components/shell/SiteSettingsModal.tsx +0 -11
  57. package/src/lib/pages.ts +0 -22
  58. package/src/schemas/index.ts +0 -4
  59. package/src/schemas/site-config.ts +4 -32
  60. package/dist/chunk-4TZJZU2T.js +0 -92
  61. package/dist/chunk-DIMDRBFK.js +0 -11
  62. package/dist/chunk-FV7JQRCN.js +0 -94
  63. package/dist/chunk-IIDKW7AV.js +0 -41
  64. package/dist/chunk-JCDZAFX2.js +0 -224
  65. package/dist/chunk-MM7KZS5C.js +0 -30
  66. package/dist/chunk-QQ3S3P5P.js +0 -38
  67. package/dist/chunk-TEOAKGZA.js +0 -784
  68. package/dist/chunk-VAYZJKVR.js +0 -209
  69. package/dist/components/shell/DocInspector.d.ts +0 -18
  70. package/dist/components/shell/DocInspector.d.ts.map +0 -1
  71. package/dist/components/shell/DocumentEditorOverlay.d.ts +0 -29
  72. package/dist/components/shell/DocumentEditorOverlay.d.ts.map +0 -1
  73. package/dist/components/shell/DocumentPresentOverlay.d.ts +0 -30
  74. package/dist/components/shell/DocumentPresentOverlay.d.ts.map +0 -1
  75. package/dist/components/shell/SiteSettingsDecks.d.ts +0 -13
  76. package/dist/components/shell/SiteSettingsDecks.d.ts.map +0 -1
  77. package/dist/deck/DeckComponentView.d.ts +0 -13
  78. package/dist/deck/DeckComponentView.d.ts.map +0 -1
  79. package/dist/deck/DeckPlayer.d.ts +0 -26
  80. package/dist/deck/DeckPlayer.d.ts.map +0 -1
  81. package/dist/deck/DeckSlideView.d.ts +0 -17
  82. package/dist/deck/DeckSlideView.d.ts.map +0 -1
  83. package/dist/deck/DeckStage.d.ts +0 -16
  84. package/dist/deck/DeckStage.d.ts.map +0 -1
  85. package/dist/deck/components/DeckImage.d.ts +0 -14
  86. package/dist/deck/components/DeckImage.d.ts.map +0 -1
  87. package/dist/deck/components/DeckImageGrid.d.ts +0 -27
  88. package/dist/deck/components/DeckImageGrid.d.ts.map +0 -1
  89. package/dist/deck/components/DeckRichText.d.ts +0 -22
  90. package/dist/deck/components/DeckRichText.d.ts.map +0 -1
  91. package/dist/deck/components/DeckVideo.d.ts +0 -15
  92. package/dist/deck/components/DeckVideo.d.ts.map +0 -1
  93. package/dist/deck/editing.d.ts +0 -50
  94. package/dist/deck/editing.d.ts.map +0 -1
  95. package/dist/deck/flip.d.ts +0 -11
  96. package/dist/deck/flip.d.ts.map +0 -1
  97. package/dist/deck/index.d.ts +0 -24
  98. package/dist/deck/index.d.ts.map +0 -1
  99. package/dist/deck/index.js +0 -51
  100. package/dist/deck/layouts/CenteredTextLayout.d.ts +0 -12
  101. package/dist/deck/layouts/CenteredTextLayout.d.ts.map +0 -1
  102. package/dist/deck/layouts/ColumnSplitLayout.d.ts +0 -14
  103. package/dist/deck/layouts/ColumnSplitLayout.d.ts.map +0 -1
  104. package/dist/deck/layouts/FullBleedImageLayout.d.ts +0 -14
  105. package/dist/deck/layouts/FullBleedImageLayout.d.ts.map +0 -1
  106. package/dist/deck/media.d.ts +0 -33
  107. package/dist/deck/media.d.ts.map +0 -1
  108. package/dist/deck/tokens.d.ts +0 -22
  109. package/dist/deck/tokens.d.ts.map +0 -1
  110. package/dist/deck/useStageScale.d.ts +0 -10
  111. package/dist/deck/useStageScale.d.ts.map +0 -1
  112. package/dist/deck-builder/DeckBuilderApp.d.ts +0 -30
  113. package/dist/deck-builder/DeckBuilderApp.d.ts.map +0 -1
  114. package/dist/deck-builder/DeckBuilderTopBar.d.ts +0 -24
  115. package/dist/deck-builder/DeckBuilderTopBar.d.ts.map +0 -1
  116. package/dist/deck-builder/DeckChatPanel.d.ts +0 -45
  117. package/dist/deck-builder/DeckChatPanel.d.ts.map +0 -1
  118. package/dist/deck-builder/DeckEditor.d.ts +0 -37
  119. package/dist/deck-builder/DeckEditor.d.ts.map +0 -1
  120. package/dist/deck-builder/DeckLibrary.d.ts +0 -22
  121. package/dist/deck-builder/DeckLibrary.d.ts.map +0 -1
  122. package/dist/deck-builder/DeckSlideSurface.d.ts +0 -31
  123. package/dist/deck-builder/DeckSlideSurface.d.ts.map +0 -1
  124. package/dist/deck-builder/deck-api.d.ts +0 -76
  125. package/dist/deck-builder/deck-api.d.ts.map +0 -1
  126. package/dist/deck-builder/deck-chat-client.d.ts +0 -44
  127. package/dist/deck-builder/deck-chat-client.d.ts.map +0 -1
  128. package/dist/deck-builder/deck-chat-history.d.ts +0 -10
  129. package/dist/deck-builder/deck-chat-history.d.ts.map +0 -1
  130. package/dist/deck-builder/index.d.ts +0 -13
  131. package/dist/deck-builder/index.d.ts.map +0 -1
  132. package/dist/deck-builder/index.js +0 -1498
  133. package/dist/deck-builder/starter-deck.d.ts +0 -23
  134. package/dist/deck-builder/starter-deck.d.ts.map +0 -1
  135. package/dist/deck-builder/types.d.ts +0 -29
  136. package/dist/deck-builder/types.d.ts.map +0 -1
  137. package/dist/deck-builder/useSortableSlide.d.ts +0 -29
  138. package/dist/deck-builder/useSortableSlide.d.ts.map +0 -1
  139. package/dist/document/assets/fonts/albra-grotesk-bold.woff +0 -0
  140. package/dist/document/assets/fonts/albra-grotesk-regular.woff +0 -0
  141. package/dist/document/assets/fonts/kapra-neue-expanded-medium.woff +0 -0
  142. package/dist/document/assets/fonts/kapra-neue-expanded-regular.woff +0 -0
  143. package/dist/document/components/DocCoverPage.d.ts +0 -11
  144. package/dist/document/components/DocCoverPage.d.ts.map +0 -1
  145. package/dist/document/components/DocPage.d.ts +0 -10
  146. package/dist/document/components/DocPage.d.ts.map +0 -1
  147. package/dist/document/components/DocRail.d.ts +0 -28
  148. package/dist/document/components/DocRail.d.ts.map +0 -1
  149. package/dist/document/components/DocSectionPage.d.ts +0 -12
  150. package/dist/document/components/DocSectionPage.d.ts.map +0 -1
  151. package/dist/document/components/DocViewer.d.ts +0 -21
  152. package/dist/document/components/DocViewer.d.ts.map +0 -1
  153. package/dist/document/components/Wordmark.d.ts +0 -4
  154. package/dist/document/components/Wordmark.d.ts.map +0 -1
  155. package/dist/document/components/measure.d.ts +0 -7
  156. package/dist/document/components/measure.d.ts.map +0 -1
  157. package/dist/document/components/useDocPages.d.ts +0 -12
  158. package/dist/document/components/useDocPages.d.ts.map +0 -1
  159. package/dist/document/engine/blocks.d.ts +0 -2
  160. package/dist/document/engine/blocks.d.ts.map +0 -1
  161. package/dist/document/engine/harvest.d.ts +0 -3
  162. package/dist/document/engine/harvest.d.ts.map +0 -1
  163. package/dist/document/engine/masonry.d.ts +0 -26
  164. package/dist/document/engine/masonry.d.ts.map +0 -1
  165. package/dist/document/engine/paginate.d.ts +0 -43
  166. package/dist/document/engine/paginate.d.ts.map +0 -1
  167. package/dist/document/engine/settings.d.ts +0 -91
  168. package/dist/document/engine/settings.d.ts.map +0 -1
  169. package/dist/document/engine/types.d.ts +0 -44
  170. package/dist/document/engine/types.d.ts.map +0 -1
  171. package/dist/document/index.d.ts +0 -13
  172. package/dist/document/index.d.ts.map +0 -1
  173. package/dist/document/index.js +0 -1030
  174. package/dist/document/styles/document.css +0 -217
  175. package/dist/lib/deck-access.d.ts +0 -86
  176. package/dist/lib/deck-access.d.ts.map +0 -1
  177. package/dist/lib/deck-access.js +0 -58
  178. package/dist/lib/deck-dexie.d.ts +0 -88
  179. package/dist/lib/deck-dexie.d.ts.map +0 -1
  180. package/dist/lib/deck-dexie.js +0 -22
  181. package/dist/lib/deck-edit.d.ts +0 -67
  182. package/dist/lib/deck-edit.d.ts.map +0 -1
  183. package/dist/lib/deck-media-assets.d.ts +0 -27
  184. package/dist/lib/deck-media-assets.d.ts.map +0 -1
  185. package/dist/lib/deck-media-assets.js +0 -25
  186. package/dist/lib/deck-media-refs.d.ts +0 -35
  187. package/dist/lib/deck-media-refs.d.ts.map +0 -1
  188. package/dist/lib/deck-media-refs.js +0 -36
  189. package/dist/lib/deck-tool.d.ts +0 -25
  190. package/dist/lib/deck-tool.d.ts.map +0 -1
  191. package/dist/lib/deck-tool.js +0 -58
  192. package/dist/lib/document-input.d.ts +0 -25
  193. package/dist/lib/document-input.d.ts.map +0 -1
  194. package/dist/schemas/deck-meta.d.ts +0 -85
  195. package/dist/schemas/deck-meta.d.ts.map +0 -1
  196. package/dist/schemas/deck-meta.js +0 -64
  197. package/dist/schemas/deck.d.ts +0 -954
  198. package/dist/schemas/deck.d.ts.map +0 -1
  199. package/dist/schemas/deck.js +0 -65
  200. package/src/components/shell/DocInspector.tsx +0 -314
  201. package/src/components/shell/DocumentEditorOverlay.tsx +0 -179
  202. package/src/components/shell/DocumentPresentOverlay.tsx +0 -87
  203. package/src/components/shell/SiteSettingsDecks.tsx +0 -41
  204. package/src/deck/DeckComponentView.tsx +0 -28
  205. package/src/deck/DeckPlayer.tsx +0 -166
  206. package/src/deck/DeckSlideView.tsx +0 -38
  207. package/src/deck/DeckStage.tsx +0 -39
  208. package/src/deck/components/DeckImage.tsx +0 -38
  209. package/src/deck/components/DeckImageGrid.tsx +0 -254
  210. package/src/deck/components/DeckRichText.tsx +0 -111
  211. package/src/deck/components/DeckVideo.tsx +0 -81
  212. package/src/deck/editing.tsx +0 -201
  213. package/src/deck/flip.ts +0 -70
  214. package/src/deck/index.ts +0 -30
  215. package/src/deck/layouts/CenteredTextLayout.tsx +0 -29
  216. package/src/deck/layouts/ColumnSplitLayout.tsx +0 -69
  217. package/src/deck/layouts/FullBleedImageLayout.tsx +0 -58
  218. package/src/deck/media.tsx +0 -46
  219. package/src/deck/tokens.ts +0 -57
  220. package/src/deck/useStageScale.ts +0 -44
  221. package/src/deck-builder/DeckBuilderApp.tsx +0 -572
  222. package/src/deck-builder/DeckBuilderTopBar.tsx +0 -62
  223. package/src/deck-builder/DeckChatPanel.tsx +0 -334
  224. package/src/deck-builder/DeckEditor.tsx +0 -258
  225. package/src/deck-builder/DeckLibrary.tsx +0 -195
  226. package/src/deck-builder/DeckSlideSurface.tsx +0 -55
  227. package/src/deck-builder/deck-api.ts +0 -177
  228. package/src/deck-builder/deck-chat-client.ts +0 -129
  229. package/src/deck-builder/deck-chat-history.ts +0 -62
  230. package/src/deck-builder/index.ts +0 -12
  231. package/src/deck-builder/starter-deck.ts +0 -86
  232. package/src/deck-builder/types.ts +0 -24
  233. package/src/deck-builder/useSortableSlide.ts +0 -102
  234. package/src/document/assets/fonts/albra-grotesk-bold.woff +0 -0
  235. package/src/document/assets/fonts/albra-grotesk-regular.woff +0 -0
  236. package/src/document/assets/fonts/kapra-neue-expanded-medium.woff +0 -0
  237. package/src/document/assets/fonts/kapra-neue-expanded-regular.woff +0 -0
  238. package/src/document/components/DocCoverPage.tsx +0 -45
  239. package/src/document/components/DocPage.tsx +0 -40
  240. package/src/document/components/DocRail.tsx +0 -189
  241. package/src/document/components/DocSectionPage.tsx +0 -48
  242. package/src/document/components/DocViewer.tsx +0 -313
  243. package/src/document/components/Wordmark.tsx +0 -18
  244. package/src/document/components/measure.tsx +0 -133
  245. package/src/document/components/useDocPages.ts +0 -95
  246. package/src/document/engine/blocks.ts +0 -116
  247. package/src/document/engine/harvest.ts +0 -95
  248. package/src/document/engine/masonry.ts +0 -158
  249. package/src/document/engine/paginate.ts +0 -232
  250. package/src/document/engine/settings.ts +0 -125
  251. package/src/document/engine/types.ts +0 -64
  252. package/src/document/index.ts +0 -18
  253. package/src/document/styles/document.css +0 -217
  254. package/src/lib/deck-access.ts +0 -132
  255. package/src/lib/deck-dexie.ts +0 -190
  256. package/src/lib/deck-edit.ts +0 -196
  257. package/src/lib/deck-media-assets.ts +0 -57
  258. package/src/lib/deck-media-refs.ts +0 -67
  259. package/src/lib/deck-tool.ts +0 -95
  260. package/src/lib/document-input.ts +0 -57
  261. package/src/schemas/deck-meta.ts +0 -88
  262. package/src/schemas/deck.ts +0 -478
  263. package/dist/{chunk-DJABADOO.js → chunk-AJ2QOAZI.js} +3 -3
@@ -1,92 +0,0 @@
1
- // src/document/engine/settings.ts
2
- import { z } from "zod";
3
- var sectionSettingsSchema = z.object({
4
- excluded: z.boolean().default(false),
5
- textPlacement: z.enum(["top", "leftColumn"]).default("top"),
6
- // "right" is only meaningful with textPlacement "leftColumn"; settingsFor
7
- // normalizes the invalid combo.
8
- imagePlacement: z.enum(["fullWidth", "right"]).default("fullWidth"),
9
- // When true, text that overflows the first page is dropped instead of
10
- // flowing onto Cont. pages (images still paginate normally).
11
- dropTextOverflow: z.boolean().default(false),
12
- // Also start new pages at sub-heading boundaries. Only read from PARENT
13
- // entries (link_heading ids / __preamble); inert on sub-chunk entries.
14
- splitAt: z.enum(["none", "sub_heading"]).default("none"),
15
- imageLayout: z.discriminatedUnion("mode", [
16
- z.object({
17
- mode: z.literal("grid"),
18
- rows: z.union([z.literal(1), z.literal(2), z.literal(3)]).default(2),
19
- columns: z.union([z.literal(2), z.literal(3), z.literal(4)]).default(4),
20
- // "cover" crops each image to its cell; "contain" letterboxes the
21
- // natural image inside it.
22
- fit: z.enum(["cover", "contain"]).default("cover")
23
- }),
24
- z.object({
25
- mode: z.literal("masonry"),
26
- flow: z.enum(["rows", "columns"]).default("rows"),
27
- columns: z.union([z.literal(2), z.literal(3), z.literal(4), z.literal(5), z.literal(6)]).default(3),
28
- // rows flow only: "auto" = greedy target-height fill (legacy behavior);
29
- // 1-4 forces an exact aspect-balanced row count.
30
- rows: z.union([z.literal("auto"), z.literal(1), z.literal(2), z.literal(3), z.literal(4)]).default("auto")
31
- })
32
- ]).default({ mode: "masonry", flow: "rows", columns: 3, rows: "auto" })
33
- });
34
- var DEFAULTS = sectionSettingsSchema.parse({});
35
- function salvage(raw) {
36
- const fast = sectionSettingsSchema.safeParse(raw ?? {});
37
- if (fast.success) return { settings: fast.data, rejected: [] };
38
- if (!raw || typeof raw !== "object") return { settings: DEFAULTS, rejected: [] };
39
- const src = raw;
40
- const out = {};
41
- const rejected = [];
42
- for (const [key, field] of Object.entries(sectionSettingsSchema.shape)) {
43
- const parsed = field.safeParse(src[key]);
44
- if (parsed.success) {
45
- out[key] = parsed.data;
46
- } else {
47
- rejected.push(key);
48
- out[key] = DEFAULTS[key];
49
- }
50
- }
51
- return { settings: out, rejected };
52
- }
53
- function settingsFor(all, chunkId) {
54
- const s = salvage(all?.[chunkId]).settings;
55
- if (s.textPlacement === "top" && s.imagePlacement === "right") {
56
- return { ...s, imagePlacement: "fullWidth" };
57
- }
58
- return s;
59
- }
60
- function settingsIssuesFor(all, chunkId) {
61
- return salvage(all?.[chunkId]).rejected;
62
- }
63
- var documentMetaSchema = z.object({
64
- client: z.string().default(""),
65
- project: z.string().default(""),
66
- dateLabel: z.string().default("")
67
- });
68
- var documentCoverSchema = z.object({
69
- bgColor: z.string().default("#333333"),
70
- accentColor: z.string().default("#EB9500"),
71
- title: z.string().default(""),
72
- label: z.string().default("BRAND GUIDELINES"),
73
- date: z.string().default(""),
74
- // Media-library image id shown between masthead and title lockup; null = solid cover.
75
- imageId: z.string().nullable().default(null)
76
- });
77
- var documentOptionsSchema = z.object({
78
- enabled: z.boolean().default(false),
79
- // `.default({})` doesn't typecheck even though `{}` parses fine at
80
- // runtime — zod v4 infers the default's type from the object schema's
81
- // required input shape, not its post-default output shape.
82
- meta: documentMetaSchema.default(() => documentMetaSchema.parse({})),
83
- cover: documentCoverSchema.default(() => documentCoverSchema.parse({})),
84
- sections: z.record(z.string(), sectionSettingsSchema).default({})
85
- });
86
-
87
- export {
88
- sectionSettingsSchema,
89
- settingsFor,
90
- settingsIssuesFor,
91
- documentOptionsSchema
92
- };
@@ -1,11 +0,0 @@
1
- // src/lib/reorder.ts
2
- function computeReorderTarget(fromIndex, overIndex, edge) {
3
- let toIndex = overIndex;
4
- if (edge === "bottom") toIndex = overIndex + 1;
5
- if (fromIndex < toIndex) toIndex--;
6
- return fromIndex === toIndex ? null : toIndex;
7
- }
8
-
9
- export {
10
- computeReorderTarget
11
- };
@@ -1,94 +0,0 @@
1
- import {
2
- serializeDeck
3
- } from "./chunk-VAYZJKVR.js";
4
-
5
- // src/lib/deck-dexie.ts
6
- import Dexie from "dexie";
7
- var DeckDraftDatabase = class extends Dexie {
8
- drafts;
9
- constructor(name) {
10
- super(name);
11
- this.version(1).stores({ drafts: "deckId" });
12
- }
13
- };
14
- function databaseName(siteId, scope) {
15
- return `brand-portal-decks-${siteId}-${scope}`;
16
- }
17
- var db = null;
18
- function initDeckDraftStore(siteId, scope) {
19
- const name = databaseName(siteId, scope);
20
- if (db?.name === name) return;
21
- db?.close();
22
- db = new DeckDraftDatabase(name);
23
- }
24
- function getDb() {
25
- if (!db) throw new Error("Deck draft store not initialized. Call initDeckDraftStore first.");
26
- return db;
27
- }
28
- async function listDeckDrafts() {
29
- const rows = await getDb().drafts.toArray();
30
- return rows.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
31
- }
32
- async function getDeckDraft(deckId) {
33
- return await getDb().drafts.get(deckId) ?? null;
34
- }
35
- async function putDeckDraft(deck) {
36
- const db2 = getDb();
37
- return db2.transaction("rw", db2.drafts, async () => {
38
- const existing = await db2.drafts.get(deck.id);
39
- const row = {
40
- deckId: deck.id,
41
- deck,
42
- baseVersion: existing?.baseVersion ?? null,
43
- publishedText: existing?.publishedText ?? null,
44
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
45
- };
46
- await db2.drafts.put(row);
47
- return row;
48
- });
49
- }
50
- async function markDeckDraftPublished(deck, version, updatedAt) {
51
- const row = {
52
- deckId: deck.id,
53
- deck,
54
- baseVersion: version,
55
- publishedText: serializeDeck(deck),
56
- updatedAt: updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
57
- };
58
- await getDb().drafts.put(row);
59
- return row;
60
- }
61
- async function recordDeckPublish(deckId, publishedDeck, version) {
62
- const db2 = getDb();
63
- return db2.transaction("rw", db2.drafts, async () => {
64
- const existing = await db2.drafts.get(deckId);
65
- if (!existing) return null;
66
- const row = {
67
- ...existing,
68
- baseVersion: version,
69
- publishedText: serializeDeck(publishedDeck),
70
- // "Now", as the previous implementation stamped: a publish is activity the
71
- // deck grid should sort on, even though it did not change the body.
72
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
73
- };
74
- await db2.drafts.put(row);
75
- return row;
76
- });
77
- }
78
- async function deleteDeckDraft(deckId) {
79
- await getDb().drafts.delete(deckId);
80
- }
81
- function hasUnpublishedChanges(row) {
82
- return row.publishedText === null || serializeDeck(row.deck) !== row.publishedText;
83
- }
84
-
85
- export {
86
- initDeckDraftStore,
87
- listDeckDrafts,
88
- getDeckDraft,
89
- putDeckDraft,
90
- markDeckDraftPublished,
91
- recordDeckPublish,
92
- deleteDeckDraft,
93
- hasUnpublishedChanges
94
- };
@@ -1,41 +0,0 @@
1
- import {
2
- cn
3
- } from "./chunk-7EOSDFS3.js";
4
-
5
- // src/components/shared/IconButton.tsx
6
- import { forwardRef } from "react";
7
- import { jsx } from "react/jsx-runtime";
8
- var sizeClasses = {
9
- sm: "h-chrome-sm w-chrome-sm",
10
- md: "h-chrome-md w-chrome-md",
11
- lg: "h-chrome-lg w-chrome-lg"
12
- };
13
- var intentClasses = {
14
- default: "text-base-contrast-light hover:text-base-contrast",
15
- destructive: "text-destructive hover:text-destructive-hover",
16
- primary: "text-primary/60 hover:text-primary"
17
- };
18
- var IconButton = forwardRef(
19
- function IconButton2({ icon, label, size = "md", intent = "default", className, ...rest }, ref) {
20
- return /* @__PURE__ */ jsx(
21
- "button",
22
- {
23
- ref,
24
- type: "button",
25
- className: cn(
26
- "cursor-pointer flex items-center justify-center rounded transition-colors",
27
- sizeClasses[size],
28
- intentClasses[intent],
29
- className
30
- ),
31
- "aria-label": label,
32
- ...rest,
33
- children: icon
34
- }
35
- );
36
- }
37
- );
38
-
39
- export {
40
- IconButton
41
- };
@@ -1,224 +0,0 @@
1
- import {
2
- cn
3
- } from "./chunk-7EOSDFS3.js";
4
-
5
- // src/components/shared/Tooltip.tsx
6
- import { jsx, jsxs } from "react/jsx-runtime";
7
- var sideClasses = {
8
- bottom: "left-1/2 top-full mt-1.5 -translate-x-1/2",
9
- right: "left-full top-1/2 ml-1.5 -translate-y-1/2",
10
- "bottom-clamp": "top-full mt-1.5 left-1/2 -translate-x-1/2 max-xl:left-auto max-xl:right-0 max-xl:translate-x-0"
11
- };
12
- function Tooltip({ content, children, className, side = "bottom" }) {
13
- return /* @__PURE__ */ jsxs("div", { className: cn("group/tooltip relative inline-flex", className), children: [
14
- children,
15
- /* @__PURE__ */ jsx(
16
- "span",
17
- {
18
- className: cn(
19
- "pointer-events-none absolute z-50 opacity-0 transition-opacity delay-300 group-hover/tooltip:opacity-100",
20
- sideClasses[side]
21
- ),
22
- role: "tooltip",
23
- children: /* @__PURE__ */ jsx("span", { className: "block whitespace-nowrap rounded bg-tooltip px-2 py-1 text-center text-xs leading-relaxed text-tooltip-muted", children: content })
24
- }
25
- )
26
- ] });
27
- }
28
- function Kbd({ children }) {
29
- return /* @__PURE__ */ jsx("strong", { className: "text-tooltip-contrast", children });
30
- }
31
-
32
- // src/components/shared/Popover.tsx
33
- import { useEffect as useEffect3, useLayoutEffect, useRef as useRef2, useState } from "react";
34
- import { createPortal } from "react-dom";
35
-
36
- // src/hooks/useFocusTrap.ts
37
- import { useEffect } from "react";
38
- var FOCUSABLE_SELECTOR = [
39
- "a[href]",
40
- "button:not([disabled])",
41
- "input:not([disabled])",
42
- "select:not([disabled])",
43
- "textarea:not([disabled])",
44
- '[tabindex]:not([tabindex="-1"])'
45
- ].join(", ");
46
- function useInitialFocus(ref, active) {
47
- useEffect(() => {
48
- if (!active || !ref.current) return;
49
- const previouslyFocused = document.activeElement;
50
- ref.current.querySelector(FOCUSABLE_SELECTOR)?.focus();
51
- return () => {
52
- if (previouslyFocused && document.body.contains(previouslyFocused)) {
53
- previouslyFocused.focus();
54
- }
55
- };
56
- }, [active, ref]);
57
- }
58
-
59
- // src/hooks/useStackedEscape.ts
60
- import { useEffect as useEffect2, useRef } from "react";
61
- function useStackedEscape(onEscape, { enabled, before }) {
62
- const layerRef = useRef(null);
63
- useEffect2(() => {
64
- if (!enabled) return;
65
- const onKeyDown = (e) => {
66
- if (e.key !== "Escape") return;
67
- const own = layerRef.current;
68
- const layers = document.querySelectorAll("[data-modal-layer]");
69
- const above = Array.from(layers).some((el) => {
70
- if (el === own) return false;
71
- if (!own) return true;
72
- return Boolean(own.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING);
73
- });
74
- if (above) return;
75
- if (before?.(e)) return;
76
- e.preventDefault();
77
- onEscape();
78
- };
79
- document.addEventListener("keydown", onKeyDown);
80
- return () => document.removeEventListener("keydown", onKeyDown);
81
- }, [enabled, onEscape, before]);
82
- return layerRef;
83
- }
84
-
85
- // src/components/shared/Popover.tsx
86
- import { jsx as jsx2 } from "react/jsx-runtime";
87
- function Popover({
88
- isOpen,
89
- onClose,
90
- anchorRef,
91
- children,
92
- align = "auto",
93
- className,
94
- portal = false,
95
- placement = "bottom"
96
- }) {
97
- const panelRef = useRef2(null);
98
- const [resolvedAlign, setResolvedAlign] = useState("start");
99
- const [fixedPos, setFixedPos] = useState(null);
100
- useInitialFocus(panelRef, isOpen && (!portal || fixedPos !== null));
101
- useLayoutEffect(() => {
102
- if (!portal) return;
103
- if (!isOpen) {
104
- setFixedPos(null);
105
- return;
106
- }
107
- const anchor = anchorRef.current;
108
- if (!anchor) return;
109
- const update = () => {
110
- const r = anchor.getBoundingClientRect();
111
- const next = placement === "top" ? { left: r.left, bottom: window.innerHeight - r.top + 4 } : { left: r.left, top: r.bottom + 4 };
112
- setFixedPos(
113
- (prev) => prev && prev.left === next.left && prev.top === next.top && prev.bottom === next.bottom ? prev : next
114
- );
115
- };
116
- update();
117
- window.addEventListener("resize", update);
118
- window.addEventListener("scroll", update, true);
119
- return () => {
120
- window.removeEventListener("resize", update);
121
- window.removeEventListener("scroll", update, true);
122
- };
123
- }, [isOpen, portal, placement, anchorRef]);
124
- useLayoutEffect(() => {
125
- if (portal) return;
126
- if (!isOpen || align !== "auto") {
127
- if (!isOpen) setResolvedAlign("start");
128
- return;
129
- }
130
- const panel = panelRef.current;
131
- if (!panel) return;
132
- panel.style.left = "0";
133
- panel.style.right = "auto";
134
- const rect = panel.getBoundingClientRect();
135
- if (rect.right > window.innerWidth) {
136
- setResolvedAlign("end");
137
- } else {
138
- setResolvedAlign("start");
139
- }
140
- panel.style.left = "";
141
- panel.style.right = "";
142
- }, [isOpen, align]);
143
- useStackedEscape(onClose, { enabled: isOpen });
144
- useEffect3(() => {
145
- if (!isOpen) return;
146
- function onMouseDown(e) {
147
- const target = e.target;
148
- if (panelRef.current?.contains(target)) return;
149
- if (anchorRef.current?.contains(target)) return;
150
- if (target instanceof Element && target.closest("[data-modal-layer]")) return;
151
- onClose();
152
- }
153
- document.addEventListener("mousedown", onMouseDown);
154
- return () => {
155
- document.removeEventListener("mousedown", onMouseDown);
156
- };
157
- }, [isOpen, onClose, anchorRef]);
158
- if (!isOpen) return null;
159
- const effectiveAlign = align === "auto" ? resolvedAlign : align;
160
- if (portal) {
161
- if (!fixedPos) return null;
162
- return createPortal(
163
- /* @__PURE__ */ jsx2(
164
- "div",
165
- {
166
- ref: panelRef,
167
- role: "dialog",
168
- "aria-modal": "false",
169
- style: {
170
- position: "fixed",
171
- left: `${fixedPos.left}px`,
172
- ...fixedPos.top !== void 0 ? { top: `${fixedPos.top}px` } : {},
173
- ...fixedPos.bottom !== void 0 ? { bottom: `${fixedPos.bottom}px` } : {}
174
- },
175
- className: cn("z-50 rounded-md border border-base-200 bg-base shadow-lg", className),
176
- children
177
- }
178
- ),
179
- document.body
180
- );
181
- }
182
- return /* @__PURE__ */ jsx2(
183
- "div",
184
- {
185
- ref: panelRef,
186
- role: "dialog",
187
- "aria-modal": "false",
188
- className: cn(
189
- "absolute top-full z-50 mt-1 rounded-md border border-base-200 bg-base shadow-lg",
190
- effectiveAlign === "end" ? "right-0" : "left-0",
191
- className
192
- ),
193
- children
194
- }
195
- );
196
- }
197
-
198
- // src/components/shared/PopoverItem.tsx
199
- import { forwardRef } from "react";
200
- import { jsx as jsx3 } from "react/jsx-runtime";
201
- var PopoverItem = forwardRef(
202
- function PopoverItem2({ className, children, ...rest }, ref) {
203
- return /* @__PURE__ */ jsx3(
204
- "button",
205
- {
206
- ref,
207
- type: "button",
208
- className: cn(
209
- "flex w-full cursor-pointer items-center gap-3 px-3 py-1.5 text-left text-xs hover:bg-base-accent",
210
- className
211
- ),
212
- ...rest,
213
- children
214
- }
215
- );
216
- }
217
- );
218
-
219
- export {
220
- Tooltip,
221
- Kbd,
222
- Popover,
223
- PopoverItem
224
- };
@@ -1,30 +0,0 @@
1
- // src/lib/timestamp.ts
2
- function formatTimestamp(iso) {
3
- const date = new Date(iso);
4
- const now = /* @__PURE__ */ new Date();
5
- const diffMs = now.getTime() - date.getTime();
6
- const diffMinutes = Math.floor(diffMs / 6e4);
7
- const diffHours = Math.floor(diffMs / 36e5);
8
- const sameDay = date.getUTCFullYear() === now.getUTCFullYear() && date.getUTCMonth() === now.getUTCMonth() && date.getUTCDate() === now.getUTCDate();
9
- if (diffMinutes < 1) return "just now";
10
- if (diffMinutes < 60) {
11
- return `${diffMinutes} ${diffMinutes === 1 ? "minute" : "minutes"} ago`;
12
- }
13
- if (sameDay) {
14
- return `${diffHours} ${diffHours === 1 ? "hour" : "hours"} ago`;
15
- }
16
- return date.toLocaleDateString("en-US", {
17
- month: "short",
18
- day: "numeric",
19
- timeZone: "UTC"
20
- }) + " at " + date.toLocaleTimeString("en-US", {
21
- hour: "numeric",
22
- minute: "2-digit",
23
- hour12: true,
24
- timeZone: "UTC"
25
- });
26
- }
27
-
28
- export {
29
- formatTimestamp
30
- };
@@ -1,38 +0,0 @@
1
- // src/lib/sanitize.ts
2
- var purifierPromise = null;
3
- var purifier = null;
4
- if (typeof window !== "undefined") {
5
- purifierPromise = import("dompurify").then((mod) => {
6
- const DOMPurify = mod.default ?? mod;
7
- purifier = (html) => DOMPurify.sanitize(html);
8
- return mod;
9
- });
10
- }
11
- var sanitizeCache = /* @__PURE__ */ new Map();
12
- var SANITIZE_CACHE_LIMIT = 500;
13
- function sanitizeHtml(html) {
14
- if (!html) return "";
15
- if (!purifier) return html;
16
- const cached = sanitizeCache.get(html);
17
- if (cached !== void 0) return cached;
18
- const clean = purifier(html);
19
- if (sanitizeCache.size >= SANITIZE_CACHE_LIMIT) {
20
- const oldest = sanitizeCache.keys().next().value;
21
- if (oldest !== void 0) sanitizeCache.delete(oldest);
22
- }
23
- sanitizeCache.set(html, clean);
24
- return clean;
25
- }
26
- function isSanitizerReady() {
27
- return typeof window === "undefined" || purifier !== null;
28
- }
29
- async function ensureSanitizer() {
30
- if (typeof window === "undefined") return;
31
- if (!purifier && purifierPromise) await purifierPromise;
32
- }
33
-
34
- export {
35
- sanitizeHtml,
36
- isSanitizerReady,
37
- ensureSanitizer
38
- };