@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.
- package/dist/theculturepost/TheCulturePostRoot.js +63 -45
- package/dist/theculturepost/TheCulturePostRoot.js.map +1 -1
- package/dist/theculturepost/TheCulturePostRoutes.js +17 -9
- package/dist/theculturepost/TheCulturePostRoutes.js.map +1 -1
- package/dist/theculturepost/components/AddCitationDialog.js +131 -102
- package/dist/theculturepost/components/AddCitationDialog.js.map +1 -1
- package/dist/theculturepost/components/ArchiveItemCard.js +56 -43
- package/dist/theculturepost/components/ArchiveItemCard.js.map +1 -1
- package/dist/theculturepost/components/AudioPlayer.js +74 -0
- package/dist/theculturepost/components/AudioPlayer.js.map +1 -0
- package/dist/theculturepost/components/CitationList.js +215 -105
- package/dist/theculturepost/components/CitationList.js.map +1 -1
- package/dist/theculturepost/components/CollectionCard.js +32 -32
- package/dist/theculturepost/components/CollectionCard.js.map +1 -1
- package/dist/theculturepost/components/CreateArchiveItemDialog.js +133 -93
- package/dist/theculturepost/components/CreateArchiveItemDialog.js.map +1 -1
- package/dist/theculturepost/components/CreateCollectionDialog.js +91 -70
- package/dist/theculturepost/components/CreateCollectionDialog.js.map +1 -1
- package/dist/theculturepost/components/CreateStoryDialog.js +311 -132
- package/dist/theculturepost/components/CreateStoryDialog.js.map +1 -1
- package/dist/theculturepost/components/DecorativeCover.js +78 -0
- package/dist/theculturepost/components/DecorativeCover.js.map +1 -0
- package/dist/theculturepost/components/DecorativeDivider.js +45 -0
- package/dist/theculturepost/components/DecorativeDivider.js.map +1 -0
- package/dist/theculturepost/components/DiscussionCard.js +75 -60
- package/dist/theculturepost/components/DiscussionCard.js.map +1 -1
- package/dist/theculturepost/components/HistoryTimeline.js +115 -0
- package/dist/theculturepost/components/HistoryTimeline.js.map +1 -0
- package/dist/theculturepost/components/LifecycleStepper.js +33 -0
- package/dist/theculturepost/components/LifecycleStepper.js.map +1 -0
- package/dist/theculturepost/components/OpenDiscussionDialog.js +66 -56
- package/dist/theculturepost/components/OpenDiscussionDialog.js.map +1 -1
- package/dist/theculturepost/components/OralHistoryCard.js +6 -73
- package/dist/theculturepost/components/OverlayBadge.js +22 -0
- package/dist/theculturepost/components/OverlayBadge.js.map +1 -0
- package/dist/theculturepost/components/PageHero.js +62 -0
- package/dist/theculturepost/components/PageHero.js.map +1 -0
- package/dist/theculturepost/components/RecordOralHistoryDialog.js +306 -131
- package/dist/theculturepost/components/RecordOralHistoryDialog.js.map +1 -1
- package/dist/theculturepost/components/ReplyThread.js +268 -139
- package/dist/theculturepost/components/ReplyThread.js.map +1 -1
- package/dist/theculturepost/components/StatusBadge.js +9 -9
- package/dist/theculturepost/components/StatusBadge.js.map +1 -1
- package/dist/theculturepost/components/StoryCard.js +54 -49
- package/dist/theculturepost/components/StoryCard.js.map +1 -1
- package/dist/theculturepost/components/TopicCard.js +60 -41
- package/dist/theculturepost/components/TopicCard.js.map +1 -1
- package/dist/theculturepost/components/Waveform.js +31 -0
- package/dist/theculturepost/components/Waveform.js.map +1 -0
- package/dist/theculturepost/components/categoryMeta.js +20 -0
- package/dist/theculturepost/components/categoryMeta.js.map +1 -0
- package/dist/theculturepost/components/index.js +41 -0
- package/dist/theculturepost/components/viz/BarChart.js +53 -0
- package/dist/theculturepost/components/viz/BarChart.js.map +1 -0
- package/dist/theculturepost/components/viz/Donut.js +58 -0
- package/dist/theculturepost/components/viz/Donut.js.map +1 -0
- package/dist/theculturepost/components/viz/StatTile.js +35 -0
- package/dist/theculturepost/components/viz/StatTile.js.map +1 -0
- package/dist/theculturepost/components/viz/index.js +3 -0
- package/dist/theculturepost/pages/HomePage.js +247 -124
- package/dist/theculturepost/pages/HomePage.js.map +1 -1
- package/dist/theculturepost/pages/archive/ArchiveItemDetailPage.js +319 -127
- package/dist/theculturepost/pages/archive/ArchiveItemDetailPage.js.map +1 -1
- package/dist/theculturepost/pages/archive/ArchivePage.js +265 -180
- package/dist/theculturepost/pages/archive/ArchivePage.js.map +1 -1
- package/dist/theculturepost/pages/archive/CollectionDetailPage.js +158 -143
- package/dist/theculturepost/pages/archive/CollectionDetailPage.js.map +1 -1
- package/dist/theculturepost/pages/discussions/DiscussionDetailPage.js +155 -93
- package/dist/theculturepost/pages/discussions/DiscussionDetailPage.js.map +1 -1
- package/dist/theculturepost/pages/discussions/DiscussionsPage.js +16 -16
- package/dist/theculturepost/pages/discussions/DiscussionsPage.js.map +1 -1
- package/dist/theculturepost/pages/governance/GovernancePage.js +293 -0
- package/dist/theculturepost/pages/governance/GovernancePage.js.map +1 -0
- package/dist/theculturepost/pages/stories/StoriesPage.js +18 -18
- package/dist/theculturepost/pages/stories/StoriesPage.js.map +1 -1
- package/dist/theculturepost/pages/stories/StoryDetailPage.js +603 -285
- package/dist/theculturepost/pages/stories/StoryDetailPage.js.map +1 -1
- package/dist/theculturepost/pages/timeline/TimelinePage.js +162 -0
- package/dist/theculturepost/pages/timeline/TimelinePage.js.map +1 -0
- package/dist/theculturepost/pages/topics/TopicDetailPage.js +239 -163
- package/dist/theculturepost/pages/topics/TopicDetailPage.js.map +1 -1
- package/dist/theculturepost/pages/topics/TopicsPage.js +76 -74
- package/dist/theculturepost/pages/topics/TopicsPage.js.map +1 -1
- package/dist/theculturepost/styles/injectDisplayFont.js +11 -0
- package/dist/theculturepost/styles/injectDisplayFont.js.map +1 -0
- package/dist/theculturepost/utils/formatters.js +6 -1
- package/dist/theculturepost/utils/formatters.js.map +1 -1
- package/package.json +1 -1
- package/dist/theculturepost/components/OralHistoryCard.js.map +0 -1
|
@@ -1,129 +1,239 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { cn as e } from "../utils/cn.js";
|
|
2
|
+
import { ErrorView as t, LoadingView as n } from "./StateViews.js";
|
|
3
|
+
import { formatDate as r, formatEnumLabel as i } from "../utils/formatters.js";
|
|
4
|
+
import { StatusBadge as a } from "./StatusBadge.js";
|
|
5
|
+
import { EmptyState as o } from "./EmptyState.js";
|
|
6
|
+
import { useTcpCitations as s, useTcpVerifyCitation as c } from "../hooks/useTcpApi.js";
|
|
6
7
|
import "../hooks/index.js";
|
|
7
|
-
import { describeError as
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
8
|
+
import { describeError as l, notify as u } from "../lib/toast.js";
|
|
9
|
+
import { createElement as d } from "react";
|
|
10
|
+
import { AlertCircle as f, BookMarked as p, BookOpen as m, Box as h, CheckCircle2 as g, ExternalLink as _, FileText as v, Globe as y, GraduationCap as b, HelpCircle as x, Landmark as S, Mic as C, Newspaper as w, Quote as T, ShieldCheck as E, XCircle as D } from "lucide-react";
|
|
11
|
+
import { jsx as O, jsxs as k } from "react/jsx-runtime";
|
|
12
|
+
import { Spinner as A } from "@burdenoff/fe-libs/ui";
|
|
11
13
|
//#region src/theculturepost/components/CitationList.tsx
|
|
12
|
-
var
|
|
13
|
-
|
|
14
|
+
var j = {
|
|
15
|
+
ACADEMIC: b,
|
|
16
|
+
ARCHIVAL_RECORD: S,
|
|
17
|
+
ARTIFACT: h,
|
|
18
|
+
BOOK: m,
|
|
19
|
+
INTERVIEW: C,
|
|
20
|
+
PERIODICAL: w,
|
|
21
|
+
PRIMARY_DOCUMENT: v,
|
|
22
|
+
WEB: y
|
|
23
|
+
};
|
|
24
|
+
function M(e) {
|
|
25
|
+
return j[e] ?? v;
|
|
26
|
+
}
|
|
27
|
+
var N = {
|
|
28
|
+
CORROBORATED: {
|
|
29
|
+
icon: g,
|
|
30
|
+
accent: "success",
|
|
31
|
+
label: "Corroborated",
|
|
32
|
+
blurb: "Strong agreement among reliable sources."
|
|
33
|
+
},
|
|
34
|
+
DISPUTED: {
|
|
35
|
+
icon: f,
|
|
36
|
+
accent: "warning",
|
|
37
|
+
label: "Disputed",
|
|
38
|
+
blurb: "Conflicting or insufficient evidence."
|
|
39
|
+
},
|
|
40
|
+
RETRACTED: {
|
|
41
|
+
icon: D,
|
|
42
|
+
accent: "destructive",
|
|
43
|
+
label: "Retracted",
|
|
44
|
+
blurb: "The source has since been withdrawn."
|
|
45
|
+
},
|
|
46
|
+
UNVERIFIED: {
|
|
47
|
+
icon: x,
|
|
48
|
+
accent: "secondary",
|
|
49
|
+
label: "Unverified",
|
|
50
|
+
blurb: "Not yet reviewed by an editor."
|
|
51
|
+
}
|
|
52
|
+
}, P = [
|
|
14
53
|
"CORROBORATED",
|
|
15
54
|
"DISPUTED",
|
|
16
|
-
"RETRACTED"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
55
|
+
"RETRACTED",
|
|
56
|
+
"UNVERIFIED"
|
|
57
|
+
], F = {
|
|
58
|
+
success: "bg-status-success-bg-subtle text-status-success-text shadow-elevation-1",
|
|
59
|
+
warning: "bg-status-warning-bg-subtle text-status-warning-text shadow-elevation-1",
|
|
60
|
+
destructive: "bg-status-error-bg-subtle text-status-error-text shadow-elevation-1",
|
|
61
|
+
secondary: "bg-bg-sunken text-text-primary shadow-elevation-1"
|
|
62
|
+
};
|
|
63
|
+
function I({ value: t, onChange: n, pending: r = !1, compact: i = !1, className: a }) {
|
|
64
|
+
return /* @__PURE__ */ O("div", {
|
|
65
|
+
role: "radiogroup",
|
|
66
|
+
"aria-label": "Verification status",
|
|
67
|
+
className: e("grid grid-cols-2 gap-1 rounded-xl border border-border-seam bg-bg-surface p-1", i ? "grid-cols-4" : "sm:inline-grid sm:auto-cols-max sm:grid-flow-col", a),
|
|
68
|
+
children: P.map((a) => {
|
|
69
|
+
let o = N[a], s = o.icon, c = a === t;
|
|
70
|
+
return /* @__PURE__ */ k("button", {
|
|
71
|
+
type: "button",
|
|
72
|
+
role: "radio",
|
|
73
|
+
"aria-checked": c,
|
|
74
|
+
"aria-label": o.label,
|
|
75
|
+
title: o.label,
|
|
76
|
+
disabled: r,
|
|
77
|
+
onClick: () => n(a),
|
|
78
|
+
className: e("inline-flex min-h-9 items-center justify-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium transition-colors disabled:opacity-60", c ? F[o.accent] : "text-text-tertiary hover:bg-bg-sunken hover:text-text-primary"),
|
|
79
|
+
children: [/* @__PURE__ */ O(s, {
|
|
80
|
+
className: "h-3.5 w-3.5 shrink-0",
|
|
81
|
+
"aria-hidden": "true"
|
|
82
|
+
}), /* @__PURE__ */ O("span", {
|
|
83
|
+
className: i ? "sr-only" : "hidden sm:inline",
|
|
84
|
+
children: o.label
|
|
85
|
+
})]
|
|
86
|
+
}, a);
|
|
87
|
+
})
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function L({ citation: t, compact: n }) {
|
|
91
|
+
let o = c(), s = async (e) => {
|
|
92
|
+
if (e !== t.verification) try {
|
|
93
|
+
await o.mutateAsync({
|
|
94
|
+
id: t.id,
|
|
95
|
+
verification: e
|
|
96
|
+
}), u.success("Verification updated", i(e));
|
|
25
97
|
} catch (e) {
|
|
26
|
-
|
|
98
|
+
u.error("Could not update verification", l(e));
|
|
27
99
|
}
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
100
|
+
}, f = [
|
|
101
|
+
t.author,
|
|
102
|
+
t.publisher,
|
|
103
|
+
r(t.publishedOn)
|
|
32
104
|
].filter((e) => e && e !== "—").join(" · ");
|
|
33
|
-
return /* @__PURE__ */
|
|
34
|
-
className: "rounded-
|
|
35
|
-
children: [
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
children: [/* @__PURE__ */ m(i, { status: e.sourceType }), /* @__PURE__ */ m(i, { status: e.verification })]
|
|
44
|
-
}),
|
|
45
|
-
/* @__PURE__ */ m("p", {
|
|
46
|
-
className: "text-sm font-semibold text-text-primary",
|
|
47
|
-
children: e.title
|
|
48
|
-
}),
|
|
49
|
-
o && /* @__PURE__ */ m("p", {
|
|
50
|
-
className: "mt-0.5 text-xs text-text-tertiary",
|
|
51
|
-
children: o
|
|
52
|
-
})
|
|
53
|
-
]
|
|
54
|
-
}), e.url && /* @__PURE__ */ h("a", {
|
|
55
|
-
href: e.url,
|
|
56
|
-
target: "_blank",
|
|
57
|
-
rel: "noreferrer noopener",
|
|
58
|
-
className: "inline-flex shrink-0 items-center gap-1 text-xs font-medium text-accent hover:underline",
|
|
59
|
-
children: ["Source ", /* @__PURE__ */ m(d, { className: "h-3 w-3" })]
|
|
60
|
-
})]
|
|
61
|
-
}),
|
|
62
|
-
e.excerpt && /* @__PURE__ */ h("blockquote", {
|
|
63
|
-
className: "mt-3 flex gap-2 rounded-lg bg-bg-sunken/60 px-3 py-2 text-sm italic text-text-secondary",
|
|
64
|
-
children: [/* @__PURE__ */ m(f, {
|
|
65
|
-
className: "h-3.5 w-3.5 shrink-0 text-text-tertiary",
|
|
66
|
-
"aria-hidden": "true"
|
|
67
|
-
}), /* @__PURE__ */ m("span", {
|
|
68
|
-
className: "not-italic",
|
|
69
|
-
children: e.excerpt
|
|
70
|
-
})]
|
|
71
|
-
}),
|
|
72
|
-
e.provenance && /* @__PURE__ */ h("p", {
|
|
73
|
-
className: "mt-2 text-xs text-text-tertiary",
|
|
105
|
+
return /* @__PURE__ */ k("li", {
|
|
106
|
+
className: e("rounded-2xl border border-border-seam bg-bg-surface transition-colors hover:border-border-strong", n ? "p-3.5" : "p-4 sm:p-5"),
|
|
107
|
+
children: [/* @__PURE__ */ k("div", {
|
|
108
|
+
className: e("flex gap-3", n ? "items-start" : "sm:gap-4"),
|
|
109
|
+
children: [/* @__PURE__ */ O("span", {
|
|
110
|
+
className: e("grid shrink-0 place-items-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary", n ? "h-9 w-9" : "h-12 w-12"),
|
|
111
|
+
"aria-hidden": "true",
|
|
112
|
+
children: d(M(t.sourceType), { className: n ? "h-4 w-4" : "h-6 w-6" })
|
|
113
|
+
}), /* @__PURE__ */ k("div", {
|
|
114
|
+
className: "min-w-0 flex-1",
|
|
74
115
|
children: [
|
|
75
|
-
/* @__PURE__ */
|
|
76
|
-
className: "
|
|
77
|
-
children:
|
|
116
|
+
/* @__PURE__ */ k("div", {
|
|
117
|
+
className: "mb-1 flex flex-wrap items-center gap-1.5",
|
|
118
|
+
children: [/* @__PURE__ */ O(a, {
|
|
119
|
+
status: t.sourceType,
|
|
120
|
+
icon: d(M(t.sourceType), { className: "h-3 w-3" })
|
|
121
|
+
}), n && /* @__PURE__ */ O(a, { status: t.verification })]
|
|
122
|
+
}),
|
|
123
|
+
/* @__PURE__ */ O("p", {
|
|
124
|
+
className: e("font-display font-semibold leading-snug text-text-primary", n ? "text-sm" : "text-base"),
|
|
125
|
+
children: t.title
|
|
78
126
|
}),
|
|
79
|
-
|
|
80
|
-
|
|
127
|
+
f && /* @__PURE__ */ O("p", {
|
|
128
|
+
className: "mt-0.5 text-xs text-text-tertiary",
|
|
129
|
+
children: f
|
|
130
|
+
}),
|
|
131
|
+
t.excerpt && !n && /* @__PURE__ */ k("blockquote", {
|
|
132
|
+
className: "mt-3 flex gap-2 rounded-lg bg-bg-sunken/60 px-3 py-2 text-sm text-text-secondary",
|
|
133
|
+
children: [/* @__PURE__ */ O(T, {
|
|
134
|
+
className: "h-3.5 w-3.5 shrink-0 text-text-tertiary",
|
|
135
|
+
"aria-hidden": "true"
|
|
136
|
+
}), /* @__PURE__ */ O("span", { children: t.excerpt })]
|
|
137
|
+
}),
|
|
138
|
+
t.provenance && !n && /* @__PURE__ */ k("p", {
|
|
139
|
+
className: "mt-2 text-xs text-text-tertiary",
|
|
140
|
+
children: [
|
|
141
|
+
/* @__PURE__ */ O("span", {
|
|
142
|
+
className: "font-medium text-text-secondary",
|
|
143
|
+
children: "Provenance:"
|
|
144
|
+
}),
|
|
145
|
+
" ",
|
|
146
|
+
t.provenance
|
|
147
|
+
]
|
|
148
|
+
}),
|
|
149
|
+
t.url && /* @__PURE__ */ k("a", {
|
|
150
|
+
href: t.url,
|
|
151
|
+
target: "_blank",
|
|
152
|
+
rel: "noreferrer noopener",
|
|
153
|
+
className: "mt-2 inline-flex max-w-full items-center gap-1 text-xs font-medium text-accent hover:underline",
|
|
154
|
+
children: [/* @__PURE__ */ O("span", {
|
|
155
|
+
className: "truncate",
|
|
156
|
+
children: n ? "View source" : t.url
|
|
157
|
+
}), /* @__PURE__ */ O(_, {
|
|
158
|
+
className: "h-3 w-3 shrink-0",
|
|
159
|
+
"aria-hidden": "true"
|
|
160
|
+
})]
|
|
161
|
+
})
|
|
81
162
|
]
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
|
|
163
|
+
})]
|
|
164
|
+
}), /* @__PURE__ */ k("div", {
|
|
165
|
+
className: e("mt-3 flex flex-wrap items-center gap-x-3 gap-y-2 border-t border-border-seam pt-3", n ? "" : "sm:justify-between"),
|
|
166
|
+
children: [/* @__PURE__ */ k("span", {
|
|
167
|
+
className: "inline-flex items-center gap-1.5 text-xs font-medium text-text-secondary",
|
|
85
168
|
children: [
|
|
86
|
-
/* @__PURE__ */
|
|
87
|
-
className: "h-
|
|
169
|
+
/* @__PURE__ */ O(E, {
|
|
170
|
+
className: "h-3.5 w-3.5 text-text-tertiary",
|
|
88
171
|
"aria-hidden": "true"
|
|
89
172
|
}),
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
children: "Verification"
|
|
93
|
-
}),
|
|
94
|
-
/* @__PURE__ */ h(g, {
|
|
95
|
-
value: e.verification,
|
|
96
|
-
onValueChange: (e) => a(e),
|
|
97
|
-
children: [/* @__PURE__ */ m(y, {
|
|
98
|
-
className: "h-8 w-40",
|
|
99
|
-
"aria-label": "Change verification status",
|
|
100
|
-
children: /* @__PURE__ */ m(b, {})
|
|
101
|
-
}), /* @__PURE__ */ m(_, { children: S.map((e) => /* @__PURE__ */ m(v, {
|
|
102
|
-
value: e,
|
|
103
|
-
children: r(e)
|
|
104
|
-
}, e)) })]
|
|
105
|
-
}),
|
|
106
|
-
t.isPending && /* @__PURE__ */ m(x, { size: "sm" })
|
|
173
|
+
"Verification",
|
|
174
|
+
o.isPending && /* @__PURE__ */ O(A, { size: "sm" })
|
|
107
175
|
]
|
|
176
|
+
}), /* @__PURE__ */ O(I, {
|
|
177
|
+
value: t.verification,
|
|
178
|
+
onChange: s,
|
|
179
|
+
pending: o.isPending,
|
|
180
|
+
compact: n
|
|
181
|
+
})]
|
|
182
|
+
})]
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
function R() {
|
|
186
|
+
return /* @__PURE__ */ k("div", {
|
|
187
|
+
className: "mt-4 rounded-2xl border border-border-seam bg-bg-sunken/50 p-4 sm:p-5",
|
|
188
|
+
children: [/* @__PURE__ */ k("div", {
|
|
189
|
+
className: "flex items-start gap-3",
|
|
190
|
+
children: [/* @__PURE__ */ O("span", {
|
|
191
|
+
className: "grid h-9 w-9 shrink-0 place-items-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary",
|
|
192
|
+
"aria-hidden": "true",
|
|
193
|
+
children: /* @__PURE__ */ O(E, { className: "h-5 w-5" })
|
|
194
|
+
}), /* @__PURE__ */ O("p", {
|
|
195
|
+
className: "text-sm text-text-secondary",
|
|
196
|
+
children: "Every source is evaluated for accuracy, relevance, and cultural sensitivity through a transparent, multi-step review by editors and subject-area contributors."
|
|
197
|
+
})]
|
|
198
|
+
}), /* @__PURE__ */ O("dl", {
|
|
199
|
+
className: "mt-4 grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4",
|
|
200
|
+
children: P.map((t) => {
|
|
201
|
+
let n = N[t], r = n.icon;
|
|
202
|
+
return /* @__PURE__ */ k("div", {
|
|
203
|
+
className: "flex items-start gap-2",
|
|
204
|
+
children: [/* @__PURE__ */ O(r, {
|
|
205
|
+
className: e("mt-0.5 h-4 w-4 shrink-0", n.accent === "success" && "text-status-success-text", n.accent === "warning" && "text-status-warning-text", n.accent === "destructive" && "text-status-error-text", n.accent === "secondary" && "text-text-tertiary"),
|
|
206
|
+
"aria-hidden": "true"
|
|
207
|
+
}), /* @__PURE__ */ k("div", { children: [/* @__PURE__ */ O("dt", {
|
|
208
|
+
className: "text-xs font-semibold text-text-primary",
|
|
209
|
+
children: n.label
|
|
210
|
+
}), /* @__PURE__ */ O("dd", {
|
|
211
|
+
className: "mt-0.5 text-xs text-text-tertiary",
|
|
212
|
+
children: n.blurb
|
|
213
|
+
})] })]
|
|
214
|
+
}, t);
|
|
108
215
|
})
|
|
109
|
-
]
|
|
216
|
+
})]
|
|
110
217
|
});
|
|
111
218
|
}
|
|
112
|
-
function
|
|
113
|
-
let { data:
|
|
114
|
-
return
|
|
219
|
+
function z({ storyId: r, compact: i = !1 }) {
|
|
220
|
+
let { data: a, isLoading: c, isError: l, refetch: u } = s(r);
|
|
221
|
+
return c ? /* @__PURE__ */ O(n, { label: "Loading citations…" }) : l ? /* @__PURE__ */ O(t, {
|
|
115
222
|
message: "We couldn't load citations.",
|
|
116
|
-
onRetry: () =>
|
|
117
|
-
}) : !
|
|
118
|
-
icon: /* @__PURE__ */
|
|
223
|
+
onRetry: () => u()
|
|
224
|
+
}) : !a || a.length === 0 ? /* @__PURE__ */ O(o, {
|
|
225
|
+
icon: /* @__PURE__ */ O(p, { className: "h-9 w-9" }),
|
|
119
226
|
title: "No citations yet",
|
|
120
227
|
description: "Add verifiable sources to ground this story in the record."
|
|
121
|
-
}) : /* @__PURE__ */
|
|
122
|
-
className: "flex flex-col gap-3",
|
|
123
|
-
children:
|
|
124
|
-
|
|
228
|
+
}) : /* @__PURE__ */ k("div", { children: [/* @__PURE__ */ O("ul", {
|
|
229
|
+
className: e("flex flex-col", i ? "gap-3" : "gap-3 sm:gap-4"),
|
|
230
|
+
children: a.map((e) => /* @__PURE__ */ O(L, {
|
|
231
|
+
citation: e,
|
|
232
|
+
compact: i
|
|
233
|
+
}, e.id))
|
|
234
|
+
}), !i && /* @__PURE__ */ O(R, {})] });
|
|
125
235
|
}
|
|
126
236
|
//#endregion
|
|
127
|
-
export {
|
|
237
|
+
export { z as CitationList, P as VERIFICATIONS, N as VERIFICATION_META, M as sourceTypeIcon };
|
|
128
238
|
|
|
129
239
|
//# sourceMappingURL=CitationList.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CitationList.js","names":[],"sources":["../../../src/theculturepost/components/CitationList.tsx"],"sourcesContent":["/**\n * CitationList — the sources attached to a story, with verification controls.\n * @module theculturepost/components\n *\n * Reads `tcpListCitations(storyId)`; each entry can be moved through its\n * verification state (`tcpVerifyCitation`) — the archival integrity control at\n * the heart of a serious cultural publication.\n */\n\nimport { BookMarked, ExternalLink, Quote, ShieldCheck } from 'lucide-react';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Spinner,\n} from '@burdenoff/fe-libs/ui';\nimport { StatusBadge } from './StatusBadge';\nimport { LoadingView, ErrorView } from './StateViews';\nimport { EmptyState } from './EmptyState';\nimport { useTcpCitations, useTcpVerifyCitation } from '../hooks';\nimport { formatDate, formatEnumLabel } from '../utils/formatters';\nimport { notify, describeError } from '../lib/toast';\nimport type { TcpCitation, TcpVerificationStatus } from '../types';\n\nconst VERIFICATIONS: TcpVerificationStatus[] = [\n 'UNVERIFIED',\n 'CORROBORATED',\n 'DISPUTED',\n 'RETRACTED',\n];\n\ninterface CitationListProps {\n storyId: string;\n}\n\nfunction CitationRow({ citation }: { citation: TcpCitation }) {\n const verify = useTcpVerifyCitation();\n\n const changeVerification = async (verification: TcpVerificationStatus) => {\n try {\n await verify.mutateAsync({ id: citation.id, verification });\n notify.success('Verification updated', formatEnumLabel(verification));\n } catch (err) {\n notify.error('Could not update verification', describeError(err));\n }\n };\n\n const meta = [citation.author, citation.publisher, formatDate(citation.publishedOn)]\n .filter((v) => v && v !== '—')\n .join(' · ');\n\n return (\n <li className=\"rounded-xl border border-border-seam bg-bg-surface p-4\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"mb-1.5 flex flex-wrap items-center gap-1.5\">\n <StatusBadge status={citation.sourceType} />\n <StatusBadge status={citation.verification} />\n </div>\n <p className=\"text-sm font-semibold text-text-primary\">{citation.title}</p>\n {meta && <p className=\"mt-0.5 text-xs text-text-tertiary\">{meta}</p>}\n </div>\n {citation.url && (\n <a\n href={citation.url}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n className=\"inline-flex shrink-0 items-center gap-1 text-xs font-medium text-accent hover:underline\"\n >\n Source <ExternalLink className=\"h-3 w-3\" />\n </a>\n )}\n </div>\n\n {citation.excerpt && (\n <blockquote className=\"mt-3 flex gap-2 rounded-lg bg-bg-sunken/60 px-3 py-2 text-sm italic text-text-secondary\">\n <Quote className=\"h-3.5 w-3.5 shrink-0 text-text-tertiary\" aria-hidden=\"true\" />\n <span className=\"not-italic\">{citation.excerpt}</span>\n </blockquote>\n )}\n\n {citation.provenance && (\n <p className=\"mt-2 text-xs text-text-tertiary\">\n <span className=\"font-medium text-text-secondary\">Provenance:</span> {citation.provenance}\n </p>\n )}\n\n <div className=\"mt-3 flex items-center gap-2 border-t border-border-seam pt-3\">\n <ShieldCheck className=\"h-4 w-4 text-text-tertiary\" aria-hidden=\"true\" />\n <span className=\"text-xs text-text-secondary\">Verification</span>\n <Select\n value={citation.verification}\n onValueChange={(v) => changeVerification(v as TcpVerificationStatus)}\n >\n <SelectTrigger className=\"h-8 w-40\" aria-label=\"Change verification status\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {VERIFICATIONS.map((v) => (\n <SelectItem key={v} value={v}>\n {formatEnumLabel(v)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {verify.isPending && <Spinner size=\"sm\" />}\n </div>\n </li>\n );\n}\n\nexport function CitationList({ storyId }: CitationListProps) {\n const { data: citations, isLoading, isError, refetch } = useTcpCitations(storyId);\n\n if (isLoading) return <LoadingView label=\"Loading citations…\" />;\n if (isError) return <ErrorView message=\"We couldn't load citations.\" onRetry={() => refetch()} />;\n\n if (!citations || citations.length === 0) {\n return (\n <EmptyState\n icon={<BookMarked className=\"h-9 w-9\" />}\n title=\"No citations yet\"\n description=\"Add verifiable sources to ground this story in the record.\"\n />\n );\n }\n\n return (\n <ul className=\"flex flex-col gap-3\">\n {citations.map((citation) => (\n <CitationRow key={citation.id} citation={citation} />\n ))}\n </ul>\n );\n}\n"],"mappings":";;;;;;;;;;;AA0BA,IAAM,IAAyC;CAC7C;CACA;CACA;CACA;CACD;AAMD,SAAS,EAAY,EAAE,eAAuC;CAC5D,IAAM,IAAS,GAAsB,EAE/B,IAAqB,OAAO,MAAwC;AACxE,MAAI;AAEF,GADA,MAAM,EAAO,YAAY;IAAE,IAAI,EAAS;IAAI;IAAc,CAAC,EAC3D,EAAO,QAAQ,wBAAwB,EAAgB,EAAa,CAAC;WAC9D,GAAK;AACZ,KAAO,MAAM,iCAAiC,EAAc,EAAI,CAAC;;IAI/D,IAAO;EAAC,EAAS;EAAQ,EAAS;EAAW,EAAW,EAAS,YAAY;EAAC,CACjF,QAAQ,MAAM,KAAK,MAAM,IAAI,CAC7B,KAAK,MAAM;AAEd,QACE,kBAAC,MAAD;EAAI,WAAU;YAAd;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAa,QAAQ,EAAS,YAAc,CAAA,EAC5C,kBAAC,GAAD,EAAa,QAAQ,EAAS,cAAgB,CAAA,CAC1C;;MACN,kBAAC,KAAD;OAAG,WAAU;iBAA2C,EAAS;OAAU,CAAA;MAC1E,KAAQ,kBAAC,KAAD;OAAG,WAAU;iBAAqC;OAAS,CAAA;MAChE;QACL,EAAS,OACR,kBAAC,KAAD;KACE,MAAM,EAAS;KACf,QAAO;KACP,KAAI;KACJ,WAAU;eAJZ,CAKC,WACQ,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA,CACzC;OAEF;;GAEL,EAAS,WACR,kBAAC,cAAD;IAAY,WAAU;cAAtB,CACE,kBAAC,GAAD;KAAO,WAAU;KAA0C,eAAY;KAAS,CAAA,EAChF,kBAAC,QAAD;KAAM,WAAU;eAAc,EAAS;KAAe,CAAA,CAC3C;;GAGd,EAAS,cACR,kBAAC,KAAD;IAAG,WAAU;cAAb;KACE,kBAAC,QAAD;MAAM,WAAU;gBAAkC;MAAkB,CAAA;;KAAE,EAAS;KAC7E;;GAGN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAa,WAAU;MAA6B,eAAY;MAAS,CAAA;KACzE,kBAAC,QAAD;MAAM,WAAU;gBAA8B;MAAmB,CAAA;KACjE,kBAAC,GAAD;MACE,OAAO,EAAS;MAChB,gBAAgB,MAAM,EAAmB,EAA2B;gBAFtE,CAIE,kBAAC,GAAD;OAAe,WAAU;OAAW,cAAW;iBAC7C,kBAAC,GAAD,EAAe,CAAA;OACD,CAAA,EAChB,kBAAC,GAAD,EAAA,UACG,EAAc,KAAK,MAClB,kBAAC,GAAD;OAAoB,OAAO;iBACxB,EAAgB,EAAE;OACR,EAFI,EAEJ,CACb,EACY,CAAA,CACT;;KACR,EAAO,aAAa,kBAAC,GAAD,EAAS,MAAK,MAAO,CAAA;KACtC;;GACH;;;AAIT,SAAgB,EAAa,EAAE,cAA8B;CAC3D,IAAM,EAAE,MAAM,GAAW,cAAW,YAAS,eAAY,EAAgB,EAAQ;AAejF,QAbI,IAAkB,kBAAC,GAAD,EAAa,OAAM,sBAAuB,CAAA,GAC5D,IAAgB,kBAAC,GAAD;EAAW,SAAQ;EAA8B,eAAe,GAAS;EAAI,CAAA,GAE7F,CAAC,KAAa,EAAU,WAAW,IAEnC,kBAAC,GAAD;EACE,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;EACxC,OAAM;EACN,aAAY;EACZ,CAAA,GAKJ,kBAAC,MAAD;EAAI,WAAU;YACX,EAAU,KAAK,MACd,kBAAC,GAAD,EAAyC,aAAY,EAAnC,EAAS,GAA0B,CACrD;EACC,CAAA"}
|
|
1
|
+
{"version":3,"file":"CitationList.js","names":[],"sources":["../../../src/theculturepost/components/CitationList.tsx"],"sourcesContent":["/**\n * CitationList — the verifiable sources that ground a story (tcp-05).\n * @module theculturepost/components\n *\n * Reads `tcpListCitations(storyId)`; each entry can be moved through its\n * verification state (`tcpVerifyCitation`) via a **segmented control** — the\n * archival-integrity control at the heart of a serious cultural publication.\n *\n * Each source shows a source-type icon, its bibliographic detail, an optional\n * excerpt + link, and (in the full variant) closes with a static methodology\n * legend. There is deliberately NO \"evidence trail\" mapping citations to\n * individual claims — the backend exposes no such linkage, so we never fake it.\n *\n * Two layouts, same data:\n * - default (full): roomy cards + labelled segments + methodology legend.\n * - `compact`: narrow-rail cards + icon-only segments, no legend.\n */\n\nimport {\n BookOpen,\n GraduationCap,\n Landmark,\n FileText,\n Globe,\n Newspaper,\n Mic,\n Box,\n ExternalLink,\n Quote,\n ShieldCheck,\n CheckCircle2,\n AlertCircle,\n XCircle,\n HelpCircle,\n BookMarked,\n type LucideIcon,\n} from 'lucide-react';\nimport { createElement } from 'react';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { StatusBadge } from './StatusBadge';\nimport { LoadingView, ErrorView } from './StateViews';\nimport { EmptyState } from './EmptyState';\nimport { useTcpCitations, useTcpVerifyCitation } from '../hooks';\nimport { cn } from '../utils/cn';\nimport { formatDate, formatEnumLabel } from '../utils/formatters';\nimport { notify, describeError } from '../lib/toast';\nimport type { TcpCitation, TcpSourceType, TcpVerificationStatus } from '../types';\n\n// ---------------------------------------------------------------------------\n// Source-type + verification metadata (exported for reuse in the editorial table)\n// ---------------------------------------------------------------------------\n\n/** A distinct lucide motif per source type (icon, not hue — per the design rules). */\nexport const SOURCE_TYPE_ICON: Record<TcpSourceType, LucideIcon> = {\n ACADEMIC: GraduationCap,\n ARCHIVAL_RECORD: Landmark,\n ARTIFACT: Box,\n BOOK: BookOpen,\n INTERVIEW: Mic,\n PERIODICAL: Newspaper,\n PRIMARY_DOCUMENT: FileText,\n WEB: Globe,\n};\n\n/** Resolve a source-type's motif icon, falling back to a neutral document. */\nexport function sourceTypeIcon(type: TcpSourceType): LucideIcon {\n return SOURCE_TYPE_ICON[type] ?? FileText;\n}\n\ntype VerificationAccent = 'success' | 'warning' | 'destructive' | 'secondary';\n\ninterface VerificationMetaEntry {\n icon: LucideIcon;\n accent: VerificationAccent;\n label: string;\n /** Static, factual description of what the state means — shown in the legend. */\n blurb: string;\n}\n\n/** Ordered, tone-mapped metadata for each verification state. */\nexport const VERIFICATION_META: Record<TcpVerificationStatus, VerificationMetaEntry> = {\n CORROBORATED: {\n icon: CheckCircle2,\n accent: 'success',\n label: 'Corroborated',\n blurb: 'Strong agreement among reliable sources.',\n },\n DISPUTED: {\n icon: AlertCircle,\n accent: 'warning',\n label: 'Disputed',\n blurb: 'Conflicting or insufficient evidence.',\n },\n RETRACTED: {\n icon: XCircle,\n accent: 'destructive',\n label: 'Retracted',\n blurb: 'The source has since been withdrawn.',\n },\n UNVERIFIED: {\n icon: HelpCircle,\n accent: 'secondary',\n label: 'Unverified',\n blurb: 'Not yet reviewed by an editor.',\n },\n};\n\n/** The order the segmented control presents states in. */\nexport const VERIFICATIONS: TcpVerificationStatus[] = [\n 'CORROBORATED',\n 'DISPUTED',\n 'RETRACTED',\n 'UNVERIFIED',\n];\n\n/** Active-segment styling per accent — semantic tokens only. */\nconst SEGMENT_ACTIVE: Record<VerificationAccent, string> = {\n success: 'bg-status-success-bg-subtle text-status-success-text shadow-elevation-1',\n warning: 'bg-status-warning-bg-subtle text-status-warning-text shadow-elevation-1',\n destructive: 'bg-status-error-bg-subtle text-status-error-text shadow-elevation-1',\n secondary: 'bg-bg-sunken text-text-primary shadow-elevation-1',\n};\n\n// ---------------------------------------------------------------------------\n// Segmented verification control\n// ---------------------------------------------------------------------------\n\ninterface VerificationSegmentsProps {\n value: TcpVerificationStatus;\n onChange: (value: TcpVerificationStatus) => void;\n pending?: boolean;\n /** Icon-only segments (for the narrow reading rail). */\n compact?: boolean;\n className?: string;\n}\n\nfunction VerificationSegments({\n value,\n onChange,\n pending = false,\n compact = false,\n className,\n}: VerificationSegmentsProps) {\n return (\n <div\n role=\"radiogroup\"\n aria-label=\"Verification status\"\n className={cn(\n 'grid grid-cols-2 gap-1 rounded-xl border border-border-seam bg-bg-surface p-1',\n compact ? 'grid-cols-4' : 'sm:inline-grid sm:auto-cols-max sm:grid-flow-col',\n className\n )}\n >\n {VERIFICATIONS.map((v) => {\n const meta = VERIFICATION_META[v];\n const Icon = meta.icon;\n const active = v === value;\n return (\n <button\n key={v}\n type=\"button\"\n role=\"radio\"\n aria-checked={active}\n aria-label={meta.label}\n title={meta.label}\n disabled={pending}\n onClick={() => onChange(v)}\n className={cn(\n 'inline-flex min-h-9 items-center justify-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium transition-colors disabled:opacity-60',\n active\n ? SEGMENT_ACTIVE[meta.accent]\n : 'text-text-tertiary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n <Icon className=\"h-3.5 w-3.5 shrink-0\" aria-hidden=\"true\" />\n <span className={compact ? 'sr-only' : 'hidden sm:inline'}>{meta.label}</span>\n </button>\n );\n })}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Citation row\n// ---------------------------------------------------------------------------\n\nfunction CitationRow({ citation, compact }: { citation: TcpCitation; compact: boolean }) {\n const verify = useTcpVerifyCitation();\n\n const changeVerification = async (verification: TcpVerificationStatus) => {\n if (verification === citation.verification) return;\n try {\n await verify.mutateAsync({ id: citation.id, verification });\n notify.success('Verification updated', formatEnumLabel(verification));\n } catch (err) {\n notify.error('Could not update verification', describeError(err));\n }\n };\n\n const meta = [citation.author, citation.publisher, formatDate(citation.publishedOn)]\n .filter((v) => v && v !== '—')\n .join(' · ');\n\n return (\n <li\n className={cn(\n 'rounded-2xl border border-border-seam bg-bg-surface transition-colors hover:border-border-strong',\n compact ? 'p-3.5' : 'p-4 sm:p-5'\n )}\n >\n <div className={cn('flex gap-3', compact ? 'items-start' : 'sm:gap-4')}>\n {/* Source-type motif tile */}\n <span\n className={cn(\n 'grid shrink-0 place-items-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary',\n compact ? 'h-9 w-9' : 'h-12 w-12'\n )}\n aria-hidden=\"true\"\n >\n {createElement(sourceTypeIcon(citation.sourceType), {\n className: compact ? 'h-4 w-4' : 'h-6 w-6',\n })}\n </span>\n\n <div className=\"min-w-0 flex-1\">\n <div className=\"mb-1 flex flex-wrap items-center gap-1.5\">\n <StatusBadge\n status={citation.sourceType}\n icon={createElement(sourceTypeIcon(citation.sourceType), { className: 'h-3 w-3' })}\n />\n {compact && <StatusBadge status={citation.verification} />}\n </div>\n\n <p\n className={cn(\n 'font-display font-semibold leading-snug text-text-primary',\n compact ? 'text-sm' : 'text-base'\n )}\n >\n {citation.title}\n </p>\n {meta && <p className=\"mt-0.5 text-xs text-text-tertiary\">{meta}</p>}\n\n {citation.excerpt && !compact && (\n <blockquote className=\"mt-3 flex gap-2 rounded-lg bg-bg-sunken/60 px-3 py-2 text-sm text-text-secondary\">\n <Quote className=\"h-3.5 w-3.5 shrink-0 text-text-tertiary\" aria-hidden=\"true\" />\n <span>{citation.excerpt}</span>\n </blockquote>\n )}\n\n {citation.provenance && !compact && (\n <p className=\"mt-2 text-xs text-text-tertiary\">\n <span className=\"font-medium text-text-secondary\">Provenance:</span>{' '}\n {citation.provenance}\n </p>\n )}\n\n {citation.url && (\n <a\n href={citation.url}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n className=\"mt-2 inline-flex max-w-full items-center gap-1 text-xs font-medium text-accent hover:underline\"\n >\n <span className=\"truncate\">{compact ? 'View source' : citation.url}</span>\n <ExternalLink className=\"h-3 w-3 shrink-0\" aria-hidden=\"true\" />\n </a>\n )}\n </div>\n </div>\n\n {/* Verification control */}\n <div\n className={cn(\n 'mt-3 flex flex-wrap items-center gap-x-3 gap-y-2 border-t border-border-seam pt-3',\n compact ? '' : 'sm:justify-between'\n )}\n >\n <span className=\"inline-flex items-center gap-1.5 text-xs font-medium text-text-secondary\">\n <ShieldCheck className=\"h-3.5 w-3.5 text-text-tertiary\" aria-hidden=\"true\" />\n Verification\n {verify.isPending && <Spinner size=\"sm\" />}\n </span>\n <VerificationSegments\n value={citation.verification}\n onChange={changeVerification}\n pending={verify.isPending}\n compact={compact}\n />\n </div>\n </li>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Methodology legend (static — no fabricated data)\n// ---------------------------------------------------------------------------\n\nfunction MethodologyLegend() {\n return (\n <div className=\"mt-4 rounded-2xl border border-border-seam bg-bg-sunken/50 p-4 sm:p-5\">\n <div className=\"flex items-start gap-3\">\n <span\n className=\"grid h-9 w-9 shrink-0 place-items-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary\"\n aria-hidden=\"true\"\n >\n <ShieldCheck className=\"h-5 w-5\" />\n </span>\n <p className=\"text-sm text-text-secondary\">\n Every source is evaluated for accuracy, relevance, and cultural sensitivity through a\n transparent, multi-step review by editors and subject-area contributors.\n </p>\n </div>\n <dl className=\"mt-4 grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n {VERIFICATIONS.map((v) => {\n const m = VERIFICATION_META[v];\n const Icon = m.icon;\n return (\n <div key={v} className=\"flex items-start gap-2\">\n <Icon\n className={cn(\n 'mt-0.5 h-4 w-4 shrink-0',\n m.accent === 'success' && 'text-status-success-text',\n m.accent === 'warning' && 'text-status-warning-text',\n m.accent === 'destructive' && 'text-status-error-text',\n m.accent === 'secondary' && 'text-text-tertiary'\n )}\n aria-hidden=\"true\"\n />\n <div>\n <dt className=\"text-xs font-semibold text-text-primary\">{m.label}</dt>\n <dd className=\"mt-0.5 text-xs text-text-tertiary\">{m.blurb}</dd>\n </div>\n </div>\n );\n })}\n </dl>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// CitationList\n// ---------------------------------------------------------------------------\n\ninterface CitationListProps {\n storyId: string;\n /** Narrow reading-rail rendering: smaller cards, icon-only segments, no legend. */\n compact?: boolean;\n}\n\nexport function CitationList({ storyId, compact = false }: CitationListProps) {\n const { data: citations, isLoading, isError, refetch } = useTcpCitations(storyId);\n\n if (isLoading) return <LoadingView label=\"Loading citations…\" />;\n if (isError) return <ErrorView message=\"We couldn't load citations.\" onRetry={() => refetch()} />;\n\n if (!citations || citations.length === 0) {\n return (\n <EmptyState\n icon={<BookMarked className=\"h-9 w-9\" />}\n title=\"No citations yet\"\n description=\"Add verifiable sources to ground this story in the record.\"\n />\n );\n }\n\n return (\n <div>\n <ul className={cn('flex flex-col', compact ? 'gap-3' : 'gap-3 sm:gap-4')}>\n {citations.map((citation) => (\n <CitationRow key={citation.id} citation={citation} compact={compact} />\n ))}\n </ul>\n {!compact && <MethodologyLegend />}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,56 +1,56 @@
|
|
|
1
1
|
import { CoverImage as e } from "./CoverImage.js";
|
|
2
2
|
import { formatNumber as t } from "../utils/formatters.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { OverlayBadge as n } from "./OverlayBadge.js";
|
|
4
|
+
import { Layers as r, Library as i } from "lucide-react";
|
|
5
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
6
|
+
import { GlassCard as s } from "@burdenoff/fe-libs/ui";
|
|
6
7
|
//#region src/theculturepost/components/CollectionCard.tsx
|
|
7
|
-
function
|
|
8
|
-
return /* @__PURE__ */
|
|
8
|
+
function c({ collection: c, onOpen: l }) {
|
|
9
|
+
return /* @__PURE__ */ o(s, {
|
|
9
10
|
treatment: "plain",
|
|
10
11
|
className: "flex flex-col overflow-hidden",
|
|
11
|
-
children: [/* @__PURE__ */
|
|
12
|
+
children: [/* @__PURE__ */ o("button", {
|
|
12
13
|
type: "button",
|
|
13
|
-
onClick:
|
|
14
|
+
onClick: l,
|
|
14
15
|
className: "group relative block aspect-[3/2] w-full overflow-hidden text-left",
|
|
15
|
-
"aria-label": `Open ${
|
|
16
|
-
children: /* @__PURE__ */
|
|
17
|
-
fileId:
|
|
18
|
-
alt:
|
|
16
|
+
"aria-label": `Open ${c.name}`,
|
|
17
|
+
children: [/* @__PURE__ */ a(e, {
|
|
18
|
+
fileId: c.cover?.id,
|
|
19
|
+
alt: c.name,
|
|
19
20
|
rounded: "rounded-none",
|
|
20
21
|
className: "h-full w-full transition-transform duration-500 group-hover:scale-[1.03]",
|
|
21
|
-
icon: /* @__PURE__ */ i
|
|
22
|
-
})
|
|
23
|
-
|
|
22
|
+
icon: /* @__PURE__ */ a(i, { className: "h-8 w-8" })
|
|
23
|
+
}), /* @__PURE__ */ o(n, {
|
|
24
|
+
position: "top-right",
|
|
25
|
+
icon: /* @__PURE__ */ a(r, { className: "h-3 w-3" }),
|
|
26
|
+
children: [
|
|
27
|
+
t(c.itemCount),
|
|
28
|
+
" ",
|
|
29
|
+
c.itemCount === 1 ? "item" : "items"
|
|
30
|
+
]
|
|
31
|
+
})]
|
|
32
|
+
}), /* @__PURE__ */ o("div", {
|
|
24
33
|
className: "flex flex-1 flex-col p-5",
|
|
25
34
|
children: [
|
|
26
|
-
/* @__PURE__ */
|
|
35
|
+
/* @__PURE__ */ a("button", {
|
|
27
36
|
type: "button",
|
|
28
|
-
onClick:
|
|
29
|
-
className: "text-left text-
|
|
30
|
-
children:
|
|
37
|
+
onClick: l,
|
|
38
|
+
className: "font-display text-left text-lg font-semibold text-text-primary hover:underline",
|
|
39
|
+
children: c.name
|
|
31
40
|
}),
|
|
32
|
-
|
|
41
|
+
c.tradition && /* @__PURE__ */ a("p", {
|
|
33
42
|
className: "mt-0.5 text-sm text-text-secondary",
|
|
34
|
-
children:
|
|
43
|
+
children: c.tradition
|
|
35
44
|
}),
|
|
36
|
-
|
|
45
|
+
c.description && /* @__PURE__ */ a("p", {
|
|
37
46
|
className: "mt-2 line-clamp-2 text-sm text-text-secondary",
|
|
38
|
-
children:
|
|
39
|
-
}),
|
|
40
|
-
/* @__PURE__ */ a("div", {
|
|
41
|
-
className: "mt-auto flex items-center gap-1.5 pt-4 text-xs text-text-tertiary",
|
|
42
|
-
children: [
|
|
43
|
-
/* @__PURE__ */ i(n, { className: "h-3.5 w-3.5" }),
|
|
44
|
-
t(s.itemCount),
|
|
45
|
-
" ",
|
|
46
|
-
s.itemCount === 1 ? "item" : "items"
|
|
47
|
-
]
|
|
47
|
+
children: c.description
|
|
48
48
|
})
|
|
49
49
|
]
|
|
50
50
|
})]
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
53
|
//#endregion
|
|
54
|
-
export {
|
|
54
|
+
export { c as CollectionCard };
|
|
55
55
|
|
|
56
56
|
//# sourceMappingURL=CollectionCard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollectionCard.js","names":[],"sources":["../../../src/theculturepost/components/CollectionCard.tsx"],"sourcesContent":["/**\n * CollectionCard — a tile for an archive collection.\n * @module theculturepost/components\n *\n * Cover image
|
|
1
|
+
{"version":3,"file":"CollectionCard.js","names":[],"sources":["../../../src/theculturepost/components/CollectionCard.tsx"],"sourcesContent":["/**\n * CollectionCard — a tile for an archive collection.\n * @module theculturepost/components\n *\n * Cover image (collections DO carry a cover file) with the real item count as an\n * {@link OverlayBadge}; serif name, tradition (as region), description. Links to\n * the collection detail page.\n */\n\nimport { Library, Layers } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { CoverImage } from './CoverImage';\nimport { OverlayBadge } from './OverlayBadge';\nimport { formatNumber } from '../utils/formatters';\nimport type { TcpCollection } from '../types';\n\ninterface CollectionCardProps {\n collection: TcpCollection;\n onOpen: () => void;\n}\n\nexport function CollectionCard({ collection, onOpen }: CollectionCardProps) {\n return (\n <GlassCard treatment=\"plain\" className=\"flex flex-col overflow-hidden\">\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"group relative block aspect-[3/2] w-full overflow-hidden text-left\"\n aria-label={`Open ${collection.name}`}\n >\n <CoverImage\n fileId={collection.cover?.id}\n alt={collection.name}\n rounded=\"rounded-none\"\n className=\"h-full w-full transition-transform duration-500 group-hover:scale-[1.03]\"\n icon={<Library className=\"h-8 w-8\" />}\n />\n <OverlayBadge position=\"top-right\" icon={<Layers className=\"h-3 w-3\" />}>\n {formatNumber(collection.itemCount)} {collection.itemCount === 1 ? 'item' : 'items'}\n </OverlayBadge>\n </button>\n\n <div className=\"flex flex-1 flex-col p-5\">\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"font-display text-left text-lg font-semibold text-text-primary hover:underline\"\n >\n {collection.name}\n </button>\n {collection.tradition && (\n <p className=\"mt-0.5 text-sm text-text-secondary\">{collection.tradition}</p>\n )}\n {collection.description && (\n <p className=\"mt-2 line-clamp-2 text-sm text-text-secondary\">{collection.description}</p>\n )}\n </div>\n </GlassCard>\n );\n}\n"],"mappings":";;;;;;;AAqBA,SAAgB,EAAe,EAAE,eAAY,aAA+B;AAC1E,QACE,kBAAC,GAAD;EAAW,WAAU;EAAQ,WAAU;YAAvC,CACE,kBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAU;GACV,cAAY,QAAQ,EAAW;aAJjC,CAME,kBAAC,GAAD;IACE,QAAQ,EAAW,OAAO;IAC1B,KAAK,EAAW;IAChB,SAAQ;IACR,WAAU;IACV,MAAM,kBAAC,GAAD,EAAS,WAAU,WAAY,CAAA;IACrC,CAAA,EACF,kBAAC,GAAD;IAAc,UAAS;IAAY,MAAM,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;cAAvE;KACG,EAAa,EAAW,UAAU;KAAC;KAAE,EAAW,cAAc,IAAI,SAAS;KAC/D;MACR;MAET,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAU;eAET,EAAW;KACL,CAAA;IACR,EAAW,aACV,kBAAC,KAAD;KAAG,WAAU;eAAsC,EAAW;KAAc,CAAA;IAE7E,EAAW,eACV,kBAAC,KAAD;KAAG,WAAU;eAAiD,EAAW;KAAgB,CAAA;IAEvF;KACI"}
|