@drawnagency/primitives 0.1.80 → 0.1.81

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 (102) hide show
  1. package/dist/{chunk-KVQFMVXE.js → chunk-DKXISNJ2.js} +2 -2
  2. package/dist/{chunk-RSITF24B.js → chunk-EVNEMJZ6.js} +9 -3
  3. package/dist/{chunk-VI26O4E3.js → chunk-FDBZZ4AT.js} +1 -1
  4. package/dist/{chunk-QB5Q23G2.js → chunk-FN4NKUZU.js} +1 -1
  5. package/dist/{chunk-EMGLZQCM.js → chunk-MBJUWOM2.js} +1 -1
  6. package/dist/{chunk-4TVODHD2.js → chunk-P4ZNHZMP.js} +6 -6
  7. package/dist/{chunk-UNUJPLZV.js → chunk-PJOHAWNV.js} +1 -1
  8. package/dist/{chunk-2DDWWTRX.js → chunk-Q6LZOH5M.js} +1 -1
  9. package/dist/chunk-WP5UX4MI.js +63 -0
  10. package/dist/{chunk-3LNKOLZP.js → chunk-YKOLOZB2.js} +1 -1
  11. package/dist/{chunk-7XWER6YR.js → chunk-ZEXR7JYQ.js} +3 -3
  12. package/dist/components/editor/PagesModal.d.ts +2 -0
  13. package/dist/components/editor/PagesModal.d.ts.map +1 -1
  14. package/dist/components/editor/index.js +6 -5
  15. package/dist/components/primitives/index.js +7 -6
  16. package/dist/components/sections/brand-guide.js +7 -6
  17. package/dist/components/sections/register-schemas.js +10 -9
  18. package/dist/components/sections/register.js +10 -9
  19. package/dist/components/shell/DocInspector.d.ts +17 -0
  20. package/dist/components/shell/DocInspector.d.ts.map +1 -0
  21. package/dist/components/shell/DocumentEditorOverlay.d.ts +29 -0
  22. package/dist/components/shell/DocumentEditorOverlay.d.ts.map +1 -0
  23. package/dist/components/shell/DocumentPresentOverlay.d.ts +30 -0
  24. package/dist/components/shell/DocumentPresentOverlay.d.ts.map +1 -0
  25. package/dist/components/shell/EditorShell.d.ts +31 -0
  26. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  27. package/dist/document/assets/fonts/albra-grotesk-bold.woff +0 -0
  28. package/dist/document/assets/fonts/albra-grotesk-regular.woff +0 -0
  29. package/dist/document/assets/fonts/kapra-neue-expanded-medium.woff +0 -0
  30. package/dist/document/assets/fonts/kapra-neue-expanded-regular.woff +0 -0
  31. package/dist/document/components/DocCoverPage.d.ts +11 -0
  32. package/dist/document/components/DocCoverPage.d.ts.map +1 -0
  33. package/dist/document/components/DocPage.d.ts +10 -0
  34. package/dist/document/components/DocPage.d.ts.map +1 -0
  35. package/dist/document/components/DocRail.d.ts +27 -0
  36. package/dist/document/components/DocRail.d.ts.map +1 -0
  37. package/dist/document/components/DocSectionPage.d.ts +12 -0
  38. package/dist/document/components/DocSectionPage.d.ts.map +1 -0
  39. package/dist/document/components/DocViewer.d.ts +18 -0
  40. package/dist/document/components/DocViewer.d.ts.map +1 -0
  41. package/dist/document/components/Wordmark.d.ts +4 -0
  42. package/dist/document/components/Wordmark.d.ts.map +1 -0
  43. package/dist/document/components/measure.d.ts +6 -0
  44. package/dist/document/components/measure.d.ts.map +1 -0
  45. package/dist/document/components/useDocPages.d.ts +12 -0
  46. package/dist/document/components/useDocPages.d.ts.map +1 -0
  47. package/dist/document/engine/blocks.d.ts +2 -0
  48. package/dist/document/engine/blocks.d.ts.map +1 -0
  49. package/dist/document/engine/harvest.d.ts +3 -0
  50. package/dist/document/engine/harvest.d.ts.map +1 -0
  51. package/dist/document/engine/masonry.d.ts +25 -0
  52. package/dist/document/engine/masonry.d.ts.map +1 -0
  53. package/dist/document/engine/paginate.d.ts +40 -0
  54. package/dist/document/engine/paginate.d.ts.map +1 -0
  55. package/dist/document/engine/settings.d.ts +70 -0
  56. package/dist/document/engine/settings.d.ts.map +1 -0
  57. package/dist/document/engine/types.d.ts +40 -0
  58. package/dist/document/engine/types.d.ts.map +1 -0
  59. package/dist/document/index.d.ts +13 -0
  60. package/dist/document/index.d.ts.map +1 -0
  61. package/dist/document/index.js +881 -0
  62. package/dist/document/styles/document.css +208 -0
  63. package/dist/index.js +29 -28
  64. package/dist/lib/document-input.d.ts +25 -0
  65. package/dist/lib/document-input.d.ts.map +1 -0
  66. package/dist/lib/index.js +10 -9
  67. package/dist/lib/pages.d.ts +2 -0
  68. package/dist/lib/pages.d.ts.map +1 -1
  69. package/dist/media/index.js +4 -3
  70. package/dist/schemas/index.js +3 -2
  71. package/dist/schemas/site-config.d.ts +223 -1
  72. package/dist/schemas/site-config.d.ts.map +1 -1
  73. package/package.json +5 -1
  74. package/src/components/editor/PagesModal.tsx +16 -2
  75. package/src/components/shell/DocInspector.tsx +278 -0
  76. package/src/components/shell/DocumentEditorOverlay.tsx +169 -0
  77. package/src/components/shell/DocumentPresentOverlay.tsx +87 -0
  78. package/src/components/shell/EditorShell.tsx +128 -5
  79. package/src/document/assets/fonts/albra-grotesk-bold.woff +0 -0
  80. package/src/document/assets/fonts/albra-grotesk-regular.woff +0 -0
  81. package/src/document/assets/fonts/kapra-neue-expanded-medium.woff +0 -0
  82. package/src/document/assets/fonts/kapra-neue-expanded-regular.woff +0 -0
  83. package/src/document/components/DocCoverPage.tsx +45 -0
  84. package/src/document/components/DocPage.tsx +40 -0
  85. package/src/document/components/DocRail.tsx +160 -0
  86. package/src/document/components/DocSectionPage.tsx +45 -0
  87. package/src/document/components/DocViewer.tsx +285 -0
  88. package/src/document/components/Wordmark.tsx +18 -0
  89. package/src/document/components/measure.tsx +105 -0
  90. package/src/document/components/useDocPages.ts +67 -0
  91. package/src/document/engine/blocks.ts +87 -0
  92. package/src/document/engine/harvest.ts +80 -0
  93. package/src/document/engine/masonry.ts +89 -0
  94. package/src/document/engine/paginate.ts +209 -0
  95. package/src/document/engine/settings.ts +77 -0
  96. package/src/document/engine/types.ts +54 -0
  97. package/src/document/index.ts +18 -0
  98. package/src/document/styles/document.css +208 -0
  99. package/src/lib/document-input.ts +57 -0
  100. package/src/lib/pages.ts +22 -0
  101. package/src/schemas/site-config.ts +22 -7
  102. /package/dist/{chunk-4YEOTFVU.js → chunk-YBVK254P.js} +0 -0
