@burdenoff/microfe-theculturepost 2026.704.2 → 2026.705.1

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 (89) hide show
  1. package/dist/theculturepost/TheCulturePostRoot.js +63 -45
  2. package/dist/theculturepost/TheCulturePostRoot.js.map +1 -1
  3. package/dist/theculturepost/TheCulturePostRoutes.js +17 -9
  4. package/dist/theculturepost/TheCulturePostRoutes.js.map +1 -1
  5. package/dist/theculturepost/components/AddCitationDialog.js +131 -102
  6. package/dist/theculturepost/components/AddCitationDialog.js.map +1 -1
  7. package/dist/theculturepost/components/ArchiveItemCard.js +56 -43
  8. package/dist/theculturepost/components/ArchiveItemCard.js.map +1 -1
  9. package/dist/theculturepost/components/AudioPlayer.js +74 -0
  10. package/dist/theculturepost/components/AudioPlayer.js.map +1 -0
  11. package/dist/theculturepost/components/CitationList.js +215 -105
  12. package/dist/theculturepost/components/CitationList.js.map +1 -1
  13. package/dist/theculturepost/components/CollectionCard.js +32 -32
  14. package/dist/theculturepost/components/CollectionCard.js.map +1 -1
  15. package/dist/theculturepost/components/CreateArchiveItemDialog.js +133 -93
  16. package/dist/theculturepost/components/CreateArchiveItemDialog.js.map +1 -1
  17. package/dist/theculturepost/components/CreateCollectionDialog.js +91 -70
  18. package/dist/theculturepost/components/CreateCollectionDialog.js.map +1 -1
  19. package/dist/theculturepost/components/CreateStoryDialog.js +311 -132
  20. package/dist/theculturepost/components/CreateStoryDialog.js.map +1 -1
  21. package/dist/theculturepost/components/DecorativeCover.js +78 -0
  22. package/dist/theculturepost/components/DecorativeCover.js.map +1 -0
  23. package/dist/theculturepost/components/DecorativeDivider.js +45 -0
  24. package/dist/theculturepost/components/DecorativeDivider.js.map +1 -0
  25. package/dist/theculturepost/components/DiscussionCard.js +75 -60
  26. package/dist/theculturepost/components/DiscussionCard.js.map +1 -1
  27. package/dist/theculturepost/components/HistoryTimeline.js +115 -0
  28. package/dist/theculturepost/components/HistoryTimeline.js.map +1 -0
  29. package/dist/theculturepost/components/LifecycleStepper.js +33 -0
  30. package/dist/theculturepost/components/LifecycleStepper.js.map +1 -0
  31. package/dist/theculturepost/components/OpenDiscussionDialog.js +66 -56
  32. package/dist/theculturepost/components/OpenDiscussionDialog.js.map +1 -1
  33. package/dist/theculturepost/components/OralHistoryCard.js +6 -73
  34. package/dist/theculturepost/components/OverlayBadge.js +22 -0
  35. package/dist/theculturepost/components/OverlayBadge.js.map +1 -0
  36. package/dist/theculturepost/components/PageHero.js +62 -0
  37. package/dist/theculturepost/components/PageHero.js.map +1 -0
  38. package/dist/theculturepost/components/RecordOralHistoryDialog.js +306 -131
  39. package/dist/theculturepost/components/RecordOralHistoryDialog.js.map +1 -1
  40. package/dist/theculturepost/components/ReplyThread.js +268 -139
  41. package/dist/theculturepost/components/ReplyThread.js.map +1 -1
  42. package/dist/theculturepost/components/StatusBadge.js +9 -9
  43. package/dist/theculturepost/components/StatusBadge.js.map +1 -1
  44. package/dist/theculturepost/components/StoryCard.js +54 -49
  45. package/dist/theculturepost/components/StoryCard.js.map +1 -1
  46. package/dist/theculturepost/components/TopicCard.js +60 -41
  47. package/dist/theculturepost/components/TopicCard.js.map +1 -1
  48. package/dist/theculturepost/components/Waveform.js +31 -0
  49. package/dist/theculturepost/components/Waveform.js.map +1 -0
  50. package/dist/theculturepost/components/categoryMeta.js +20 -0
  51. package/dist/theculturepost/components/categoryMeta.js.map +1 -0
  52. package/dist/theculturepost/components/index.js +41 -0
  53. package/dist/theculturepost/components/viz/BarChart.js +53 -0
  54. package/dist/theculturepost/components/viz/BarChart.js.map +1 -0
  55. package/dist/theculturepost/components/viz/Donut.js +58 -0
  56. package/dist/theculturepost/components/viz/Donut.js.map +1 -0
  57. package/dist/theculturepost/components/viz/StatTile.js +35 -0
  58. package/dist/theculturepost/components/viz/StatTile.js.map +1 -0
  59. package/dist/theculturepost/components/viz/index.js +3 -0
  60. package/dist/theculturepost/pages/HomePage.js +247 -124
  61. package/dist/theculturepost/pages/HomePage.js.map +1 -1
  62. package/dist/theculturepost/pages/archive/ArchiveItemDetailPage.js +319 -127
  63. package/dist/theculturepost/pages/archive/ArchiveItemDetailPage.js.map +1 -1
  64. package/dist/theculturepost/pages/archive/ArchivePage.js +265 -180
  65. package/dist/theculturepost/pages/archive/ArchivePage.js.map +1 -1
  66. package/dist/theculturepost/pages/archive/CollectionDetailPage.js +158 -143
  67. package/dist/theculturepost/pages/archive/CollectionDetailPage.js.map +1 -1
  68. package/dist/theculturepost/pages/discussions/DiscussionDetailPage.js +155 -93
  69. package/dist/theculturepost/pages/discussions/DiscussionDetailPage.js.map +1 -1
  70. package/dist/theculturepost/pages/discussions/DiscussionsPage.js +16 -16
  71. package/dist/theculturepost/pages/discussions/DiscussionsPage.js.map +1 -1
  72. package/dist/theculturepost/pages/governance/GovernancePage.js +293 -0
  73. package/dist/theculturepost/pages/governance/GovernancePage.js.map +1 -0
  74. package/dist/theculturepost/pages/stories/StoriesPage.js +18 -18
  75. package/dist/theculturepost/pages/stories/StoriesPage.js.map +1 -1
  76. package/dist/theculturepost/pages/stories/StoryDetailPage.js +603 -285
  77. package/dist/theculturepost/pages/stories/StoryDetailPage.js.map +1 -1
  78. package/dist/theculturepost/pages/timeline/TimelinePage.js +162 -0
  79. package/dist/theculturepost/pages/timeline/TimelinePage.js.map +1 -0
  80. package/dist/theculturepost/pages/topics/TopicDetailPage.js +239 -163
  81. package/dist/theculturepost/pages/topics/TopicDetailPage.js.map +1 -1
  82. package/dist/theculturepost/pages/topics/TopicsPage.js +76 -74
  83. package/dist/theculturepost/pages/topics/TopicsPage.js.map +1 -1
  84. package/dist/theculturepost/styles/injectDisplayFont.js +11 -0
  85. package/dist/theculturepost/styles/injectDisplayFont.js.map +1 -0
  86. package/dist/theculturepost/utils/formatters.js +6 -1
  87. package/dist/theculturepost/utils/formatters.js.map +1 -1
  88. package/package.json +1 -1
  89. package/dist/theculturepost/components/OralHistoryCard.js.map +0 -1
