@burdenoff/microfe-theculturepost 2026.704.2 → 2026.705.2

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 (91) 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/hooks/useFiles.js +1 -1
  61. package/dist/theculturepost/hooks/useFiles.js.map +1 -1
  62. package/dist/theculturepost/pages/HomePage.js +247 -124
  63. package/dist/theculturepost/pages/HomePage.js.map +1 -1
  64. package/dist/theculturepost/pages/archive/ArchiveItemDetailPage.js +319 -127
  65. package/dist/theculturepost/pages/archive/ArchiveItemDetailPage.js.map +1 -1
  66. package/dist/theculturepost/pages/archive/ArchivePage.js +265 -180
  67. package/dist/theculturepost/pages/archive/ArchivePage.js.map +1 -1
  68. package/dist/theculturepost/pages/archive/CollectionDetailPage.js +158 -143
  69. package/dist/theculturepost/pages/archive/CollectionDetailPage.js.map +1 -1
  70. package/dist/theculturepost/pages/discussions/DiscussionDetailPage.js +155 -93
  71. package/dist/theculturepost/pages/discussions/DiscussionDetailPage.js.map +1 -1
  72. package/dist/theculturepost/pages/discussions/DiscussionsPage.js +16 -16
  73. package/dist/theculturepost/pages/discussions/DiscussionsPage.js.map +1 -1
  74. package/dist/theculturepost/pages/governance/GovernancePage.js +293 -0
  75. package/dist/theculturepost/pages/governance/GovernancePage.js.map +1 -0
  76. package/dist/theculturepost/pages/stories/StoriesPage.js +18 -18
  77. package/dist/theculturepost/pages/stories/StoriesPage.js.map +1 -1
  78. package/dist/theculturepost/pages/stories/StoryDetailPage.js +603 -285
  79. package/dist/theculturepost/pages/stories/StoryDetailPage.js.map +1 -1
  80. package/dist/theculturepost/pages/timeline/TimelinePage.js +162 -0
  81. package/dist/theculturepost/pages/timeline/TimelinePage.js.map +1 -0
  82. package/dist/theculturepost/pages/topics/TopicDetailPage.js +239 -163
  83. package/dist/theculturepost/pages/topics/TopicDetailPage.js.map +1 -1
  84. package/dist/theculturepost/pages/topics/TopicsPage.js +76 -74
  85. package/dist/theculturepost/pages/topics/TopicsPage.js.map +1 -1
  86. package/dist/theculturepost/styles/injectDisplayFont.js +11 -0
  87. package/dist/theculturepost/styles/injectDisplayFont.js.map +1 -0
  88. package/dist/theculturepost/utils/formatters.js +6 -1
  89. package/dist/theculturepost/utils/formatters.js.map +1 -1
  90. package/package.json +1 -1
  91. package/dist/theculturepost/components/OralHistoryCard.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"StoryDetailPage.js","names":[],"sources":["../../../../src/theculturepost/pages/stories/StoryDetailPage.tsx"],"sourcesContent":["/**\n * StoryDetailPage — a single story with its editorial lifecycle, citations and\n * linked discussions.\n * @module theculturepost/pages/stories\n *\n * Reads `tcpStory` (+ its citations). Writes `tcpTransitionStory` (validated\n * lifecycle), `tcpUpdateStory` (edit), `tcpAddCitation` / `tcpVerifyCitation`\n * (via {@link CitationList}). Person references are id-only, so we render \"You\"\n * / \"Contributor\".\n */\n\nimport { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n BookOpen,\n Clock,\n Languages,\n Tag,\n Pencil,\n Plus,\n GitBranch,\n MessagesSquare,\n} from 'lucide-react';\nimport {\n Button,\n GlassCard,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { CoverImage } from '../../components/CoverImage';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { AuthorLabel } from '../../components/AuthorLabel';\nimport { CitationList } from '../../components/CitationList';\nimport { DiscussionCard } from '../../components/DiscussionCard';\nimport { AddCitationDialog } from '../../components/AddCitationDialog';\nimport { OpenDiscussionDialog } from '../../components/OpenDiscussionDialog';\nimport { TagInput } from '../../components/TagInput';\nimport { FileUploadField } from '../../components/FileUploadField';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView, Section } from '../../components/StateViews';\nimport {\n useTcpStory,\n useTcpTransitionStory,\n useTcpUpdateStory,\n useTcpTopics,\n useTcpDiscussions,\n FILE_FOLDERS,\n} from '../../hooks';\nimport { useTheCulturePost } from '../../context';\nimport { formatEnumLabel, formatNumber } from '../../utils/formatters';\nimport { notify, describeError } from '../../lib/toast';\nimport type { TcpStory, TcpStoryFormat, TcpStoryStatus } from '../../types';\n\nconst NEXT_STATUSES: Record<TcpStoryStatus, TcpStoryStatus[]> = {\n IDEA: ['DRAFT'],\n DRAFT: ['IN_REVIEW'],\n IN_REVIEW: ['PUBLISHED', 'DRAFT'],\n PUBLISHED: ['ARCHIVED'],\n ARCHIVED: ['PUBLISHED'],\n};\n\nconst TRANSITION_LABEL: Record<TcpStoryStatus, string> = {\n IDEA: 'Move to Idea',\n DRAFT: 'Move to Draft',\n IN_REVIEW: 'Send to Review',\n PUBLISHED: 'Publish',\n ARCHIVED: 'Archive',\n};\n\nexport function StoryDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = useTheCulturePost();\n const { data: story, isLoading, isError, refetch } = useTcpStory(id);\n const transition = useTcpTransitionStory();\n\n const [citationOpen, setCitationOpen] = useState(false);\n const [discussionOpen, setDiscussionOpen] = useState(false);\n const [editOpen, setEditOpen] = useState(false);\n\n const discussionsQuery = useTcpDiscussions({ storyId: id, pagination: { limit: 20 } });\n const linkedDiscussions = discussionsQuery.data?.items ?? [];\n\n const backButton = (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => navigateTo('stories')}>\n <ArrowLeft className=\"mr-1.5 h-4 w-4\" /> Back\n </Button>\n );\n\n if (isLoading) {\n return (\n <PageLayout title=\"Story\" actions={backButton}>\n <LoadingView label=\"Loading story…\" />\n </PageLayout>\n );\n }\n\n if (isError || !story) {\n return (\n <PageLayout title=\"Story\" actions={backButton}>\n <ErrorView\n title=\"Story not found\"\n message=\"This story may have been archived, or you may not have access.\"\n onRetry={() => refetch()}\n />\n </PageLayout>\n );\n }\n\n const nextStatuses = NEXT_STATUSES[story.status] ?? [];\n\n const doTransition = async (status: TcpStoryStatus) => {\n try {\n await transition.mutateAsync({ id: story.id, status });\n notify.success('Story updated', `Moved to ${formatEnumLabel(status)}`);\n } catch (err) {\n notify.error('Could not update the story', describeError(err));\n }\n };\n\n return (\n <PageLayout\n title={story.title}\n actions={\n <div className=\"flex items-center gap-2\">\n {backButton}\n <Button variant=\"outline\" onClick={() => setEditOpen(true)}>\n <Pencil className=\"mr-1.5 h-4 w-4\" /> Edit\n </Button>\n </div>\n }\n >\n <article className=\"mx-auto flex max-w-3xl flex-col gap-6\">\n {/* Hero cover */}\n <CoverImage\n fileId={story.cover?.id}\n alt={story.title}\n className=\"aspect-[16/9] w-full\"\n icon={<BookOpen className=\"h-10 w-10\" />}\n />\n\n {/* Meta */}\n <div className=\"flex flex-col gap-3\">\n <div className=\"flex flex-wrap items-center gap-1.5\">\n <StatusBadge status={story.format} />\n <StatusBadge status={story.status} />\n {story.topic && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`topics/${story.topic!.id}`)}\n className=\"inline-flex items-center gap-1 rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary hover:text-text-primary\"\n >\n <Tag className=\"h-3 w-3\" /> {story.topic.name}\n </button>\n )}\n </div>\n\n {story.summary && (\n <p className=\"text-lg leading-relaxed text-text-secondary\">{story.summary}</p>\n )}\n\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1.5 text-sm text-text-tertiary\">\n <AuthorLabel actorId={story.authorId} prefix=\"By\" withIcon />\n {story.editorId && <AuthorLabel actorId={story.editorId} prefix=\"Edited by\" />}\n {story.readingMins > 0 && (\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-4 w-4\" /> {formatNumber(story.readingMins)} min read\n </span>\n )}\n {story.languages.length > 0 && (\n <span className=\"inline-flex items-center gap-1\">\n <Languages className=\"h-4 w-4\" /> {story.languages.map(formatEnumLabel).join(', ')}\n </span>\n )}\n </div>\n\n {story.tags.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5\">\n {story.tags.map((tag) => (\n <span\n key={tag}\n className=\"rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary\"\n >\n #{tag}\n </span>\n ))}\n </div>\n )}\n </div>\n\n {/* Editorial lifecycle */}\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <div className=\"flex items-center gap-2\">\n <GitBranch className=\"h-4 w-4 text-text-tertiary\" />\n <h2 className=\"text-sm font-semibold text-text-primary\">Editorial lifecycle</h2>\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Current stage:{' '}\n <span className=\"font-medium text-text-primary\">{formatEnumLabel(story.status)}</span>\n </p>\n {nextStatuses.length > 0 ? (\n <div className=\"mt-3 flex flex-wrap gap-2\">\n {nextStatuses.map((status) => (\n <Button\n key={status}\n size=\"sm\"\n variant={status === 'PUBLISHED' ? 'default' : 'outline'}\n onClick={() => doTransition(status)}\n disabled={transition.isPending}\n >\n {TRANSITION_LABEL[status]}\n </Button>\n ))}\n </div>\n ) : (\n <p className=\"mt-3 text-sm text-text-tertiary\">\n This story is at the end of its lifecycle.\n </p>\n )}\n </GlassCard>\n\n {/* Body */}\n {story.body ? (\n <div className=\"whitespace-pre-wrap text-base leading-relaxed text-text-primary\">\n {story.body}\n </div>\n ) : (\n <p className=\"rounded-xl border border-dashed border-border-seam px-4 py-6 text-center text-sm text-text-tertiary\">\n This story has no body yet. Use Edit to write it.\n </p>\n )}\n\n {/* Citations */}\n <Section\n title=\"Citations\"\n description=\"Verifiable sources that ground this story.\"\n action={\n <Button size=\"sm\" variant=\"outline\" onClick={() => setCitationOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Add citation\n </Button>\n }\n >\n <CitationList storyId={story.id} />\n </Section>\n\n {/* Linked discussions */}\n <Section\n title=\"Discussions\"\n description=\"Conversations anchored to this story.\"\n action={\n <Button size=\"sm\" variant=\"outline\" onClick={() => setDiscussionOpen(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Open discussion\n </Button>\n }\n >\n {discussionsQuery.isLoading ? (\n <LoadingView label=\"Loading discussions…\" />\n ) : linkedDiscussions.length === 0 ? (\n <EmptyState\n icon={<MessagesSquare className=\"h-9 w-9\" />}\n title=\"No discussions yet\"\n description=\"Open a discussion to invite perspectives on this story.\"\n />\n ) : (\n <div className=\"grid gap-4 md:grid-cols-2\">\n {linkedDiscussions.map((discussion) => (\n <DiscussionCard\n key={discussion.id}\n discussion={discussion}\n onOpen={() => navigateTo(`discussions/${discussion.id}`)}\n />\n ))}\n </div>\n )}\n </Section>\n </article>\n\n <AddCitationDialog open={citationOpen} onOpenChange={setCitationOpen} storyId={story.id} />\n <OpenDiscussionDialog\n open={discussionOpen}\n onOpenChange={setDiscussionOpen}\n storyId={story.id}\n onCreated={(discussion) => navigateTo(`discussions/${discussion.id}`)}\n />\n <EditStoryDialog open={editOpen} onOpenChange={setEditOpen} story={story} />\n </PageLayout>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Edit story dialog (local — only used here)\n// ---------------------------------------------------------------------------\n\nconst FORMATS: TcpStoryFormat[] = [\n 'ARTICLE',\n 'ESSAY',\n 'EXPLAINER',\n 'ORAL_HISTORY',\n 'PHOTO_STORY',\n 'TIMELINE',\n];\n\nfunction EditStoryDialog({\n open,\n onOpenChange,\n story,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n story: TcpStory;\n}) {\n const updateStory = useTcpUpdateStory();\n const topicsQuery = useTcpTopics({ pagination: { limit: 100 } });\n\n const [title, setTitle] = useState(story.title);\n const [summary, setSummary] = useState(story.summary ?? '');\n const [body, setBody] = useState(story.body ?? '');\n const [format, setFormat] = useState<TcpStoryFormat>(story.format);\n const [pickedTopic, setPickedTopic] = useState(story.topicId ?? '');\n const [languages, setLanguages] = useState<string[]>(story.languages);\n const [tags, setTags] = useState<string[]>(story.tags);\n const [readingMins, setReadingMins] = useState(\n story.readingMins ? String(story.readingMins) : ''\n );\n const [coverFileId, setCoverFileId] = useState<string | null>(story.cover?.id ?? null);\n const [error, setError] = useState<string | null>(null);\n\n // Reset local state whenever a different story is opened for editing.\n const storyKey = useMemo(() => `${story.id}:${story.updatedAt}`, [story.id, story.updatedAt]);\n const [seededKey, setSeededKey] = useState(storyKey);\n if (seededKey !== storyKey) {\n setSeededKey(storyKey);\n setTitle(story.title);\n setSummary(story.summary ?? '');\n setBody(story.body ?? '');\n setFormat(story.format);\n setPickedTopic(story.topicId ?? '');\n setLanguages(story.languages);\n setTags(story.tags);\n setReadingMins(story.readingMins ? String(story.readingMins) : '');\n setCoverFileId(story.cover?.id ?? null);\n setError(null);\n }\n\n const submit = async () => {\n if (!title.trim()) {\n setError('A title is required.');\n return;\n }\n try {\n await updateStory.mutateAsync({\n id: story.id,\n input: {\n title: title.trim(),\n summary: summary.trim() || null,\n body: body.trim() || null,\n format,\n topicId: pickedTopic || null,\n languages,\n tags,\n readingMins: readingMins ? Number(readingMins) : null,\n coverFileId,\n },\n });\n notify.success('Story updated', title.trim());\n onOpenChange(false);\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>Edit story</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Refine the story. The URL slug is fixed once created.\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 <FileUploadField\n folder={FILE_FOLDERS.covers}\n accept=\"image/*\"\n label=\"Upload cover\"\n fileId={coverFileId}\n onUploaded={setCoverFileId}\n onCleared={() => setCoverFileId(null)}\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"edit-title\">Title</Label>\n <Input id=\"edit-title\" value={title} onChange={(e) => setTitle(e.target.value)} />\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"grid gap-1.5\">\n <Label>Format</Label>\n <Select value={format} onValueChange={(v) => setFormat(v as TcpStoryFormat)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {FORMATS.map((f) => (\n <SelectItem key={f} value={f}>\n {formatEnumLabel(f)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"edit-reading\">Reading time (min)</Label>\n <Input\n id=\"edit-reading\"\n type=\"number\"\n min={0}\n value={readingMins}\n onChange={(e) => setReadingMins(e.target.value)}\n />\n </div>\n </div>\n <div className=\"grid gap-1.5\">\n <Label>Topic</Label>\n <Select value={pickedTopic} onValueChange={setPickedTopic}>\n <SelectTrigger>\n <SelectValue placeholder=\"Choose a topic (optional)\" />\n </SelectTrigger>\n <SelectContent>\n {(topicsQuery.data?.items ?? []).map((topic) => (\n <SelectItem key={topic.id} value={topic.id}>\n {topic.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"edit-summary\">Summary</Label>\n <Textarea\n id=\"edit-summary\"\n value={summary}\n onChange={(e) => setSummary(e.target.value)}\n rows={2}\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"edit-body\">Body</Label>\n <Textarea\n id=\"edit-body\"\n value={body}\n onChange={(e) => setBody(e.target.value)}\n rows={6}\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"edit-langs\">Languages</Label>\n <TagInput id=\"edit-langs\" value={languages} onChange={setLanguages} preserveCase />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"edit-tags\">Tags</Label>\n <TagInput id=\"edit-tags\" value={tags} onChange={setTags} />\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={updateStory.isPending}>\n Save changes\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"StoryDetailPage.js","names":[],"sources":["../../../../src/theculturepost/pages/stories/StoryDetailPage.tsx"],"sourcesContent":["/**\n * StoryDetailPage — a single story in two complementary surfaces.\n * @module theculturepost/pages/stories\n *\n * A `?view=` toggle (with a sub-tab control) splits the page into:\n * - READING (tcp-03): a cover-banner hero, serif display title, a drop-cap\n * article body with ornamental section breaks, and a right rail of citations\n * (compact) + linked discussions.\n * - EDITORIAL (tcp-04): a visual lifecycle stepper with validated transitions\n * (Publish / Send back), plus citations as a verifiable-source table with an\n * inline verify control.\n *\n * Reads `tcpStory` (+ citations), `tcpListDiscussions(storyId)`. Writes\n * `tcpTransitionStory`, `tcpUpdateStory`, `tcpVerifyCitation`. Person references\n * are id-only, so we render \"You\" / \"Contributor\".\n */\n\nimport { Fragment, useMemo, useState, type ReactNode } from 'react';\nimport { useParams, useSearchParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n BookOpen,\n ChevronDown,\n Clock,\n GitBranch,\n Languages,\n Lightbulb,\n Lock,\n MessagesSquare,\n Pencil,\n Plus,\n RotateCcw,\n Scroll,\n Send,\n ShieldCheck,\n Sparkles,\n Tag,\n Archive as ArchiveIcon,\n type LucideIcon,\n} from 'lucide-react';\nimport {\n Button,\n GlassCard,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveTable,\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\nimport { PageHero } from '../../components/PageHero';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { Tabs, type TabItem } from '../../components/Tabs';\nimport { LifecycleStepper } from '../../components/LifecycleStepper';\nimport { DecorativeDivider } from '../../components/DecorativeDivider';\nimport { AuthorLabel } from '../../components/AuthorLabel';\nimport {\n CitationList,\n sourceTypeIcon,\n VERIFICATION_META,\n VERIFICATIONS,\n} from '../../components/CitationList';\nimport { AddCitationDialog } from '../../components/AddCitationDialog';\nimport { OpenDiscussionDialog } from '../../components/OpenDiscussionDialog';\nimport { TagInput } from '../../components/TagInput';\nimport { FileUploadField } from '../../components/FileUploadField';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport {\n useTcpStory,\n useTcpTransitionStory,\n useTcpUpdateStory,\n useTcpTopics,\n useTcpDiscussions,\n useTcpCitations,\n useTcpVerifyCitation,\n FILE_FOLDERS,\n} from '../../hooks';\nimport { useTheCulturePost } from '../../context';\nimport { cn } from '../../utils/cn';\nimport {\n formatDate,\n formatEnumLabel,\n formatNumber,\n formatRelativeTime,\n} from '../../utils/formatters';\nimport { notify, describeError } from '../../lib/toast';\nimport type {\n TcpCitation,\n TcpDiscussion,\n TcpStory,\n TcpStoryFormat,\n TcpStoryStatus,\n TcpVerificationStatus,\n} from '../../types';\n\ntype StoryView = 'reading' | 'editorial';\n\nconst NEXT_STATUSES: Record<TcpStoryStatus, TcpStoryStatus[]> = {\n IDEA: ['DRAFT'],\n DRAFT: ['IN_REVIEW'],\n IN_REVIEW: ['PUBLISHED', 'DRAFT'],\n PUBLISHED: ['ARCHIVED'],\n ARCHIVED: ['PUBLISHED'],\n};\n\ninterface TransitionMetaEntry {\n label: string;\n icon: LucideIcon;\n primary?: boolean;\n}\n\nconst TRANSITION_META: Record<TcpStoryStatus, TransitionMetaEntry> = {\n IDEA: { label: 'Move to Idea', icon: Lightbulb },\n DRAFT: { label: 'Send back to Draft', icon: RotateCcw },\n IN_REVIEW: { label: 'Send to Review', icon: Send },\n PUBLISHED: { label: 'Publish', icon: Send, primary: true },\n ARCHIVED: { label: 'Archive', icon: ArchiveIcon },\n};\n\n/** Semantic-token colour for a verification icon (matches CitationList legend). */\nfunction verificationIconClass(status: TcpVerificationStatus): string {\n switch (VERIFICATION_META[status].accent) {\n case 'success':\n return 'text-status-success-text';\n case 'warning':\n return 'text-status-warning-text';\n case 'destructive':\n return 'text-status-error-text';\n default:\n return 'text-text-tertiary';\n }\n}\n\n// ===========================================================================\n// Page\n// ===========================================================================\n\nexport function StoryDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = useTheCulturePost();\n const [searchParams, setSearchParams] = useSearchParams();\n\n const view: StoryView = searchParams.get('view') === 'editorial' ? 'editorial' : 'reading';\n const setView = (next: StoryView) => {\n setSearchParams(\n (prev) => {\n const params = new URLSearchParams(prev);\n if (next === 'editorial') params.set('view', 'editorial');\n else params.delete('view');\n return params;\n },\n { replace: true }\n );\n };\n\n const { data: story, isLoading, isError, refetch } = useTcpStory(id);\n\n const [citationOpen, setCitationOpen] = useState(false);\n const [discussionOpen, setDiscussionOpen] = useState(false);\n const [editOpen, setEditOpen] = useState(false);\n\n const discussionsQuery = useTcpDiscussions({ storyId: id, pagination: { limit: 20 } });\n const linkedDiscussions = discussionsQuery.data?.items ?? [];\n\n if (isLoading) {\n return (\n <div className=\"mx-auto max-w-6xl p-4 sm:p-6\">\n <Button variant=\"ghost\" size=\"sm\" onClick={() => navigateTo('stories')}>\n <ArrowLeft className=\"mr-1.5 h-4 w-4\" /> Stories\n </Button>\n <LoadingView label=\"Loading story…\" />\n </div>\n );\n }\n\n if (isError || !story) {\n return (\n <div className=\"mx-auto max-w-6xl p-4 sm:p-6\">\n <Button variant=\"ghost\" size=\"sm\" onClick={() => navigateTo('stories')}>\n <ArrowLeft className=\"mr-1.5 h-4 w-4\" /> Stories\n </Button>\n <ErrorView\n title=\"Story not found\"\n message=\"This story may have been archived, or you may not have access.\"\n onRetry={() => refetch()}\n />\n </div>\n );\n }\n\n const heroMeta = (\n <>\n <StatusBadge status={story.format} />\n <StatusBadge status={story.status} />\n {story.topic && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`topics/${story.topic!.id}`)}\n className=\"inline-flex items-center gap-1 rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary transition-colors hover:text-text-primary\"\n >\n <Tag className=\"h-3 w-3\" aria-hidden=\"true\" /> {story.topic.name}\n </button>\n )}\n <span className=\"inline-flex items-center gap-1.5 text-xs text-text-tertiary\">\n <AuthorLabel actorId={story.authorId} prefix=\"By\" withIcon />\n </span>\n {story.readingMins > 0 && (\n <span className=\"inline-flex items-center gap-1 text-xs text-text-tertiary\">\n <Clock className=\"h-3.5 w-3.5\" aria-hidden=\"true\" /> {formatNumber(story.readingMins)} min\n read\n </span>\n )}\n {story.languages.length > 0 && (\n <span className=\"inline-flex items-center gap-1 text-xs text-text-tertiary\">\n <Languages className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />{' '}\n {story.languages.map(formatEnumLabel).join(', ')}\n </span>\n )}\n </>\n );\n\n const tabs: TabItem<StoryView>[] = [\n { value: 'reading', label: 'Reading', icon: <BookOpen className=\"h-4 w-4\" /> },\n {\n value: 'editorial',\n label: 'Editorial',\n icon: <GitBranch className=\"h-4 w-4\" />,\n count: story.citations.length,\n },\n ];\n\n return (\n <div className=\"mx-auto flex max-w-6xl flex-col gap-6 p-4 sm:p-6\">\n <PageHero\n eyebrow=\"Story\"\n title={story.title}\n description={story.summary ?? undefined}\n coverFileId={story.cover?.id ?? undefined}\n backAction={{ label: 'Stories', onClick: () => navigateTo('stories') }}\n meta={heroMeta}\n actions={\n <Button variant=\"outline\" onClick={() => setEditOpen(true)}>\n <Pencil className=\"mr-1.5 h-4 w-4\" /> Edit\n </Button>\n }\n />\n\n <Tabs items={tabs} value={view} onChange={setView} />\n\n {view === 'reading' ? (\n <ReadingView\n story={story}\n discussions={linkedDiscussions}\n discussionsLoading={discussionsQuery.isLoading}\n onViewCitations={() => setView('editorial')}\n onOpenDiscussion={() => setDiscussionOpen(true)}\n onViewAllDiscussions={() => navigateTo('discussions')}\n onOpenDiscussionItem={(discussion) => navigateTo(`discussions/${discussion.id}`)}\n />\n ) : (\n <EditorialView story={story} onAddCitation={() => setCitationOpen(true)} />\n )}\n\n <AddCitationDialog open={citationOpen} onOpenChange={setCitationOpen} storyId={story.id} />\n <OpenDiscussionDialog\n open={discussionOpen}\n onOpenChange={setDiscussionOpen}\n storyId={story.id}\n onCreated={(discussion) => navigateTo(`discussions/${discussion.id}`)}\n />\n <EditStoryDialog open={editOpen} onOpenChange={setEditOpen} story={story} />\n </div>\n );\n}\n\n// ===========================================================================\n// Reading view (tcp-03)\n// ===========================================================================\n\ninterface ReadingViewProps {\n story: TcpStory;\n discussions: TcpDiscussion[];\n discussionsLoading: boolean;\n onViewCitations: () => void;\n onOpenDiscussion: () => void;\n onViewAllDiscussions: () => void;\n onOpenDiscussionItem: (discussion: TcpDiscussion) => void;\n}\n\nfunction ReadingView({\n story,\n discussions,\n discussionsLoading,\n onViewCitations,\n onOpenDiscussion,\n onViewAllDiscussions,\n onOpenDiscussionItem,\n}: ReadingViewProps) {\n return (\n <div className=\"grid grid-cols-1 gap-8 lg:grid-cols-[minmax(0,1fr)_360px]\">\n {/* Article */}\n <article className=\"min-w-0\">\n <StoryBody body={story.body} />\n\n {story.tags.length > 0 && (\n <div className=\"mt-8 flex flex-wrap gap-1.5 border-t border-border-seam pt-6\">\n {story.tags.map((tag) => (\n <span\n key={tag}\n className=\"rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary\"\n >\n #{tag}\n </span>\n ))}\n </div>\n )}\n </article>\n\n {/* Right rail */}\n <aside className=\"flex flex-col gap-6 lg:sticky lg:top-4 lg:self-start\">\n <RailPanel\n title=\"Citations\"\n action={\n <button\n type=\"button\"\n onClick={onViewCitations}\n className=\"text-xs font-medium text-accent hover:underline\"\n >\n View all\n </button>\n }\n >\n <CitationList storyId={story.id} compact />\n </RailPanel>\n\n <RailPanel\n title=\"Linked discussions\"\n action={\n <button\n type=\"button\"\n onClick={onViewAllDiscussions}\n className=\"text-xs font-medium text-accent hover:underline\"\n >\n View all\n </button>\n }\n >\n {discussionsLoading ? (\n <LoadingView label=\"Loading discussions…\" className=\"min-h-[8rem]\" />\n ) : discussions.length === 0 ? (\n <EmptyState\n icon={<MessagesSquare className=\"h-8 w-8\" />}\n title=\"No discussions yet\"\n description=\"Open a discussion to invite perspectives on this story.\"\n action={\n <Button size=\"sm\" variant=\"outline\" onClick={onOpenDiscussion}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Open discussion\n </Button>\n }\n />\n ) : (\n <div className=\"flex flex-col gap-3\">\n {discussions.slice(0, 5).map((discussion) => (\n <LinkedDiscussion\n key={discussion.id}\n discussion={discussion}\n onOpen={() => onOpenDiscussionItem(discussion)}\n />\n ))}\n </div>\n )}\n </RailPanel>\n </aside>\n </div>\n );\n}\n\nfunction RailPanel({\n title,\n action,\n children,\n}: {\n title: string;\n action?: ReactNode;\n children: ReactNode;\n}) {\n return (\n <section>\n <div className=\"mb-3 flex items-center justify-between gap-2\">\n <h2 className=\"font-display text-lg font-semibold text-text-primary\">{title}</h2>\n {action}\n </div>\n {children}\n </section>\n );\n}\n\nfunction StoryBody({ body }: { body?: string | null }) {\n const paragraphs = useMemo(\n () =>\n (body ?? '')\n .split(/\\n{2,}/)\n .map((p) => p.trim())\n .filter(Boolean),\n [body]\n );\n\n if (paragraphs.length === 0) {\n return (\n <p className=\"rounded-xl border border-dashed border-border-seam px-4 py-10 text-center text-sm text-text-tertiary\">\n This story has no body yet. Use Edit to write it.\n </p>\n );\n }\n\n return (\n <div className=\"max-w-prose\">\n {paragraphs.map((paragraph, index) => (\n <Fragment key={index}>\n {index === 1 && <DecorativeDivider />}\n <p\n className={cn(\n 'text-[1.05rem] leading-8 text-text-primary',\n index > 0 && index !== 1 && 'mt-5',\n index === 0 &&\n 'first-letter:float-left first-letter:mr-3 first-letter:mt-1 first-letter:font-display first-letter:text-6xl first-letter:font-semibold first-letter:leading-[0.72] first-letter:text-accent'\n )}\n >\n {paragraph}\n </p>\n </Fragment>\n ))}\n </div>\n );\n}\n\nfunction LinkedDiscussion({\n discussion,\n onOpen,\n}: {\n discussion: TcpDiscussion;\n onOpen: () => void;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"w-full rounded-xl border border-border-seam bg-bg-surface p-3 text-left transition-colors hover:border-border-strong\"\n >\n <div className=\"flex items-start gap-2.5\">\n <span\n className=\"grid h-8 w-8 shrink-0 place-items-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\"\n aria-hidden=\"true\"\n >\n <MessagesSquare className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{discussion.title}</p>\n {discussion.prompt && (\n <p className=\"mt-0.5 line-clamp-2 text-xs text-text-tertiary\">{discussion.prompt}</p>\n )}\n <div className=\"mt-1.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-text-tertiary\">\n <span>\n {formatNumber(discussion.replyCount)}{' '}\n {discussion.replyCount === 1 ? 'reply' : 'replies'}\n </span>\n <span aria-hidden=\"true\">·</span>\n <span>{formatRelativeTime(discussion.createdAt)}</span>\n {discussion.isInterfaith && (\n <StatusBadge\n status=\"Interfaith\"\n icon={<Sparkles className=\"h-3 w-3\" />}\n className=\"ml-0.5\"\n />\n )}\n {discussion.isLocked && (\n <span className=\"inline-flex items-center gap-1 text-text-tertiary\">\n <Lock className=\"h-3 w-3\" aria-hidden=\"true\" /> Locked\n </span>\n )}\n </div>\n </div>\n </div>\n </button>\n );\n}\n\n// ===========================================================================\n// Editorial view (tcp-04)\n// ===========================================================================\n\nfunction EditorialView({ story, onAddCitation }: { story: TcpStory; onAddCitation: () => void }) {\n const transition = useTcpTransitionStory();\n const nextStatuses = NEXT_STATUSES[story.status] ?? [];\n\n const doTransition = async (status: TcpStoryStatus) => {\n try {\n await transition.mutateAsync({ id: story.id, status });\n notify.success('Story updated', `Moved to ${formatEnumLabel(status)}`);\n } catch (err) {\n notify.error('Could not update the story', describeError(err));\n }\n };\n\n return (\n <div className=\"flex flex-col gap-6\">\n {/* Lifecycle */}\n <GlassCard treatment=\"plain\" className=\"p-5 sm:p-6\">\n <div className=\"flex items-center gap-2.5\">\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 <GitBranch className=\"h-5 w-5\" />\n </span>\n <h2 className=\"font-display text-xl font-semibold text-text-primary\">\n Editorial lifecycle\n </h2>\n </div>\n\n <LifecycleStepper status={story.status} className=\"mt-6\" />\n\n <div className=\"mt-6 flex flex-col gap-4 border-t border-border-seam pt-5 md:flex-row md:items-center md:justify-between\">\n {nextStatuses.length > 0 ? (\n <div className=\"flex flex-wrap gap-2\">\n {nextStatuses.map((status) => {\n const meta = TRANSITION_META[status];\n const Icon = meta.icon;\n return (\n <Button\n key={status}\n variant={meta.primary ? 'default' : 'outline'}\n onClick={() => doTransition(status)}\n disabled={transition.isPending}\n >\n <Icon className=\"mr-1.5 h-4 w-4\" aria-hidden=\"true\" />\n {meta.label}\n </Button>\n );\n })}\n </div>\n ) : (\n <p className=\"text-sm text-text-tertiary\">This story is at the end of its lifecycle.</p>\n )}\n\n <p className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <ShieldCheck className=\"h-4 w-4 shrink-0 text-text-tertiary\" aria-hidden=\"true\" />\n Reviewed with fact and sensitivity care before publishing.\n </p>\n </div>\n </GlassCard>\n\n {/* Citations */}\n <GlassCard treatment=\"plain\" className=\"p-5 sm:p-6\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2.5\">\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 <Scroll className=\"h-5 w-5\" />\n </span>\n <div>\n <h2 className=\"font-display text-xl font-semibold text-text-primary\">Citations</h2>\n <p className=\"text-sm text-text-secondary\">\n Verifiable sources that ground this story.\n </p>\n </div>\n </div>\n <Button variant=\"outline\" onClick={onAddCitation}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Add citation\n </Button>\n </div>\n\n <EditorialCitationsTable storyId={story.id} className=\"mt-5\" />\n\n <p className=\"mt-4 flex items-center gap-2 border-t border-border-seam pt-4 text-xs text-text-tertiary\">\n <ShieldCheck className=\"h-3.5 w-3.5 shrink-0\" aria-hidden=\"true\" />\n All sources are evaluated for accuracy, relevance, and cultural sensitivity.\n </p>\n </GlassCard>\n </div>\n );\n}\n\nfunction EditorialCitationsTable({ storyId, className }: { storyId: string; className?: string }) {\n const { data: citations, isLoading, isError, refetch } = useTcpCitations(storyId);\n\n const columns: ResponsiveTableColumn<TcpCitation>[] = [\n {\n key: 'source',\n header: 'Source',\n priority: 'primary',\n cell: (citation) => {\n const Icon = sourceTypeIcon(citation.sourceType);\n const meta = [citation.author, citation.publisher].filter((v) => v && v.trim()).join(' · ');\n return (\n <div className=\"flex min-w-0 items-start gap-3\">\n <span\n className=\"grid h-9 w-9 shrink-0 place-items-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\"\n aria-hidden=\"true\"\n >\n <Icon className=\"h-4 w-4\" />\n </span>\n <div className=\"min-w-0\">\n <p className=\"font-medium text-text-primary\">{citation.title}</p>\n {citation.excerpt && (\n <p className=\"mt-0.5 line-clamp-1 text-xs italic text-text-tertiary\">\n {citation.excerpt}\n </p>\n )}\n {meta && <p className=\"mt-0.5 text-xs text-text-tertiary\">{meta}</p>}\n </div>\n </div>\n );\n },\n },\n {\n key: 'type',\n header: 'Type',\n cell: (citation) => (\n <StatusBadge\n status={citation.sourceType}\n icon={(() => {\n const Icon = sourceTypeIcon(citation.sourceType);\n return <Icon className=\"h-3 w-3\" />;\n })()}\n />\n ),\n },\n {\n key: 'added',\n header: 'Added on',\n priority: 'hidden-on-mobile',\n cell: (citation) => (\n <span className=\"whitespace-nowrap text-sm text-text-secondary\">\n {formatDate(citation.createdAt)}\n </span>\n ),\n },\n {\n key: 'verification',\n header: 'Status',\n cell: (citation) => {\n const meta = VERIFICATION_META[citation.verification];\n const Icon = meta.icon;\n return (\n <StatusBadge\n status={citation.verification}\n icon={<Icon className={cn('h-3 w-3', verificationIconClass(citation.verification))} />}\n />\n );\n },\n },\n {\n key: 'actions',\n header: 'Actions',\n headerClassName: 'text-right',\n cellClassName: 'text-right',\n cell: (citation) => <EditorialCitationActions citation={citation} />,\n },\n ];\n\n if (isLoading) return <LoadingView label=\"Loading citations…\" className={className} />;\n if (isError)\n return (\n <div className={className}>\n <ErrorView message=\"We couldn't load citations.\" onRetry={() => refetch()} />\n </div>\n );\n\n return (\n <ResponsiveTable<TcpCitation>\n className={className}\n columns={columns}\n data={citations ?? []}\n rowKey={(citation) => citation.id}\n emptyState={\n <EmptyState\n icon={<Scroll 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}\n\nfunction EditorialCitationActions({ citation }: { citation: TcpCitation }) {\n const verify = useTcpVerifyCitation();\n\n const change = 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 return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled={verify.isPending}\n aria-label={`Change verification for ${citation.title}`}\n >\n Verify <ChevronDown className=\"ml-1 h-4 w-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {VERIFICATIONS.map((status) => {\n const meta = VERIFICATION_META[status];\n const Icon = meta.icon;\n const current = status === citation.verification;\n return (\n <DropdownMenuItem\n key={status}\n onSelect={() => change(status)}\n className={cn('gap-2', current && 'font-semibold')}\n >\n <Icon className={cn('h-4 w-4', verificationIconClass(status))} aria-hidden=\"true\" />\n {meta.label}\n </DropdownMenuItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\n// ===========================================================================\n// Edit story dialog (local — only used here)\n// ===========================================================================\n\nconst FORMATS: TcpStoryFormat[] = [\n 'ARTICLE',\n 'ESSAY',\n 'EXPLAINER',\n 'ORAL_HISTORY',\n 'PHOTO_STORY',\n 'TIMELINE',\n];\n\nfunction EditStoryDialog({\n open,\n onOpenChange,\n story,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n story: TcpStory;\n}) {\n const updateStory = useTcpUpdateStory();\n const topicsQuery = useTcpTopics({ pagination: { limit: 100 } });\n\n const [title, setTitle] = useState(story.title);\n const [summary, setSummary] = useState(story.summary ?? '');\n const [body, setBody] = useState(story.body ?? '');\n const [format, setFormat] = useState<TcpStoryFormat>(story.format);\n const [pickedTopic, setPickedTopic] = useState(story.topicId ?? '');\n const [languages, setLanguages] = useState<string[]>(story.languages);\n const [tags, setTags] = useState<string[]>(story.tags);\n const [readingMins, setReadingMins] = useState(\n story.readingMins ? String(story.readingMins) : ''\n );\n const [coverFileId, setCoverFileId] = useState<string | null>(story.cover?.id ?? null);\n const [error, setError] = useState<string | null>(null);\n\n // Reset local state whenever a different story is opened for editing.\n const storyKey = useMemo(() => `${story.id}:${story.updatedAt}`, [story.id, story.updatedAt]);\n const [seededKey, setSeededKey] = useState(storyKey);\n if (seededKey !== storyKey) {\n setSeededKey(storyKey);\n setTitle(story.title);\n setSummary(story.summary ?? '');\n setBody(story.body ?? '');\n setFormat(story.format);\n setPickedTopic(story.topicId ?? '');\n setLanguages(story.languages);\n setTags(story.tags);\n setReadingMins(story.readingMins ? String(story.readingMins) : '');\n setCoverFileId(story.cover?.id ?? null);\n setError(null);\n }\n\n const submit = async () => {\n if (!title.trim()) {\n setError('A title is required.');\n return;\n }\n try {\n await updateStory.mutateAsync({\n id: story.id,\n input: {\n title: title.trim(),\n summary: summary.trim() || null,\n body: body.trim() || null,\n format,\n topicId: pickedTopic || null,\n languages,\n tags,\n readingMins: readingMins ? Number(readingMins) : null,\n coverFileId,\n },\n });\n notify.success('Story updated', title.trim());\n onOpenChange(false);\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>Edit story</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Refine the story. The URL slug is fixed once created.\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 <FileUploadField\n folder={FILE_FOLDERS.covers}\n accept=\"image/*\"\n label=\"Upload cover\"\n fileId={coverFileId}\n onUploaded={setCoverFileId}\n onCleared={() => setCoverFileId(null)}\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"edit-title\">Title</Label>\n <Input id=\"edit-title\" value={title} onChange={(e) => setTitle(e.target.value)} />\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"grid gap-1.5\">\n <Label>Format</Label>\n <Select value={format} onValueChange={(v) => setFormat(v as TcpStoryFormat)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {FORMATS.map((f) => (\n <SelectItem key={f} value={f}>\n {formatEnumLabel(f)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"edit-reading\">Reading time (min)</Label>\n <Input\n id=\"edit-reading\"\n type=\"number\"\n min={0}\n value={readingMins}\n onChange={(e) => setReadingMins(e.target.value)}\n />\n </div>\n </div>\n <div className=\"grid gap-1.5\">\n <Label>Topic</Label>\n <Select value={pickedTopic} onValueChange={setPickedTopic}>\n <SelectTrigger>\n <SelectValue placeholder=\"Choose a topic (optional)\" />\n </SelectTrigger>\n <SelectContent>\n {(topicsQuery.data?.items ?? []).map((topic) => (\n <SelectItem key={topic.id} value={topic.id}>\n {topic.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"edit-summary\">Summary</Label>\n <Textarea\n id=\"edit-summary\"\n value={summary}\n onChange={(e) => setSummary(e.target.value)}\n rows={2}\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"edit-body\">Body</Label>\n <Textarea\n id=\"edit-body\"\n value={body}\n onChange={(e) => setBody(e.target.value)}\n rows={6}\n />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"edit-langs\">Languages</Label>\n <TagInput id=\"edit-langs\" value={languages} onChange={setLanguages} preserveCase />\n </div>\n <div className=\"grid gap-1.5\">\n <Label htmlFor=\"edit-tags\">Tags</Label>\n <TagInput id=\"edit-tags\" value={tags} onChange={setTags} />\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={updateStory.isPending}>\n Save changes\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,162 @@
1
+ import { useTheCulturePost as e } from "../../context/TheCulturePostContext.js";
2
+ import "../../context/index.js";
3
+ import { PageHero as t } from "../../components/PageHero.js";
4
+ import { ErrorView as n, LoadingView as r } from "../../components/StateViews.js";
5
+ import { formatEnumLabel as i } from "../../utils/formatters.js";
6
+ import { EmptyState as a } from "../../components/EmptyState.js";
7
+ import { useTcpArchiveItems as o } from "../../hooks/useTcpApi.js";
8
+ import "../../hooks/index.js";
9
+ import { KIND_ICON as s } from "../../components/kindIcon.js";
10
+ import { FilterTabs as c } from "../../components/FilterTabs.js";
11
+ import { HistoryTimeline as l } from "../../components/HistoryTimeline.js";
12
+ import "../../components/index.js";
13
+ import { createElement as u, useMemo as d, useState as f } from "react";
14
+ import { Info as p, Plus as m } from "lucide-react";
15
+ import { jsx as h, jsxs as g } from "react/jsx-runtime";
16
+ import { Button as _, Select as v, SelectContent as y, SelectItem as b, SelectTrigger as x, SelectValue as S } from "@burdenoff/fe-libs/ui";
17
+ //#region src/theculturepost/pages/timeline/TimelinePage.tsx
18
+ var C = 100, w = [
19
+ "ANCIENT",
20
+ "MEDIEVAL",
21
+ "EARLY_MODERN",
22
+ "MODERN",
23
+ "CONTEMPORARY"
24
+ ], T = {
25
+ ANCIENT: "Ancient",
26
+ MEDIEVAL: "Medieval",
27
+ EARLY_MODERN: "Early Modern",
28
+ MODERN: "Modern",
29
+ CONTEMPORARY: "Contemporary"
30
+ };
31
+ function E(e) {
32
+ return e < 500 ? "ANCIENT" : e < 1500 ? "MEDIEVAL" : e < 1800 ? "EARLY_MODERN" : e < 2e3 ? "MODERN" : "CONTEMPORARY";
33
+ }
34
+ function D(e) {
35
+ let t = e.getUTCFullYear();
36
+ return t < 1 ? `${1 - t} BCE` : `${t} CE`;
37
+ }
38
+ var O = [
39
+ "MANUSCRIPT",
40
+ "PHOTOGRAPH",
41
+ "AUDIO",
42
+ "VIDEO",
43
+ "MAP",
44
+ "OBJECT",
45
+ "DOCUMENT"
46
+ ];
47
+ function k() {
48
+ let { navigateTo: k } = e(), [A, j] = f("ALL"), [M, N] = f("ALL"), { data: P, isLoading: F, isError: I, refetch: L } = o({
49
+ kind: M === "ALL" ? void 0 : M,
50
+ pagination: { limit: C }
51
+ }), R = d(() => P?.items ?? [], [P]), z = d(() => {
52
+ let e = [];
53
+ for (let t of R) {
54
+ if (!t.datedAt) continue;
55
+ let n = new Date(t.datedAt);
56
+ Number.isNaN(n.getTime()) || e.push({
57
+ item: t,
58
+ date: n,
59
+ era: E(n.getUTCFullYear())
60
+ });
61
+ }
62
+ return e.sort((e, t) => e.date.getTime() - t.date.getTime());
63
+ }, [R]), B = d(() => {
64
+ let e = new Set(z.map((e) => e.era));
65
+ return [{
66
+ value: "ALL",
67
+ label: "All eras"
68
+ }, ...w.filter((t) => e.has(t)).map((e) => ({
69
+ value: e,
70
+ label: T[e]
71
+ }))];
72
+ }, [z]), V = A !== "ALL" && !z.some((e) => e.era === A) ? "ALL" : A, H = d(() => V === "ALL" ? z : z.filter((e) => e.era === V), [z, V]), U = d(() => H.map(({ item: e, date: t }) => ({
73
+ id: e.id,
74
+ date: D(t),
75
+ title: e.title,
76
+ subtitle: e.description ?? e.origin ?? void 0,
77
+ kind: i(e.kind),
78
+ icon: s[e.kind],
79
+ onOpen: () => k(`archive/items/${e.id}`)
80
+ })), [H, k]);
81
+ return /* @__PURE__ */ h("div", {
82
+ className: "h-full overflow-y-auto",
83
+ children: /* @__PURE__ */ g("div", {
84
+ className: "mx-auto flex max-w-6xl flex-col gap-6 p-4 sm:p-6",
85
+ children: [
86
+ /* @__PURE__ */ h(t, {
87
+ eyebrow: "Chronology",
88
+ title: "Timeline",
89
+ description: "Key moments, ideas and cultural milestones — arranged in time from the dated material held in the archive.",
90
+ actions: /* @__PURE__ */ g(_, {
91
+ variant: "outline",
92
+ onClick: () => k("archive"),
93
+ children: [/* @__PURE__ */ h(m, { className: "mr-1.5 h-4 w-4" }), " Add to archive"]
94
+ })
95
+ }),
96
+ /* @__PURE__ */ g("div", {
97
+ className: "flex items-start gap-2 rounded-xl border border-border-seam bg-bg-surface p-3 text-sm text-text-secondary",
98
+ children: [/* @__PURE__ */ h(p, {
99
+ className: "mt-0.5 h-4 w-4 shrink-0 text-text-tertiary",
100
+ "aria-hidden": "true"
101
+ }), /* @__PURE__ */ h("p", { children: "This is a chronology of dated material in the archive. Only items that carry a recorded date appear here, ordered by that date — nothing is inferred or reconstructed." })]
102
+ }),
103
+ /* @__PURE__ */ g("div", {
104
+ className: "flex flex-wrap items-center gap-3",
105
+ children: [/* @__PURE__ */ h(c, {
106
+ options: B,
107
+ value: V,
108
+ onChange: j
109
+ }), /* @__PURE__ */ g(v, {
110
+ value: M,
111
+ onValueChange: (e) => {
112
+ N(e), j("ALL");
113
+ },
114
+ children: [/* @__PURE__ */ h(x, {
115
+ className: "w-[12rem]",
116
+ "aria-label": "Filter by material kind",
117
+ children: /* @__PURE__ */ h(S, { placeholder: "All kinds" })
118
+ }), /* @__PURE__ */ g(y, { children: [/* @__PURE__ */ h(b, {
119
+ value: "ALL",
120
+ children: "All kinds"
121
+ }), O.map((e) => /* @__PURE__ */ h(b, {
122
+ value: e,
123
+ children: i(e)
124
+ }, e))] })]
125
+ })]
126
+ }),
127
+ F ? /* @__PURE__ */ h(r, { label: "Loading the timeline…" }) : I ? /* @__PURE__ */ h(n, {
128
+ message: "We couldn't load the timeline.",
129
+ onRetry: () => L()
130
+ }) : z.length === 0 ? /* @__PURE__ */ h(a, {
131
+ illustration: "empty-data",
132
+ icon: u(p, { className: "h-10 w-10" }),
133
+ title: M === "ALL" ? "Nothing dated yet" : "No dated material of this kind",
134
+ description: "Only archive items with a recorded date appear on the timeline. Add a date to an archive item to place it here.",
135
+ action: /* @__PURE__ */ h(_, {
136
+ onClick: () => k("archive"),
137
+ children: "Open archive"
138
+ })
139
+ }) : H.length === 0 ? /* @__PURE__ */ h(a, {
140
+ icon: u(p, { className: "h-9 w-9" }),
141
+ title: "No material in this era",
142
+ description: "Try another era, or clear the filter to see the full chronology.",
143
+ action: /* @__PURE__ */ h(_, {
144
+ variant: "outline",
145
+ onClick: () => j("ALL"),
146
+ children: "Show all eras"
147
+ })
148
+ }) : /* @__PURE__ */ g("div", {
149
+ className: "flex flex-col gap-3",
150
+ children: [/* @__PURE__ */ h("p", {
151
+ className: "text-sm text-text-tertiary",
152
+ children: H.length === z.length ? `${z.length} dated ${z.length === 1 ? "item" : "items"}` : `${H.length} of ${z.length} dated items`
153
+ }), /* @__PURE__ */ h(l, { entries: U })]
154
+ })
155
+ ]
156
+ })
157
+ });
158
+ }
159
+ //#endregion
160
+ export { k as TimelinePage };
161
+
162
+ //# sourceMappingURL=TimelinePage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimelinePage.js","names":[],"sources":["../../../../src/theculturepost/pages/timeline/TimelinePage.tsx"],"sourcesContent":["/**\n * TimelinePage — a data-honest chronology of dated archive material.\n * @module theculturepost/pages/timeline\n *\n * The schema has no dedicated \"historical event\" entity, so this timeline is\n * built strictly from REAL archive items that carry a recorded `datedAt`\n * (`tcpListArchiveItems`). Items without a date are excluded; the rest are\n * ordered chronologically by that date and rendered on the foundation\n * {@link HistoryTimeline}. Era labels are derived from the item's own year (a\n * documented bucketing of real data), never invented. Each entry links to the\n * archive-item detail.\n *\n * NOTE: this is a NEW page — it exports {@link TimelinePage} only. Route/nav\n * registration is owned by the integration step (do not wire it here).\n */\n\nimport { createElement, useMemo, useState } from 'react';\nimport { Info, Plus } from 'lucide-react';\nimport {\n Button,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@burdenoff/fe-libs/ui';\nimport {\n PageHero,\n FilterTabs,\n type FilterOption,\n HistoryTimeline,\n type TimelineEntry,\n EmptyState,\n LoadingView,\n ErrorView,\n KIND_ICON,\n} from '../../components';\nimport { useTcpArchiveItems } from '../../hooks';\nimport { useTheCulturePost } from '../../context';\nimport { formatEnumLabel } from '../../utils/formatters';\nimport type { TcpArchiveItem, TcpArchiveItemKind } from '../../types';\n\n/** Enough dated material for an overview chronology in a single read. */\nconst FETCH_LIMIT = 100;\n\n// ---------------------------------------------------------------------------\n// Era bucketing — a documented mapping of a real year onto a coarse era. The\n// year comes from the item's own `datedAt`; only the label is derived.\n// ---------------------------------------------------------------------------\n\ntype Era = 'ANCIENT' | 'MEDIEVAL' | 'EARLY_MODERN' | 'MODERN' | 'CONTEMPORARY';\n\nconst ERA_ORDER: Era[] = ['ANCIENT', 'MEDIEVAL', 'EARLY_MODERN', 'MODERN', 'CONTEMPORARY'];\n\nconst ERA_LABEL: Record<Era, string> = {\n ANCIENT: 'Ancient',\n MEDIEVAL: 'Medieval',\n EARLY_MODERN: 'Early Modern',\n MODERN: 'Modern',\n CONTEMPORARY: 'Contemporary',\n};\n\nfunction eraOf(year: number): Era {\n if (year < 500) return 'ANCIENT';\n if (year < 1500) return 'MEDIEVAL';\n if (year < 1800) return 'EARLY_MODERN';\n if (year < 2000) return 'MODERN';\n return 'CONTEMPORARY';\n}\n\n/** Verbatim year label from a real date (astronomical year 0 → 1 BCE). */\nfunction yearLabel(date: Date): string {\n const y = date.getUTCFullYear();\n return y < 1 ? `${1 - y} BCE` : `${y} CE`;\n}\n\ntype EraFilter = 'ALL' | Era;\ntype KindFilter = 'ALL' | TcpArchiveItemKind;\n\nconst KINDS: TcpArchiveItemKind[] = [\n 'MANUSCRIPT',\n 'PHOTOGRAPH',\n 'AUDIO',\n 'VIDEO',\n 'MAP',\n 'OBJECT',\n 'DOCUMENT',\n];\n\ninterface DatedItem {\n item: TcpArchiveItem;\n date: Date;\n era: Era;\n}\n\nexport function TimelinePage() {\n const { navigateTo } = useTheCulturePost();\n const [era, setEra] = useState<EraFilter>('ALL');\n const [kind, setKind] = useState<KindFilter>('ALL');\n\n const { data, isLoading, isError, refetch } = useTcpArchiveItems({\n kind: kind === 'ALL' ? undefined : kind,\n pagination: { limit: FETCH_LIMIT },\n });\n\n const items = useMemo(() => data?.items ?? [], [data]);\n\n // Keep only items with a real, parseable date; sort ascending (chronological).\n const dated = useMemo<DatedItem[]>(() => {\n const parsed: DatedItem[] = [];\n for (const item of items) {\n if (!item.datedAt) continue;\n const date = new Date(item.datedAt);\n if (Number.isNaN(date.getTime())) continue;\n parsed.push({ item, date, era: eraOf(date.getUTCFullYear()) });\n }\n return parsed.sort((a, b) => a.date.getTime() - b.date.getTime());\n }, [items]);\n\n // Only offer era pills that actually have dated items, in chronological order.\n const eraOptions = useMemo<FilterOption<EraFilter>[]>(() => {\n const present = new Set(dated.map((d) => d.era));\n const eras = ERA_ORDER.filter((e) => present.has(e));\n return [\n { value: 'ALL', label: 'All eras' },\n ...eras.map((e) => ({ value: e, label: ERA_LABEL[e] })),\n ];\n }, [dated]);\n\n // If the active era is no longer represented (e.g. after a kind change), the\n // pill disappears — fall back to showing every era so nothing looks \"empty\".\n const effectiveEra: EraFilter = era !== 'ALL' && !dated.some((d) => d.era === era) ? 'ALL' : era;\n\n const visible = useMemo(\n () => (effectiveEra === 'ALL' ? dated : dated.filter((d) => d.era === effectiveEra)),\n [dated, effectiveEra]\n );\n\n const entries = useMemo<TimelineEntry[]>(\n () =>\n visible.map(({ item, date }) => ({\n id: item.id,\n date: yearLabel(date),\n title: item.title,\n subtitle: item.description ?? item.origin ?? undefined,\n kind: formatEnumLabel(item.kind),\n icon: KIND_ICON[item.kind],\n onOpen: () => navigateTo(`archive/items/${item.id}`),\n })),\n [visible, navigateTo]\n );\n\n const changeKind = (next: string) => {\n setKind(next as KindFilter);\n setEra('ALL');\n };\n\n return (\n <div className=\"h-full overflow-y-auto\">\n <div className=\"mx-auto flex max-w-6xl flex-col gap-6 p-4 sm:p-6\">\n <PageHero\n eyebrow=\"Chronology\"\n title=\"Timeline\"\n description=\"Key moments, ideas and cultural milestones — arranged in time from the dated material held in the archive.\"\n actions={\n <Button variant=\"outline\" onClick={() => navigateTo('archive')}>\n <Plus className=\"mr-1.5 h-4 w-4\" /> Add to archive\n </Button>\n }\n />\n\n <div className=\"flex items-start gap-2 rounded-xl border border-border-seam bg-bg-surface p-3 text-sm text-text-secondary\">\n <Info className=\"mt-0.5 h-4 w-4 shrink-0 text-text-tertiary\" aria-hidden=\"true\" />\n <p>\n This is a chronology of dated material in the archive. Only items that carry a recorded\n date appear here, ordered by that date — nothing is inferred or reconstructed.\n </p>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-3\">\n <FilterTabs options={eraOptions} value={effectiveEra} onChange={setEra} />\n <Select value={kind} onValueChange={changeKind}>\n <SelectTrigger className=\"w-[12rem]\" aria-label=\"Filter by material kind\">\n <SelectValue placeholder=\"All kinds\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All kinds</SelectItem>\n {KINDS.map((k) => (\n <SelectItem key={k} value={k}>\n {formatEnumLabel(k)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {isLoading ? (\n <LoadingView label=\"Loading the timeline…\" />\n ) : isError ? (\n <ErrorView message=\"We couldn't load the timeline.\" onRetry={() => refetch()} />\n ) : dated.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={createElement(Info, { className: 'h-10 w-10' })}\n title={kind === 'ALL' ? 'Nothing dated yet' : 'No dated material of this kind'}\n description=\"Only archive items with a recorded date appear on the timeline. Add a date to an archive item to place it here.\"\n action={<Button onClick={() => navigateTo('archive')}>Open archive</Button>}\n />\n ) : visible.length === 0 ? (\n <EmptyState\n icon={createElement(Info, { className: 'h-9 w-9' })}\n title=\"No material in this era\"\n description=\"Try another era, or clear the filter to see the full chronology.\"\n action={\n <Button variant=\"outline\" onClick={() => setEra('ALL')}>\n Show all eras\n </Button>\n }\n />\n ) : (\n <div className=\"flex flex-col gap-3\">\n <p className=\"text-sm text-text-tertiary\">\n {visible.length === dated.length\n ? `${dated.length} dated ${dated.length === 1 ? 'item' : 'items'}`\n : `${visible.length} of ${dated.length} dated items`}\n </p>\n <HistoryTimeline entries={entries} />\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA2CA,IAAM,IAAc,KASd,IAAmB;CAAC;CAAW;CAAY;CAAgB;CAAU;CAAe,EAEpF,IAAiC;CACrC,SAAS;CACT,UAAU;CACV,cAAc;CACd,QAAQ;CACR,cAAc;CACf;AAED,SAAS,EAAM,GAAmB;AAKhC,QAJI,IAAO,MAAY,YACnB,IAAO,OAAa,aACpB,IAAO,OAAa,iBACpB,IAAO,MAAa,WACjB;;AAIT,SAAS,EAAU,GAAoB;CACrC,IAAM,IAAI,EAAK,gBAAgB;AAC/B,QAAO,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,GAAG,EAAE;;AAMvC,IAAM,IAA8B;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAQD,SAAgB,IAAe;CAC7B,IAAM,EAAE,kBAAe,GAAmB,EACpC,CAAC,GAAK,KAAU,EAAoB,MAAM,EAC1C,CAAC,GAAM,KAAW,EAAqB,MAAM,EAE7C,EAAE,SAAM,cAAW,YAAS,eAAY,EAAmB;EAC/D,MAAM,MAAS,QAAQ,KAAA,IAAY;EACnC,YAAY,EAAE,OAAO,GAAa;EACnC,CAAC,EAEI,IAAQ,QAAc,GAAM,SAAS,EAAE,EAAE,CAAC,EAAK,CAAC,EAGhD,IAAQ,QAA2B;EACvC,IAAM,IAAsB,EAAE;AAC9B,OAAK,IAAM,KAAQ,GAAO;AACxB,OAAI,CAAC,EAAK,QAAS;GACnB,IAAM,IAAO,IAAI,KAAK,EAAK,QAAQ;AAC/B,UAAO,MAAM,EAAK,SAAS,CAAC,IAChC,EAAO,KAAK;IAAE;IAAM;IAAM,KAAK,EAAM,EAAK,gBAAgB,CAAC;IAAE,CAAC;;AAEhE,SAAO,EAAO,MAAM,GAAG,MAAM,EAAE,KAAK,SAAS,GAAG,EAAE,KAAK,SAAS,CAAC;IAChE,CAAC,EAAM,CAAC,EAGL,IAAa,QAAyC;EAC1D,IAAM,IAAU,IAAI,IAAI,EAAM,KAAK,MAAM,EAAE,IAAI,CAAC;AAEhD,SAAO,CACL;GAAE,OAAO;GAAO,OAAO;GAAY,EACnC,GAHW,EAAU,QAAQ,MAAM,EAAQ,IAAI,EAAE,CAAC,CAG1C,KAAK,OAAO;GAAE,OAAO;GAAG,OAAO,EAAU;GAAI,EAAE,CACxD;IACA,CAAC,EAAM,CAAC,EAIL,IAA0B,MAAQ,SAAS,CAAC,EAAM,MAAM,MAAM,EAAE,QAAQ,EAAI,GAAG,QAAQ,GAEvF,IAAU,QACP,MAAiB,QAAQ,IAAQ,EAAM,QAAQ,MAAM,EAAE,QAAQ,EAAa,EACnF,CAAC,GAAO,EAAa,CACtB,EAEK,IAAU,QAEZ,EAAQ,KAAK,EAAE,SAAM,eAAY;EAC/B,IAAI,EAAK;EACT,MAAM,EAAU,EAAK;EACrB,OAAO,EAAK;EACZ,UAAU,EAAK,eAAe,EAAK,UAAU,KAAA;EAC7C,MAAM,EAAgB,EAAK,KAAK;EAChC,MAAM,EAAU,EAAK;EACrB,cAAc,EAAW,iBAAiB,EAAK,KAAK;EACrD,EAAE,EACL,CAAC,GAAS,EAAW,CACtB;AAOD,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD;KACE,SAAQ;KACR,OAAM;KACN,aAAY;KACZ,SACE,kBAAC,GAAD;MAAQ,SAAQ;MAAU,eAAe,EAAW,UAAU;gBAA9D,CACE,kBAAC,GAAD,EAAM,WAAU,kBAAmB,CAAA,EAAA,kBAC5B;;KAEX,CAAA;IAEF,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAM,WAAU;MAA6C,eAAY;MAAS,CAAA,EAClF,kBAAC,KAAD,EAAA,UAAG,0KAGC,CAAA,CACA;;IAEN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAY,SAAS;MAAY,OAAO;MAAc,UAAU;MAAU,CAAA,EAC1E,kBAAC,GAAD;MAAQ,OAAO;MAAM,gBA7BT,MAAiB;AAEnC,OADA,EAAQ,EAAmB,EAC3B,EAAO,MAAM;;gBA2BP,CACE,kBAAC,GAAD;OAAe,WAAU;OAAY,cAAW;iBAC9C,kBAAC,GAAD,EAAa,aAAY,aAAc,CAAA;OACzB,CAAA,EAChB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;OAAY,OAAM;iBAAM;OAAsB,CAAA,EAC7C,EAAM,KAAK,MACV,kBAAC,GAAD;OAAoB,OAAO;iBACxB,EAAgB,EAAE;OACR,EAFI,EAEJ,CACb,CACY,EAAA,CAAA,CACT;QACL;;IAEL,IACC,kBAAC,GAAD,EAAa,OAAM,yBAA0B,CAAA,GAC3C,IACF,kBAAC,GAAD;KAAW,SAAQ;KAAiC,eAAe,GAAS;KAAI,CAAA,GAC9E,EAAM,WAAW,IACnB,kBAAC,GAAD;KACE,cAAa;KACb,MAAM,EAAc,GAAM,EAAE,WAAW,aAAa,CAAC;KACrD,OAAO,MAAS,QAAQ,sBAAsB;KAC9C,aAAY;KACZ,QAAQ,kBAAC,GAAD;MAAQ,eAAe,EAAW,UAAU;gBAAE;MAAqB,CAAA;KAC3E,CAAA,GACA,EAAQ,WAAW,IACrB,kBAAC,GAAD;KACE,MAAM,EAAc,GAAM,EAAE,WAAW,WAAW,CAAC;KACnD,OAAM;KACN,aAAY;KACZ,QACE,kBAAC,GAAD;MAAQ,SAAQ;MAAU,eAAe,EAAO,MAAM;gBAAE;MAE/C,CAAA;KAEX,CAAA,GAEF,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAQ,WAAW,EAAM,SACtB,GAAG,EAAM,OAAO,SAAS,EAAM,WAAW,IAAI,SAAS,YACvD,GAAG,EAAQ,OAAO,MAAM,EAAM,OAAO;MACvC,CAAA,EACJ,kBAAC,GAAD,EAA0B,YAAW,CAAA,CACjC;;IAEJ;;EACF,CAAA"}