@@ -10,7 +10,7 @@ export declare const SectionMetaSchema: z.ZodObject<{
10
10
  access: z.ZodArray<z.ZodString>;
11
11
  }, z.core.$strip>;
12
12
  export type SectionMeta = z.infer<typeof SectionMetaSchema>;
13
- export declare const RESERVED_SLUGS: readonly ["edit", "api", "login", "set-password", "404"];
13
+ export declare const RESERVED_SLUGS: readonly ["edit", "api", "login", "set-password", "404", "present"];
14
14
  export declare const PageStatusSchema: z.ZodEnum<{
15
15
  live: "live";
16
16
  archived: "archived";
@@ -27,6 +27,46 @@ export declare const PageSchema: z.ZodObject<{
27
27
  }>;
28
28
  access: z.ZodArray<z.ZodString>;
29
29
  order: z.ZodArray<z.ZodString>;
30
+ document: z.ZodOptional<z.ZodObject<{
31
+ enabled: z.ZodDefault<z.ZodBoolean>;
32
+ meta: z.ZodDefault<z.ZodObject<{
33
+ client: z.ZodDefault<z.ZodString>;
34
+ project: z.ZodDefault<z.ZodString>;
35
+ dateLabel: z.ZodDefault<z.ZodString>;
36
+ }, z.core.$strip>>;
37
+ cover: z.ZodDefault<z.ZodObject<{
38
+ bgColor: z.ZodDefault<z.ZodString>;
39
+ accentColor: z.ZodDefault<z.ZodString>;
40
+ title: z.ZodDefault<z.ZodString>;
41
+ label: z.ZodDefault<z.ZodString>;
42
+ date: z.ZodDefault<z.ZodString>;
43
+ imageId: z.ZodDefault<z.ZodNullable<z.ZodString>>;
44
+ }, z.core.$strip>>;
45
+ sections: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
46
+ excluded: z.ZodDefault<z.ZodBoolean>;
47
+ textPlacement: z.ZodDefault<z.ZodEnum<{
48
+ top: "top";
49
+ leftColumn: "leftColumn";
50
+ }>>;
51
+ imagePlacement: z.ZodDefault<z.ZodEnum<{
52
+ fullWidth: "fullWidth";
53
+ right: "right";
54
+ }>>;
55
+ dropTextOverflow: z.ZodDefault<z.ZodBoolean>;
56
+ imageLayout: z.ZodDefault<z.ZodDiscriminatedUnion<[z.ZodObject<{
57
+ mode: z.ZodLiteral<"grid">;
58
+ rows: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<3>]>>;
59
+ columns: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<2>, z.ZodLiteral<3>, z.ZodLiteral<4>]>>;
60
+ }, z.core.$strip>, z.ZodObject<{
61
+ mode: z.ZodLiteral<"masonry">;
62
+ flow: z.ZodDefault<z.ZodEnum<{
63
+ rows: "rows";
64
+ columns: "columns";
65
+ }>>;
66
+ columns: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<2>, z.ZodLiteral<3>, z.ZodLiteral<4>, z.ZodLiteral<5>, z.ZodLiteral<6>]>>;
67
+ }, z.core.$strip>], "mode">>;
68
+ }, z.core.$strip>>>;
69
+ }, z.core.$strip>>;
30
70
  }, z.core.$strip>;