@@ -3,122 +3,143 @@ import { useTcpCreateCollection as t } from "../hooks/useTcpApi.js";
3
3
  import "../hooks/index.js";
4
4
  import { slugify as n } from "../utils/slug.js";
5
5
  import { describeError as r, notify as i } from "../lib/toast.js";
6
- import { FileUploadField as a } from "./FileUploadField.js";
7
- import { useState as o } from "react";
8
- import { jsx as s, jsxs as c } from "react/jsx-runtime";
9
- import { Button as l, Input as u, Label as d, ResponsiveDialog as f, ResponsiveDialogContent as p, ResponsiveDialogDescription as m, ResponsiveDialogFooter as h, ResponsiveDialogHeader as g, ResponsiveDialogTitle as _, Textarea as v } from "@burdenoff/fe-libs/ui";
6
+ import { Counter as a, MediaDropzone as o } from "./RecordOralHistoryDialog.js";
7
+ import { useState as s } from "react";
8
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
9
+ import { Button as u, Input as d, Label as f, ResponsiveDialog as p, ResponsiveDialogContent as m, ResponsiveDialogDescription as h, ResponsiveDialogFooter as g, ResponsiveDialogHeader as _, ResponsiveDialogTitle as v, Textarea as y } from "@burdenoff/fe-libs/ui";
10
10
  //#region src/theculturepost/components/CreateCollectionDialog.tsx