31
71
  export type Page = z.infer<typeof PageSchema>;
32
72
  declare const CanonicalIndexSchema: z.ZodObject<{
@@ -43,6 +83,46 @@ declare const CanonicalIndexSchema: z.ZodObject<{
43
83
  }>;
44
84
  access: z.ZodArray<z.ZodString>;
45
85
  order: z.ZodArray<z.ZodString>;
86
+ document: z.ZodOptional<z.ZodObject<{
87
+ enabled: z.ZodDefault<z.ZodBoolean>;
88
+ meta: z.ZodDefault<z.ZodObject<{
89
+ client: z.ZodDefault<z.ZodString>;
90
+ project: z.ZodDefault<z.ZodString>;
91
+ dateLabel: z.ZodDefault<z.ZodString>;
92
+ }, z.core.$strip>>;
93
+ cover: z.ZodDefault<z.ZodObject<{
94
+ bgColor: z.ZodDefault<z.ZodString>;
95
+ accentColor: z.ZodDefault<z.ZodString>;
96
+ title: z.ZodDefault<z.ZodString>;
97
+ label: z.ZodDefault<z.ZodString>;
98
+ date: z.ZodDefault<z.ZodString>;
99
+ imageId: z.ZodDefault<z.ZodNullable<z.ZodString>>;
100
+ }, z.core.$strip>>;
101
+ sections: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
102
+ excluded: z.ZodDefault<z.ZodBoolean>;
103
+ textPlacement: z.ZodDefault<z.ZodEnum<{
104
+ top: "top";
105
+ leftColumn: "leftColumn";
106
+ }>>;
107
+ imagePlacement: z.ZodDefault<z.ZodEnum<{
108
+ fullWidth: "fullWidth";
109
+ right: "right";
110
+ }>>;
111
+ dropTextOverflow: z.ZodDefault<z.ZodBoolean>;
112
+ imageLayout: z.ZodDefault<z.ZodDiscriminatedUnion<[z.ZodObject<{
113
+ mode: z.ZodLiteral<"grid">;
114
+ rows: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<3>]>>;
115
+ columns: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<2>, z.ZodLiteral<3>, z.ZodLiteral<4>]>>;
116
+ }, z.core.$strip>, z.ZodObject<{
117
+ mode: z.ZodLiteral<"masonry">;
118
+ flow: z.ZodDefault<z.ZodEnum<{
119
+ rows: "rows";
120
+ columns: "columns";
121
+ }>>;
122
+ columns: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<2>, z.ZodLiteral<3>, z.ZodLiteral<4>, z.ZodLiteral<5>, z.ZodLiteral<6>]>>;
123
+ }, z.core.$strip>], "mode">>;
124
+ }, z.core.$strip>>>;
125
+ }, z.core.$strip>>;
46
126
  }, z.core.$strip>>;
47
127
  sections: z.ZodRecord<z.ZodString, z.ZodObject<{
48
128
  type: z.ZodString;
@@ -71,6 +151,46 @@ export declare const IndexSchema: z.ZodPipe<z.ZodPipe<z.ZodObject<{
71
151
  }>;
72
152
  access: z.ZodArray<z.ZodString>;
73
153
  order: z.ZodArray<z.ZodString>;
154
+ document: z.ZodOptional<z.ZodObject<{
155
+ enabled: z.ZodDefault<z.ZodBoolean>;
156
+ meta: z.ZodDefault<z.ZodObject<{
157
+ client: z.ZodDefault<z.ZodString>;
158
+ project: z.ZodDefault<z.ZodString>;
159
+ dateLabel: z.ZodDefault<z.ZodString>;
160
+ }, z.core.$strip>>;
161
+ cover: z.ZodDefault<z.ZodObject<{
162
+ bgColor: z.ZodDefault<z.ZodString>;
163
+ accentColor: z.ZodDefault<z.ZodString>;
164
+ title: z.ZodDefault<z.ZodString>;
165
+ label: z.ZodDefault<z.ZodString>;
166
+ date: z.ZodDefault<z.ZodString>;
167
+ imageId: z.ZodDefault<z.ZodNullable<z.ZodString>>;
168
+ }, z.core.$strip>>;
169
+ sections: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
170
+ excluded: z.ZodDefault<z.ZodBoolean>;
171
+ textPlacement: z.ZodDefault<z.ZodEnum<{
172
+ top: "top";
173
+ leftColumn: "leftColumn";
174
+ }>>;
175
+ imagePlacement: z.ZodDefault<z.ZodEnum<{
176
+ fullWidth: "fullWidth";
177
+ right: "right";
178
+ }>>;
179
+ dropTextOverflow: z.ZodDefault<z.ZodBoolean>;
180
+ imageLayout: z.ZodDefault<z.ZodDiscriminatedUnion<[z.ZodObject<{
181
+ mode: z.ZodLiteral<"grid">;
182
+ rows: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<3>]>>;
183
+ columns: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<2>, z.ZodLiteral<3>, z.ZodLiteral<4>]>>;
184
+ }, z.core.$strip>, z.ZodObject<{
185
+ mode: z.ZodLiteral<"masonry">;
186
+ flow: z.ZodDefault<z.ZodEnum<{
187
+ rows: "rows";
188
+ columns: "columns";
189
+ }>>;
190
+ columns: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<2>, z.ZodLiteral<3>, z.ZodLiteral<4>, z.ZodLiteral<5>, z.ZodLiteral<6>]>>;
191
+ }, z.core.$strip>], "mode">>;
192
+ }, z.core.$strip>>>;
193
+ }, z.core.$strip>>;
74
194
  }, z.core.$strip>>>;
75
195
  sections: z.ZodRecord<z.ZodString, z.ZodObject<{
76
196
  type: z.ZodString;
@@ -94,6 +214,37 @@ export declare const IndexSchema: z.ZodPipe<z.ZodPipe<z.ZodObject<{
94
214
  status: "live" | "archived";
95
215
  access: string[];
96
216
  order: string[];
217
+ document?: {
218
+ enabled?: boolean | undefined;
219
+ meta?: {
220
+ client?: string | undefined;
221
+ project?: string | undefined;
222
+ dateLabel?: string | undefined;
223
+ } | undefined;
224
+ cover?: {
225
+ bgColor?: string | undefined;
226
+ accentColor?: string | undefined;
227
+ title?: string | undefined;
228
+ label?: string | undefined;
229
+ date?: string | undefined;
230
+ imageId?: string | null | undefined;
231
+ } | undefined;
232
+ sections?: Record<string, {
233
+ excluded?: boolean | undefined;
234
+ textPlacement?: "top" | "leftColumn" | undefined;
235
+ imagePlacement?: "fullWidth" | "right" | undefined;
236
+ dropTextOverflow?: boolean | undefined;
237
+ imageLayout?: {
238
+ mode: "grid";
239
+ rows?: 2 | 1 | 3 | undefined;
240
+ columns?: 2 | 4 | 3 | undefined;
241
+ } | {
242
+ mode: "masonry";
243
+ flow?: "rows" | "columns" | undefined;
244
+ columns?: 2 | 4 | 3 | 5 | 6 | undefined;
245
+ } | undefined;
246
+ }> | undefined;
247
+ } | undefined;
97
248
  }[];
98
249
  sections: Record<string, {
99
250
  type: string;
@@ -118,6 +269,37 @@ export declare const IndexSchema: z.ZodPipe<z.ZodPipe<z.ZodObject<{
118
269
  status: "live" | "archived";
119
270
  access: string[];
120
271
  order: string[];
272
+ document?: {
273
+ enabled: boolean;
274
+ meta: {
275
+ client: string;
276
+ project: string;
277
+ dateLabel: string;
278
+ };
279
+ cover: {
280
+ bgColor: string;
281
+ accentColor: string;
282
+ title: string;
283
+ label: string;
284
+ date: string;
285
+ imageId: string | null;
286
+ };
287
+ sections: Record<string, {
288
+ excluded: boolean;
289
+ textPlacement: "top" | "leftColumn";
290
+ imagePlacement: "fullWidth" | "right";
291
+ dropTextOverflow: boolean;
292
+ imageLayout: {
293
+ mode: "grid";
294
+ rows: 2 | 1 | 3;
295
+ columns: 2 | 4 | 3;
296
+ } | {
297
+ mode: "masonry";
298
+ flow: "rows" | "columns";
299
+ columns: 2 | 4 | 3 | 5 | 6;
300
+ };
301
+ }>;
302
+ } | undefined;
121
303
  }[] | undefined;
122
304
  lastModified?: string | null | undefined;
123
305
  }>>, z.ZodObject<{
@@ -134,6 +316,46 @@ export declare const IndexSchema: z.ZodPipe<z.ZodPipe<z.ZodObject<{
134
316
  }>;
135
317
  access: z.ZodArray<z.ZodString>;
136
318
  order: z.ZodArray<z.ZodString>;
319
+ document: z.ZodOptional<z.ZodObject<{
320
+ enabled: z.ZodDefault<z.ZodBoolean>;
321
+ meta: z.ZodDefault<z.ZodObject<{
322
+ client: z.ZodDefault<z.ZodString>;
323
+ project: z.ZodDefault<z.ZodString>;
324
+ dateLabel: z.ZodDefault<z.ZodString>;
325
+ }, z.core.$strip>>;
326
+ cover: z.ZodDefault<z.ZodObject<{
327
+ bgColor: z.ZodDefault<z.ZodString>;
328
+ accentColor: z.ZodDefault<z.ZodString>;
329
+ title: z.ZodDefault<z.ZodString>;
330
+ label: z.ZodDefault<z.ZodString>;
331
+ date: z.ZodDefault<z.ZodString>;
332
+ imageId: z.ZodDefault<z.ZodNullable<z.ZodString>>;
333
+ }, z.core.$strip>>;
334
+ sections: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
335
+ excluded: z.ZodDefault<z.ZodBoolean>;
336
+ textPlacement: z.ZodDefault<z.ZodEnum<{
337
+ top: "top";
338
+ leftColumn: "leftColumn";
339
+ }>>;
340
+ imagePlacement: z.ZodDefault<z.ZodEnum<{
341
+ fullWidth: "fullWidth";
342
+ right: "right";
343
+ }>>;
344
+ dropTextOverflow: z.ZodDefault<z.ZodBoolean>;
345
+ imageLayout: z.ZodDefault<z.ZodDiscriminatedUnion<[z.ZodObject<{
346
+ mode: z.ZodLiteral<"grid">;
347
+ rows: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<3>]>>;
348
+ columns: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<2>, z.ZodLiteral<3>, z.ZodLiteral<4>]>>;
349
+ }, z.core.$strip>, z.ZodObject<{
350
+ mode: z.ZodLiteral<"masonry">;
351
+ flow: z.ZodDefault<z.ZodEnum<{
352
+ rows: "rows";
353
+ columns: "columns";
354
+ }>>;
355
+ columns: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<2>, z.ZodLiteral<3>, z.ZodLiteral<4>, z.ZodLiteral<5>, z.ZodLiteral<6>]>>;
356
+ }, z.core.$strip>], "mode">>;
357
+ }, z.core.$strip>>>;
358
+ }, z.core.$strip>>;
137
359
  }, z.core.$strip>>;