11
- function y({ open: y, onOpenChange: b, onCreated: x }) {
12
- let S = t(), [C, w] = o(""), [T, E] = o(""), [D, O] = o(!1), [k, A] = o(""), [j, M] = o(""), [N, P] = o(null), [F, I] = o(null), L = D ? T : n(C), R = () => {
13
- w(""), E(""), O(!1), A(""), M(""), P(null), I(null);
11
+ var b = 160, x = 120, S = 600;
12
+ function C({ open: C, onOpenChange: w, onCreated: T }) {
13
+ let E = t(), [D, O] = s(""), [k, A] = s(""), [j, M] = s(!1), [N, P] = s(""), [F, I] = s(""), [L, R] = s(null), [z, B] = s(null), V = j ? k : n(D), H = () => {
14
+ O(""), A(""), M(!1), P(""), I(""), R(null), B(null);
14
15
  };
15
- return /* @__PURE__ */ s(f, {
16
- open: y,
17
- onOpenChange: b,
18
- children: /* @__PURE__ */ c(p, {
16
+ return /* @__PURE__ */ c(p, {
17
+ open: C,
18
+ onOpenChange: w,
19
+ children: /* @__PURE__ */ l(m, {
19
20
  className: "sm:max-w-lg",
20
21
  children: [
21
- /* @__PURE__ */ c(g, { children: [/* @__PURE__ */ s(_, { children: "Create a collection" }), /* @__PURE__ */ s(m, { children: "Collections group artifacts and oral histories around a shared theme or tradition." })] }),
22
- /* @__PURE__ */ c("div", {
23
- className: "flex max-h-[60vh] flex-col gap-4 overflow-y-auto py-2",
22
+ /* @__PURE__ */ l(_, { children: [/* @__PURE__ */ c(v, { children: "Create a collection" }), /* @__PURE__ */ c(h, { children: "Collections group artifacts and oral histories around a shared theme or tradition." })] }),
23
+ /* @__PURE__ */ l("div", {
24
+ className: "flex max-h-[62vh] flex-col gap-4 overflow-y-auto py-2",
24
25
  children: [
25
- /* @__PURE__ */ c("div", {
26
+ /* @__PURE__ */ l("div", {
26
27
  className: "grid gap-1.5",
27
- children: [/* @__PURE__ */ s(d, { children: "Cover image" }), /* @__PURE__ */ s(a, {
28
+ children: [/* @__PURE__ */ c(f, { children: "Cover image" }), /* @__PURE__ */ c(o, {
28
29
  folder: e.covers,
29
30
  accept: "image/*",
30
- label: "Upload cover",
31
+ promptLabel: "Drag and drop a cover image here",
31
32
  hint: "PNG or JPG, up to 25 MB.",
32
- fileId: N,
33
- onUploaded: P,
34
- onCleared: () => P(null)
33
+ value: L,
34
+ onUploaded: (e) => R(e),
35
+ onClear: () => R(null)
35
36
  })]
36
37
  }),
37
- /* @__PURE__ */ c("div", {
38
+ /* @__PURE__ */ l("div", {
38
39
  className: "grid gap-1.5",
39
- children: [/* @__PURE__ */ s(d, {
40
- htmlFor: "collection-name",
41
- children: "Name"
42
- }), /* @__PURE__ */ s(u, {
43
- id: "collection-name",
44
- value: C,
45
- onChange: (e) => w(e.target.value),
46
- placeholder: "e.g. Temple Manuscripts of the Kaveri Delta"
47
- })]
40
+ children: [
41
+ /* @__PURE__ */ l(f, {
42
+ htmlFor: "collection-name",
43
+ children: ["Name ", /* @__PURE__ */ c("span", {
44
+ className: "text-status-error-text",
45
+ children: "*"
46
+ })]
47
+ }),
48
+ /* @__PURE__ */ c(d, {
49
+ id: "collection-name",
50
+ value: D,
51
+ maxLength: b,
52
+ onChange: (e) => O(e.target.value),
53
+ placeholder: "e.g. Temple Manuscripts of the Kaveri Delta"
54
+ }),
55
+ /* @__PURE__ */ c(a, {
56
+ length: D.length,
57
+ max: b
58
+ })
59
+ ]
48
60
  }),
49
- /* @__PURE__ */ c("div", {
61
+ /* @__PURE__ */ l("div", {
50
62
  className: "grid gap-1.5",
51
- children: [/* @__PURE__ */ s(d, {
63
+ children: [/* @__PURE__ */ c(f, {
52
64
  htmlFor: "collection-slug",
53
65
  children: "URL slug"
54
- }), /* @__PURE__ */ s(u, {
66
+ }), /* @__PURE__ */ c(d, {
55
67
  id: "collection-slug",
56
- value: L,
68
+ value: V,
57
69
  onChange: (e) => {
58
- O(!0), E(n(e.target.value));
70
+ M(!0), A(n(e.target.value));
59
71
  },
60
72
  placeholder: "temple-manuscripts-of-the-kaveri-delta"
61
73
  })]
62
74
  }),
63
- /* @__PURE__ */ c("div", {
75
+ /* @__PURE__ */ l("div", {
64
76
  className: "grid gap-1.5",
65
- children: [/* @__PURE__ */ s(d, {
77
+ children: [/* @__PURE__ */ c(f, {
66
78
  htmlFor: "collection-tradition",
67
79
  children: "Tradition"
68
- }), /* @__PURE__ */ s(u, {
80
+ }), /* @__PURE__ */ c(d, {
69
81
  id: "collection-tradition",
70
- value: k,
71
- onChange: (e) => A(e.target.value),
82
+ value: N,
83
+ maxLength: x,
84
+ onChange: (e) => P(e.target.value),
72
85
  placeholder: "e.g. Tamil Shaiva (optional)"
73
86
  })]
74
87
  }),
75
- /* @__PURE__ */ c("div", {
88
+ /* @__PURE__ */ l("div", {
76
89
  className: "grid gap-1.5",
77
- children: [/* @__PURE__ */ s(d, {
78
- htmlFor: "collection-desc",
79
- children: "Description"
80
- }), /* @__PURE__ */ s(v, {
81
- id: "collection-desc",
82
- value: j,
83
- onChange: (e) => M(e.target.value),
84
- placeholder: "What does this collection hold?",
85
- rows: 3
86
- })]
90
+ children: [
91
+ /* @__PURE__ */ c(f, {
92
+ htmlFor: "collection-desc",
93
+ children: "Description"
94
+ }),
95
+ /* @__PURE__ */ c(y, {
96
+ id: "collection-desc",
97
+ value: F,
98
+ maxLength: S,
99
+ onChange: (e) => I(e.target.value),
100
+ placeholder: "What does this collection hold?",
101
+ rows: 3
102
+ }),
103
+ /* @__PURE__ */ c(a, {
104
+ length: F.length,
105
+ max: S
106
+ })
107
+ ]
87
108
  }),
88
- F && /* @__PURE__ */ s("p", {
109
+ z && /* @__PURE__ */ c("p", {
89
110
  className: "text-sm text-status-error-text",
90
- children: F
111
+ children: z
91
112
  })
92
113
  ]
93
114
  }),
94
- /* @__PURE__ */ c(h, { children: [/* @__PURE__ */ s(l, {
115
+ /* @__PURE__ */ l(g, { children: [/* @__PURE__ */ c(u, {
95
116
  variant: "outline",
96
- onClick: () => b(!1),
117
+ onClick: () => w(!1),
97
118
  children: "Cancel"
98
- }), /* @__PURE__ */ s(l, {
119
+ }), /* @__PURE__ */ c(u, {
99
120
  onClick: async () => {
100
- if (!C.trim()) {
101
- I("A collection name is required.");
121
+ if (!D.trim()) {
122
+ B("A collection name is required.");
102
123
  return;
103
124
  }
104
- if (!L) {
105
- I("A URL slug is required.");
125
+ if (!V) {
126
+ B("A URL slug is required.");
106
127
  return;
107
128
  }
108
129
  try {
109
- let e = await S.mutateAsync({
110
- name: C.trim(),
111
- slug: L,
112
- tradition: k.trim() || null,
113
- description: j.trim() || null,
114
- coverFileId: N
130
+ let e = await E.mutateAsync({
131
+ name: D.trim(),
132
+ slug: V,
133
+ tradition: N.trim() || null,
134
+ description: F.trim() || null,
135
+ coverFileId: L?.id ?? null
115
136
  });
116
- i.success("Collection created", e.name), b(!1), R(), x?.(e);
137
+ i.success("Collection created", e.name), w(!1), H(), T?.(e);
117
138
  } catch (e) {
118
- I(r(e));
139
+ B(r(e));
119
140
  }
120
141
  },
121
- disabled: S.isPending,
142
+ disabled: E.isPending,
122
143
  children: "Create collection"
123
144
  })] })
124
145
  ]
@@ -126,6 +147,6 @@ function y({ open: y, onOpenChange: b, onCreated: x }) {
126
147
  });
127
148
  }
128
149
  //#endregion
129
- export { y as CreateCollectionDialog };
150
+ export { C as CreateCollectionDialog };
130
151
 
131
152
  //# sourceMappingURL=CreateCollectionDialog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CreateCollectionDialog.js","names":[],"sources":["../../../src/theculturepost/components/CreateCollectionDialog.tsx"],"sourcesContent":["/**\n * CreateCollectionDialog — start a new archive collection.\n * @module theculturepost/components\n *\n * Writes `tcpCreateCollection`. Slug auto-derives from the name (editable).\n */\n\nimport { useState } from 'react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { FileUploadField } from './FileUploadField';\nimport { useTcpCreateCollection, FILE_FOLDERS } from '../hooks';\nimport { slugify } from '../utils/slug';\nimport { notify, describeError } from '../lib/toast';\nimport type { TcpCollection } from '../types';\n\ninterface CreateCollectionDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onCreated?: (collection: TcpCollection) => void;\n}\n\nexport function CreateCollectionDialog({\n open,\n onOpenChange,\n onCreated,\n}: CreateCollectionDialogProps) {\n const createCollection = useTcpCreateCollection();\n const [name, setName] = useState('');\n const [slug, setSlug] = useState('');\n const [slugTouched, setSlugTouched] = useState(false);\n const [tradition, setTradition] = useState('');\n const [description, setDescription] = useState('');\n const [coverFileId, setCoverFileId] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const effectiveSlug = slugTouched ? slug : slugify(name);\n\n const reset = () => {\n setName('');\n setSlug('');\n setSlugTouched(false);\n setTradition('');\n setDescription('');\n setCoverFileId(null);\n setError(null);\n };\n\n const submit = async () => {\n if (!name.trim()) {\n setError('A collection name is required.');\n return;\n }\n if (!effectiveSlug) {\n setError('A URL slug is required.');\n return;\n }\n try {\n const created = await createCollection.mutateAsync({\n name: name.trim(),\n slug: effectiveSlug,\n tradition: tradition.trim() || null,\n description: description.trim() || null,\n coverFileId,\n });\n notify.success('Collection created', created.name);\n onOpenChange(false);\n reset();\n onCreated?.(created);\n } catch (err) {\n setError(describeError(err));\n }\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"sm:max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Create a collection</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Collections group artifacts and oral histories around a shared theme or tradition.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"flex max-h-[60vh] flex-col gap-4 overflow-y-auto py-2\">\n <div className=\"grid gap-1.5\">\n <Label>Cover image</Label>\n <FileUploadField\n folder={FILE_FOLDERS.covers}\n accept=\"image/*\"\n label=\"Upload cover\"\n hint=\"PNG or JPG, up to 25 MB.\"\n fileId={coverFileId}\n onUploaded={setCoverFileId}\n onCleared={() => setCoverFileId(null)}\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"collection-name\">Name</Label>\n <Input\n id=\"collection-name\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Temple Manuscripts of the Kaveri Delta\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"collection-slug\">URL slug</Label>\n <Input\n id=\"collection-slug\"\n value={effectiveSlug}\n onChange={(e) => {\n setSlugTouched(true);\n setSlug(slugify(e.target.value));\n }}\n placeholder=\"temple-manuscripts-of-the-kaveri-delta\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"collection-tradition\">Tradition</Label>\n <Input\n id=\"collection-tradition\"\n value={tradition}\n onChange={(e) => setTradition(e.target.value)}\n placeholder=\"e.g. Tamil Shaiva (optional)\"\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"collection-desc\">Description</Label>\n <Textarea\n id=\"collection-desc\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"What does this collection hold?\"\n rows={3}\n />\n </div>\n {error && <p className=\"text-sm text-status-error-text\">{error}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button onClick={submit} disabled={createCollection.isPending}>\n Create collection\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CreateCollectionDialog.js","names":[],"sources":["../../../src/theculturepost/components/CreateCollectionDialog.tsx"],"sourcesContent":["/**\n * CreateCollectionDialog — start a new archive collection.\n * @module theculturepost/components\n *\n * Writes `tcpCreateCollection`. The cover image is uploaded to wspace-files-svc\n * via the shared {@link MediaDropzone} (drag-drop). Slug auto-derives from the\n * name (editable).\n */\n\nimport { useState } from 'react';\nimport {\n Button,\n Input,\n Label,\n Textarea,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { MediaDropzone, Counter, type UploadedRef } from './RecordOralHistoryDialog';\nimport { useTcpCreateCollection, FILE_FOLDERS } from '../hooks';\nimport { slugify } from '../utils/slug';\nimport { notify, describeError } from '../lib/toast';\nimport type { TcpCollection } from '../types';\n\nconst NAME_MAX = 160;\nconst TRADITION_MAX = 120;\nconst DESCRIPTION_MAX = 600;\n\ninterface CreateCollectionDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onCreated?: (collection: TcpCollection) => void;\n}\n\nexport function CreateCollectionDialog({\n open,\n onOpenChange,\n onCreated,\n}: CreateCollectionDialogProps) {\n const createCollection = useTcpCreateCollection();\n const [name, setName] = useState('');\n const [slug, setSlug] = useState('');\n const [slugTouched, setSlugTouched] = useState(false);\n const [tradition, setTradition] = useState('');\n const [description, setDescription] = useState('');\n const [cover, setCover] = useState<UploadedRef | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const effectiveSlug = slugTouched ? slug : slugify(name);\n\n const reset = () => {\n setName('');\n setSlug('');\n setSlugTouched(false);\n setTradition('');\n setDescription('');\n setCover(null);\n setError(null);\n };\n\n const submit = async () => {\n if (!name.trim()) {\n setError('A collection name is required.');\n return;\n }\n if (!effectiveSlug) {\n setError('A URL slug is required.');\n return;\n }\n try {\n const created = await createCollection.mutateAsync({\n name: name.trim(),\n slug: effectiveSlug,\n tradition: tradition.trim() || null,\n description: description.trim() || null,\n coverFileId: cover?.id ?? null,\n });\n notify.success('Collection created', created.name);\n onOpenChange(false);\n reset();\n onCreated?.(created);\n } catch (err) {\n setError(describeError(err));\n }\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent className=\"sm:max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Create a collection</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Collections group artifacts and oral histories around a shared theme or tradition.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div className=\"flex max-h-[62vh] flex-col gap-4 overflow-y-auto py-2\">\n <div className=\"grid gap-1.5\">\n <Label>Cover image</Label>\n <MediaDropzone\n folder={FILE_FOLDERS.covers}\n accept=\"image/*\"\n promptLabel=\"Drag and drop a cover image here\"\n hint=\"PNG or JPG, up to 25 MB.\"\n value={cover}\n onUploaded={(ref) => setCover(ref)}\n onClear={() => setCover(null)}\n />\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"collection-name\">\n Name <span className=\"text-status-error-text\">*</span>\n </Label>\n <Input\n id=\"collection-name\"\n value={name}\n maxLength={NAME_MAX}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Temple Manuscripts of the Kaveri Delta\"\n />\n <Counter length={name.length} max={NAME_MAX} />\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"collection-slug\">URL slug</Label>\n <Input\n id=\"collection-slug\"\n value={effectiveSlug}\n onChange={(e) => {\n setSlugTouched(true);\n setSlug(slugify(e.target.value));\n }}\n placeholder=\"temple-manuscripts-of-the-kaveri-delta\"\n />\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"collection-tradition\">Tradition</Label>\n <Input\n id=\"collection-tradition\"\n value={tradition}\n maxLength={TRADITION_MAX}\n onChange={(e) => setTradition(e.target.value)}\n placeholder=\"e.g. Tamil Shaiva (optional)\"\n />\n </div>\n\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"collection-desc\">Description</Label>\n <Textarea\n id=\"collection-desc\"\n value={description}\n maxLength={DESCRIPTION_MAX}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"What does this collection hold?\"\n rows={3}\n />\n <Counter length={description.length} max={DESCRIPTION_MAX} />\n </div>\n\n {error && <p className=\"text-sm text-status-error-text\">{error}</p>}\n </div>\n\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button onClick={submit} disabled={createCollection.isPending}>\n Create collection\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}