138
360
  sections: z.ZodRecord<z.ZodString, z.ZodObject<{
139
361
  type: z.ZodString;
@@ -1 +1 @@
1
- {"version":3,"file":"site-config.d.ts","sourceRoot":"","sources":["../../src/schemas/site-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB,eAAO,MAAM,iBAAiB;;;;;;;;;iBAI5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAO5D,eAAO,MAAM,cAAc,0DAA2D,CAAC;AAEvF,eAAO,MAAM,gBAAgB;;;EAA+B,CAAC;AAE7D,eAAO,MAAM,UAAU;;;;;;;;;;;;iBASrB,CAAC;AAEH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AA0C9C,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6CtB,CAAC;AAEL,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAAyE,CAAC;AAElG,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAE7D,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,CAE1D;AAMD,eAAO,MAAM,iBAAiB;;;;;iBAM5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,mBAAmB;;;;;;;;;;;iBAwB5B,CAAC;AACL,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4B3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
1
+ {"version":3,"file":"site-config.d.ts","sourceRoot":"","sources":["../../src/schemas/site-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAaxB,eAAO,MAAM,iBAAiB;;;;;;;;;iBAI5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAQ5D,eAAO,MAAM,cAAc,qEAAsE,CAAC;AAWlG,eAAO,MAAM,gBAAgB;;;EAA+B,CAAC;AAE7D,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAUrB,CAAC;AAEH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AA0C9C,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6CtB,CAAC;AAEL,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAAyE,CAAC;AAElG,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAE7D,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,CAE1D;AAMD,eAAO,MAAM,iBAAiB;;;;;iBAM5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,mBAAmB;;;;;;;;;;;iBAwB5B,CAAC;AACL,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4B3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawnagency/primitives",
3
- "version": "0.1.80",
3
+ "version": "0.1.81",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./package.json": "./package.json",
@@ -84,6 +84,10 @@
84
84
  "types": "./dist/components/primitives/index.d.ts",
85
85
  "default": "./dist/components/primitives/index.js"
86
86
  },
87
+ "./document": {
88
+ "types": "./dist/document/index.d.ts",
89
+ "default": "./dist/document/index.js"
90
+ },
87
91
  "./auth": {
88
92
  "types": "./dist/auth/index.d.ts",
89
93
  "default": "./dist/auth/index.js"
@@ -2,6 +2,10 @@ import { useState, useEffect } from "react";
2
2
  import { Check } from "lucide-react";
3
3
  import type { SiteIndex, Page } from "../../schemas/site-config";
4
4
  import type { Audience } from "../../auth/types";
5
+ // Sanctioned outside->inside import: document/ is a sealed subtree, but the
6
+ // Document mode toggle needs the patch shape it edits (mirrors the same
7
+ // sanctioned import in schemas/site-config.ts and lib/pages.ts).
8
+ import type { DocumentOptions } from "../../document/engine/settings";
5
9
  import { Button } from "../shared/Button";
6
10
  import { Input } from "../shared/Input";
7
11
  import { Checkbox } from "../shared/Checkbox";
@@ -24,6 +28,7 @@ export interface PagesModalProps {
24
28
  onSetArchived: (pageId: string, archived: boolean) => void;
25
29
  onSetFields: (pageId: string, patch: Partial<Pick<Page, "title" | "slug" | "showInNav">>) => void;
26
30
  onSetAudience: (pageId: string, access: string[]) => void;
31
+ onSetDocument: (pageId: string, patch: Partial<DocumentOptions>) => void;
27
32
  onConfirmDelete: (pageId: string) => void;
28
33
  }
29
34
 
@@ -71,6 +76,7 @@ export function PagesModal(props: PagesModalProps) {
71
76
  }}
72
77
  onSetFields={(patch) => props.onSetFields(page.id, patch)}
73
78
  onSetAudience={(access) => props.onSetAudience(page.id, access)}
79
+ onSetDocument={(patch) => props.onSetDocument(page.id, patch)}
74
80
  onRequestDelete={() =>
75
81
  page.order.length === 0 ? props.onConfirmDelete(page.id) : setDeletingId(page.id)
76
82
  }
@@ -105,14 +111,16 @@ export function PagesModal(props: PagesModalProps) {
105
111
  }
106
112
 
107
113
  function PageRow({
108
- page, audiences, expanded, isNew, otherSlugs, dragIndex, onReorder, onToggleExpand, onSetHome, onSetArchived, onSetFields, onSetAudience, onRequestDelete,
114
+ page, audiences, expanded, isNew, otherSlugs, dragIndex, onReorder, onToggleExpand, onSetHome, onSetArchived, onSetFields, onSetAudience, onSetDocument, onRequestDelete,
109
115
  }: {
110
116
  page: Page; audiences: Audience[]; expanded: boolean;
111
117
  isNew: boolean; otherSlugs: string[];
112
118
  dragIndex?: number; onReorder: (fromIndex: number, toIndex: number) => void;
113
119
  onToggleExpand: () => void; onSetHome: () => void; onSetArchived: (v: boolean) => void;
114
120
  onSetFields: (patch: Partial<Pick<Page, "title" | "slug" | "showInNav">>) => void;
115
- onSetAudience: (access: string[]) => void; onRequestDelete: () => void;
121
+ onSetAudience: (access: string[]) => void;
122
+ onSetDocument: (patch: Partial<DocumentOptions>) => void;
123
+ onRequestDelete: () => void;
116
124
  }) {
117
125
  const draggable = dragIndex !== undefined;
118
126
  const { rowRef, handleRef, isDragging, closestEdge } = useSortableRow<HTMLDivElement, HTMLButtonElement>({
@@ -264,6 +272,12 @@ function PageRow({
264
272
  className="shrink-0"
265
273
  />
266
274
  </div>
275
+ <Checkbox
276
+ label="Document mode"
277
+ description="Adds a presentation view of this page."
278
+ checked={page.document?.enabled ?? false}
279
+ onChange={(enabled) => onSetDocument({ enabled })}
280
+ />
267
281
  <div className="flex items-center gap-2">
268
282
  <Button
269
283
  variant="secondary"
@@ -0,0 +1,278 @@
1
+ import { settingsFor, type DocumentOptions } from "../../document";
2
+ import { Input } from "../shared/Input";
3
+ import { Select } from "../shared/Select";
4
+ import { Checkbox } from "../shared/Checkbox";
5
+ import { RadioGroup } from "../shared/RadioGroup";
6
+ import { ColorPicker } from "../shared/ColorPicker";
7
+ import { FormLabel } from "../shared/FormLabel";
8
+ import { useMediaLibrary } from "./MediaLibraryContext";
9
+ import { Button } from "../shared/Button";
10
+ import type { MediaItem } from "../../media/types";
11
+
12
+ // Smallest generated variant for the inspector thumbnail (same file naming as
13
+ // docImagesFrom in lib/document-input.ts); null when the item can't render.
14
+ function thumbSrc(imageId: string, item: MediaItem | undefined): string | null {
15
+ if (!item || item.kind !== "image") return null;
16
+ if (item.mimeType === "image/svg+xml") return `/api/media/${imageId}/original.svg`;
17
+ const widths = item.variants.map((v) => v.width).sort((a, b) => a - b);
18
+ if (widths.length === 0) return null;
19
+ return `/api/media/${imageId}/${widths[0]}.webp`;
20
+ }
21
+
22
+ export interface DocInspectorProps {
23
+ document: DocumentOptions;
24
+ selection: { kind: "cover" } | { kind: "chunk"; chunkId: string; title: string };
25
+ warnings: string[]; // warningsByChunk for the selected chunk
26
+ onUpdateCover: (patch: Partial<DocumentOptions["cover"]>) => void;
27
+ onUpdateMeta: (patch: Partial<DocumentOptions["meta"]>) => void;
28
+ // Caller merges the patch via sectionSettingsSchema.parse.
29
+ onUpdateSection: (chunkId: string, patch: Record<string, unknown>) => void;
30
+ }
31
+
32
+ // Drawn palette — mirrors the swatch row in the harness inspector.
33
+ const SWATCHES = [
34
+ "#FFFFFF", "#EBEBEB", "#999999", "#333333", "#1F1F1F", // neutrals: white → near-black
35
+ "#009FAD", // teal (brand primary)
36
+ "#3D7F7F", // forest
37
+ "#099A6F", // green
38
+ "#5F81AB", // blue
39
+ "#7C97BB", // sky
40
+ "#6864A0", // violet
41
+ "#D3A978", // beige
42
+ "#EB9500", // gold
43
+ "#F07C00", // orange
44
+ "#A24E16", // brown / rust
45
+ "#A65982", // indigo
46
+ "#E64165", // pink
47
+ ];
48
+
49
+ function ColorControl({ label, value, onPick }: { label: string; value: string; onPick: (v: string) => void }) {
50
+ return (
51
+ <div className="mb-4">
52
+ <FormLabel>{label}</FormLabel>
53
+ <div className="flex flex-wrap items-center gap-1">
54
+ {SWATCHES.map((s) => (
55
+ <button
56
+ key={s}
57
+ type="button"
58
+ aria-label={s}
59
+ onClick={() => onPick(s)}
60
+ style={{ background: s }}
61
+ className={`h-6 w-6 rounded border ${s === value ? "border-primary ring-1 ring-primary" : "border-base-200"}`}
62
+ />
63
+ ))}
64
+ <ColorPicker value={value} onChange={onPick} label="Custom color" className="h-6 w-6" />
65
+ </div>
66
+ </div>
67
+ );
68
+ }
69
+
70
+ export function DocInspector({
71
+ document: doc,
72
+ selection,
73
+ warnings,
74
+ onUpdateCover,
75
+ onUpdateMeta,
76
+ onUpdateSection,
77
+ }: DocInspectorProps) {
78
+ return (
79
+ <aside data-testid="doc-inspector" className="w-64 shrink-0 overflow-y-auto border-l border-base-200 bg-base p-4">
80
+ {selection.kind === "cover" ? (
81
+ <CoverPanel doc={doc} onUpdateCover={onUpdateCover} onUpdateMeta={onUpdateMeta} />
82
+ ) : (
83
+ <ChunkPanel
84
+ key={selection.chunkId}
85
+ chunkId={selection.chunkId}
86
+ title={selection.title}
87
+ doc={doc}
88
+ warnings={warnings}
89
+ onUpdateSection={onUpdateSection}
90
+ />
91
+ )}
92
+ </aside>
93
+ );
94
+ }
95
+
96
+ function CoverPanel({
97
+ doc,
98
+ onUpdateCover,
99
+ onUpdateMeta,
100
+ }: {
101
+ doc: DocumentOptions;
102
+ onUpdateCover: (patch: Partial<DocumentOptions["cover"]>) => void;
103
+ onUpdateMeta: (patch: Partial<DocumentOptions["meta"]>) => void;
104
+ }) {
105
+ const { cover, meta } = doc;
106
+ const media = useMediaLibrary();
107
+ return (
108
+ <>
109
+ <h2 className="mb-2 text-xs font-semibold uppercase tracking-wide text-base-contrast-light">Cover</h2>
110
+ <Input label="Title" value={cover.title} onChange={(title) => onUpdateCover({ title })} className="mb-2" />
111
+ <Input label="Label" value={cover.label} onChange={(label) => onUpdateCover({ label })} className="mb-2" />
112
+ <Input label="Date" value={cover.date} onChange={(date) => onUpdateCover({ date })} className="mb-2" />
113
+
114
+ {media ? (
115
+ <div className="mb-4">
116
+ <FormLabel>Cover image</FormLabel>
117
+ {cover.imageId ? (
118
+ (() => {
119
+ const src = thumbSrc(cover.imageId, media.manifest.images[cover.imageId]);
120
+ return src ? (
121
+ <img src={src} alt="Cover image preview" className="mb-2 max-h-24 rounded border border-base-200" />
122
+ ) : null;
123
+ })()
124
+ ) : null}
125
+ <div className="flex gap-2">
126
+ <Button
127
+ variant="secondary"
128
+ size="sm"
129
+ onClick={() => media.openSelectModal((imageId) => onUpdateCover({ imageId }))}
130
+ >
131
+ {cover.imageId ? "Replace image" : "Choose image"}
132
+ </Button>
133
+ {cover.imageId ? (
134
+ <Button variant="ghost" size="sm" onClick={() => onUpdateCover({ imageId: null })}>
135
+ Remove image
136
+ </Button>
137
+ ) : null}
138
+ </div>
139
+ </div>
140
+ ) : null}
141
+
142
+ <ColorControl label="Background" value={cover.bgColor} onPick={(bgColor) => onUpdateCover({ bgColor })} />
143
+ <ColorControl label="Accent" value={cover.accentColor} onPick={(accentColor) => onUpdateCover({ accentColor })} />
144
+
145
+ <h2 className="mb-2 mt-6 text-xs font-semibold uppercase tracking-wide text-base-contrast-light">Document</h2>
146
+ <Input label="Client" value={meta.client} onChange={(client) => onUpdateMeta({ client })} className="mb-2" />
147
+ <Input label="Project" value={meta.project} onChange={(project) => onUpdateMeta({ project })} className="mb-2" />
148
+ <Input label="Date label" value={meta.dateLabel} onChange={(dateLabel) => onUpdateMeta({ dateLabel })} className="mb-2" />
149
+ </>
150
+ );
151
+ }
152
+
153
+ function ChunkPanel({
154
+ chunkId,
155
+ title,
156
+ doc,
157
+ warnings,
158
+ onUpdateSection,
159
+ }: {
160
+ chunkId: string;
161
+ title: string;
162
+ doc: DocumentOptions;
163
+ warnings: string[];
164
+ onUpdateSection: (chunkId: string, patch: Record<string, unknown>) => void;
165
+ }) {
166
+ const settings = settingsFor(doc.sections, chunkId);
167
+ const layout = settings.imageLayout;
168
+
169
+ return (
170
+ <>
171
+ <h2 className="mb-3 text-xs font-semibold uppercase tracking-wide text-base-contrast-light">{title}</h2>
172
+
173
+ <Checkbox
174
+ className="mb-4"
175
+ checked={!settings.excluded}
176
+ onChange={(checked) => onUpdateSection(chunkId, { excluded: !checked })}
177
+ label="Include in document"
178
+ />
179
+
180
+ {/* Image placement is linked, not independent (Drew, 2026-07-19): text
181
+ left → images right of the column, text top → images below full
182
+ width. One control drives both fields. */}
183
+ <RadioGroup
184
+ className="mb-4"
185
+ label="Text placement"
186
+ value={settings.textPlacement}
187
+ options={[
188
+ { label: "Top", value: "top" },
189
+ { label: "Left column", value: "leftColumn" },
190
+ ]}
191
+ onChange={(textPlacement) =>
192
+ onUpdateSection(chunkId, {
193
+ textPlacement,
194
+ imagePlacement: textPlacement === "leftColumn" ? "right" : "fullWidth",
195
+ })
196
+ }
197
+ />
198
+
199
+ <Checkbox
200
+ className="mb-4"
201
+ checked={settings.dropTextOverflow}
202
+ onChange={(dropTextOverflow) => onUpdateSection(chunkId, { dropTextOverflow })}
203
+ label="Drop text overflow"
204
+ />
205
+
206
+ <Select
207
+ className="mb-4"
208
+ label="Image layout"
209
+ value={layout.mode}
210
+ options={[
211
+ { value: "grid", label: "Grid" },
212
+ { value: "masonry", label: "Masonry" },
213
+ ]}
214
+ onChange={(v) =>
215
+ onUpdateSection(
216
+ chunkId,
217
+ v === "grid"
218
+ ? { imageLayout: { mode: "grid", rows: 2, columns: 4 } }
219
+ : { imageLayout: { mode: "masonry", flow: "rows", columns: 3 } },
220
+ )
221
+ }
222
+ />
223
+
224
+ {layout.mode === "grid" ? (
225
+ <>
226
+ <Select
227
+ className="mb-4"
228
+ label="Rows"
229
+ value={String(layout.rows)}
230
+ options={[1, 2, 3].map((n) => ({ value: String(n), label: String(n) }))}
231
+ onChange={(v) => onUpdateSection(chunkId, { imageLayout: { ...layout, rows: Number(v) } })}
232
+ />
233
+ <Select
234
+ className="mb-4"
235
+ label="Columns"
236
+ value={String(layout.columns)}
237
+ options={[2, 3, 4].map((n) => ({ value: String(n), label: String(n) }))}
238
+ onChange={(v) => onUpdateSection(chunkId, { imageLayout: { ...layout, columns: Number(v) } })}
239
+ />
240
+ </>
241
+ ) : (
242
+ <>
243
+ <Select
244
+ className="mb-4"
245
+ label="Flow"
246
+ value={layout.flow}
247
+ options={[
248
+ { value: "rows", label: "Rows" },
249
+ { value: "columns", label: "Columns" },
250
+ ]}
251
+ onChange={(v) => onUpdateSection(chunkId, { imageLayout: { ...layout, flow: v } })}
252
+ />
253
+ {/* Column count only drives the columns flow (layoutRows never reads
254
+ it) — hide it when irrelevant. */}
255
+ {layout.flow === "columns" ? (
256
+ <Select
257
+ className="mb-4"
258
+ label="Columns"
259
+ value={String(layout.columns)}
260
+ options={[2, 3, 4, 5, 6].map((n) => ({ value: String(n), label: String(n) }))}
261
+ onChange={(v) => onUpdateSection(chunkId, { imageLayout: { ...layout, columns: Number(v) } })}
262
+ />
263
+ ) : null}
264
+ </>
265
+ )}
266
+
267
+ {warnings.length > 0 ? (
268
+ <div className="mt-2">
269
+ {warnings.map((w, i) => (
270
+ <p key={i} className="mb-1 rounded border border-amber-300 bg-amber-50 px-2 py-1 text-xs text-amber-800">
271
+ {w}
272
+ </p>
273
+ ))}
274
+ </div>
275
+ ) : null}
276
+ </>
277
+ );
278
+ }