@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.
- 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/hooks/useFiles.js +1 -1
- package/dist/theculturepost/hooks/useFiles.js.map +1 -1
- 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFiles.js","names":[],"sources":["../../../src/theculturepost/hooks/useFiles.ts"],"sourcesContent":["/**\n * File hooks — covers, artifacts & recordings via wspace-files-svc (NO duplication).\n * @module theculturepost/hooks\n *\n * TheCulturePost never stores blobs. Stories keep `coverFileId`, archive items\n * keep `fileId`, citations keep `sourceFileId`, oral histories keep\n * `recordingFileId` — all pointing at files owned by wspace-files-svc. Upload\n * goes through the shared `uploadBlobToFiles` storage helper (presigned 3-step\n * upload) against the workspace Apollo client the shell initialises; display\n * resolves a file id to a presigned URL via `getFileDownloadUrl`.\n */\n\nimport { useQuery } from '@tanstack/react-query';\nimport { graphqlFetch, getWorkspaceClient, gql } from '@burdenoff/fe-libs/shared/graphql';\nimport { uploadBlobToFiles } from '@burdenoff/fe-libs/storage';\n\nimport { useTheCulturePost } from '../context';\n\n
|
|
1
|
+
{"version":3,"file":"useFiles.js","names":[],"sources":["../../../src/theculturepost/hooks/useFiles.ts"],"sourcesContent":["/**\n * File hooks — covers, artifacts & recordings via wspace-files-svc (NO duplication).\n * @module theculturepost/hooks\n *\n * TheCulturePost never stores blobs. Stories keep `coverFileId`, archive items\n * keep `fileId`, citations keep `sourceFileId`, oral histories keep\n * `recordingFileId` — all pointing at files owned by wspace-files-svc. Upload\n * goes through the shared `uploadBlobToFiles` storage helper (presigned 3-step\n * upload) against the workspace Apollo client the shell initialises; display\n * resolves a file id to a presigned URL via `getFileDownloadUrl`.\n */\n\nimport { useQuery } from '@tanstack/react-query';\nimport { graphqlFetch, getWorkspaceClient, gql } from '@burdenoff/fe-libs/shared/graphql';\nimport { uploadBlobToFiles } from '@burdenoff/fe-libs/storage';\n\nimport { useTheCulturePost } from '../context';\n\n/**\n * Presigned-URL lifetime, in seconds. S3 caps a presigned GET at 7 days\n * (604800s); anything longer makes wspace-files-svc `getFileDownloadUrl` throw\n * INTERNAL_SERVER_ERROR. React Query re-resolves these long before expiry\n * (30-min staleTime), so 6 hours is ample and stays safely under the cap.\n */\nconst DOWNLOAD_URL_TTL_SECONDS = 21_600;\n\nexport const FILE_FOLDERS = {\n covers: '/TheCulturePost/Covers',\n artifacts: '/TheCulturePost/Artifacts',\n recordings: '/TheCulturePost/Recordings',\n} as const;\n\nconst ENSURE_FOLDER = gql`\n mutation TcpEnsureFolder($path: String!) {\n ensureFolderByPath(path: $path) {\n id\n }\n }\n`;\n\nconst GET_FILE_DOWNLOAD_URL = gql`\n query TcpGetFileDownloadUrl($id: ID!, $expiresIn: Int) {\n getFileDownloadUrl(id: $id, expiresIn: $expiresIn)\n }\n`;\n\nexport interface UploadedFile {\n id: string;\n url: string;\n name: string;\n}\n\ninterface EnsureFolderData {\n ensureFolderByPath?: { id: string } | null;\n}\ninterface DownloadUrlData {\n getFileDownloadUrl?: string | null;\n}\n\n/**\n * Upload a file (image, audio, document…) to wspace-files-svc and return its id\n * + a presigned URL. The caller persists the id (coverFileId / fileId /\n * recordingFileId / sourceFileId) via the entity's own tcp* mutation; the URL is\n * used for an immediate preview.\n */\nexport async function uploadImageToFiles(file: File, folderPath: string): Promise<UploadedFile> {\n const client = getWorkspaceClient();\n\n const folderResult = await client.mutate<EnsureFolderData>({\n mutation: ENSURE_FOLDER,\n variables: { path: folderPath },\n });\n const folderId = folderResult.data?.ensureFolderByPath?.id;\n if (!folderId) {\n throw new Error('Could not resolve the upload folder.');\n }\n\n const uploaded = await uploadBlobToFiles({\n client,\n blob: file,\n filename: file.name,\n mimeType: file.type || 'application/octet-stream',\n folderId,\n });\n\n const urlResult = await client.query<DownloadUrlData>({\n query: GET_FILE_DOWNLOAD_URL,\n variables: { id: uploaded.id, expiresIn: DOWNLOAD_URL_TTL_SECONDS },\n fetchPolicy: 'no-cache',\n });\n const url = urlResult.data?.getFileDownloadUrl;\n if (!url) {\n throw new Error('The file was uploaded but no download URL was returned.');\n }\n\n return { id: uploaded.id, url, name: uploaded.name };\n}\n\n/** Resolve a wspace-files-svc file id to a presigned download URL for display. */\nexport function useFileUrl(fileId?: string | null) {\n const { apiGatewayUrl } = useTheCulturePost();\n return useQuery({\n queryKey: ['theculturepost', 'file-url', fileId ?? ''],\n enabled: Boolean(fileId),\n staleTime: 30 * 60 * 1000,\n retry: 1,\n queryFn: async () => {\n const response = await graphqlFetch<{ getFileDownloadUrl: string | null }>({\n gateway: 'workspace',\n baseUrl: apiGatewayUrl,\n workspaceToken: true,\n query: `query TcpFileUrl($id: ID!, $expiresIn: Int) { getFileDownloadUrl(id: $id, expiresIn: $expiresIn) }`,\n variables: { id: fileId, expiresIn: DOWNLOAD_URL_TTL_SECONDS },\n });\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'Could not resolve file URL');\n }\n return response.data?.getFileDownloadUrl ?? null;\n },\n });\n}\n"],"mappings":";;;;;;AAwBA,IAAM,IAA2B,OAEpB,IAAe;CAC1B,QAAQ;CACR,WAAW;CACX,YAAY;CACb,EAEK,IAAgB,CAAG;;;;;;GAQnB,IAAwB,CAAG;;;;;AAyBjC,eAAsB,EAAmB,GAAY,GAA2C;CAC9F,IAAM,IAAS,GAAoB,EAM7B,KAJe,MAAM,EAAO,OAAyB;EACzD,UAAU;EACV,WAAW,EAAE,MAAM,GAAY;EAChC,CAAC,EAC4B,MAAM,oBAAoB;AACxD,KAAI,CAAC,EACH,OAAU,MAAM,uCAAuC;CAGzD,IAAM,IAAW,MAAM,EAAkB;EACvC;EACA,MAAM;EACN,UAAU,EAAK;EACf,UAAU,EAAK,QAAQ;EACvB;EACD,CAAC,EAOI,KALY,MAAM,EAAO,MAAuB;EACpD,OAAO;EACP,WAAW;GAAE,IAAI,EAAS;GAAI,WAAW;GAA0B;EACnE,aAAa;EACd,CAAC,EACoB,MAAM;AAC5B,KAAI,CAAC,EACH,OAAU,MAAM,0DAA0D;AAG5E,QAAO;EAAE,IAAI,EAAS;EAAI;EAAK,MAAM,EAAS;EAAM;;AAItD,SAAgB,EAAW,GAAwB;CACjD,IAAM,EAAE,qBAAkB,GAAmB;AAC7C,QAAO,EAAS;EACd,UAAU;GAAC;GAAkB;GAAY,KAAU;GAAG;EACtD,SAAS,EAAQ;EACjB,WAAW,OAAU;EACrB,OAAO;EACP,SAAS,YAAY;GACnB,IAAM,IAAW,MAAM,EAAoD;IACzE,SAAS;IACT,SAAS;IACT,gBAAgB;IAChB,OAAO;IACP,WAAW;KAAE,IAAI;KAAQ,WAAW;KAA0B;IAC/D,CAAC;AACF,OAAI,EAAS,QAAQ,OACnB,OAAU,MAAM,EAAS,OAAO,IAAI,WAAW,6BAA6B;AAE9E,UAAO,EAAS,MAAM,sBAAsB;;EAE/C,CAAC"}
|
|
@@ -1,148 +1,271 @@
|
|
|
1
1
|
import { useTheCulturePost as e } from "../context/TheCulturePostContext.js";
|
|
2
|
-
import { PageLayout as t } from "../components/PageLayout.js";
|
|
3
|
-
import { LoadingView as n, Section as r } from "../components/StateViews.js";
|
|
4
2
|
import "../context/index.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
3
|
+
import { CoverImage as t } from "../components/CoverImage.js";
|
|
4
|
+
import { PageHero as n } from "../components/PageHero.js";
|
|
5
|
+
import { LoadingView as r } from "../components/StateViews.js";
|
|
6
|
+
import { formatNumber as i, formatRelativeTime as a } from "../utils/formatters.js";
|
|
7
|
+
import { OverlayBadge as o } from "../components/OverlayBadge.js";
|
|
8
|
+
import { StoryCard as s } from "../components/StoryCard.js";
|
|
9
|
+
import { TopicCard as c } from "../components/TopicCard.js";
|
|
10
|
+
import { EmptyState as l } from "../components/EmptyState.js";
|
|
11
|
+
import { useTcpCollections as u, useTcpDiscussions as d, useTcpStories as f, useTcpTopics as p } from "../hooks/useTcpApi.js";
|
|
11
12
|
import "../hooks/index.js";
|
|
12
|
-
import { ArrowRight as
|
|
13
|
-
import { jsx as
|
|
14
|
-
import { Button as
|
|
13
|
+
import { ArrowRight as m, BookOpen as h, Compass as g, HeartHandshake as _, Layers as v, Library as y, MessagesSquare as b } from "lucide-react";
|
|
14
|
+
import { jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
15
|
+
import { Button as C } from "@burdenoff/fe-libs/ui";
|
|
15
16
|
//#region src/theculturepost/pages/HomePage.tsx
|
|
16
|
-
function
|
|
17
|
-
return /* @__PURE__ */
|
|
17
|
+
function w({ label: e, onClick: t }) {
|
|
18
|
+
return /* @__PURE__ */ S(C, {
|
|
18
19
|
variant: "ghost",
|
|
19
20
|
size: "sm",
|
|
20
21
|
onClick: t,
|
|
22
|
+
className: "shrink-0",
|
|
21
23
|
children: [
|
|
22
24
|
e,
|
|
23
25
|
" ",
|
|
24
|
-
/* @__PURE__ */
|
|
26
|
+
/* @__PURE__ */ x(m, {
|
|
27
|
+
className: "ml-1 h-4 w-4",
|
|
28
|
+
"aria-hidden": "true"
|
|
29
|
+
})
|
|
25
30
|
]
|
|
26
31
|
});
|
|
27
32
|
}
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
actions: /* @__PURE__ */ y(b, {
|
|
42
|
-
onClick: () => p("stories"),
|
|
43
|
-
children: [/* @__PURE__ */ v(m, { className: "mr-1.5 h-4 w-4" }), " Read stories"]
|
|
44
|
-
}),
|
|
45
|
-
children: M ? /* @__PURE__ */ v(n, { label: "Loading the latest…" }) : N ? /* @__PURE__ */ v(c, {
|
|
46
|
-
illustration: "onboarding",
|
|
47
|
-
icon: /* @__PURE__ */ v(m, { className: "h-10 w-10" }),
|
|
48
|
-
title: "Welcome to TheCulturePost",
|
|
49
|
-
description: "This publication is just getting started. Curate a topic, draft a story, or begin building the archive.",
|
|
50
|
-
action: /* @__PURE__ */ y("div", {
|
|
51
|
-
className: "flex flex-wrap items-center justify-center gap-3",
|
|
52
|
-
children: [/* @__PURE__ */ y(b, {
|
|
53
|
-
onClick: () => p("stories"),
|
|
54
|
-
children: [/* @__PURE__ */ v(m, { className: "mr-1.5 h-4 w-4" }), " Draft a story"]
|
|
55
|
-
}), /* @__PURE__ */ y(b, {
|
|
56
|
-
variant: "outline",
|
|
57
|
-
onClick: () => p("topics"),
|
|
58
|
-
children: [/* @__PURE__ */ v(h, { className: "mr-1.5 h-4 w-4" }), " Curate a topic"]
|
|
33
|
+
function T({ title: e, description: t, action: n, children: r }) {
|
|
34
|
+
return /* @__PURE__ */ S("section", {
|
|
35
|
+
className: "flex flex-col gap-4",
|
|
36
|
+
children: [/* @__PURE__ */ S("div", {
|
|
37
|
+
className: "flex items-end justify-between gap-3 border-b border-border-seam pb-3",
|
|
38
|
+
children: [/* @__PURE__ */ S("div", {
|
|
39
|
+
className: "min-w-0",
|
|
40
|
+
children: [/* @__PURE__ */ x("h2", {
|
|
41
|
+
className: "font-display text-xl font-semibold leading-tight text-text-primary sm:text-2xl",
|
|
42
|
+
children: e
|
|
43
|
+
}), t && /* @__PURE__ */ x("p", {
|
|
44
|
+
className: "mt-1 text-sm text-text-secondary",
|
|
45
|
+
children: t
|
|
59
46
|
})]
|
|
60
|
-
})
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
47
|
+
}), n]
|
|
48
|
+
}), r]
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function E({ title: e, action: t, children: n }) {
|
|
52
|
+
return /* @__PURE__ */ S("section", {
|
|
53
|
+
className: "rounded-2xl border border-border-seam bg-bg-surface p-4",
|
|
54
|
+
children: [/* @__PURE__ */ S("div", {
|
|
55
|
+
className: "mb-3 flex items-center justify-between gap-2",
|
|
56
|
+
children: [/* @__PURE__ */ x("h3", {
|
|
57
|
+
className: "text-xs font-semibold uppercase tracking-[0.12em] text-text-secondary",
|
|
58
|
+
children: e
|
|
59
|
+
}), t]
|
|
60
|
+
}), n]
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function D({ discussion: e, onOpen: t }) {
|
|
64
|
+
return /* @__PURE__ */ S("button", {
|
|
65
|
+
type: "button",
|
|
66
|
+
onClick: t,
|
|
67
|
+
className: "group flex w-full items-start gap-3 rounded-xl px-2 py-2.5 text-left transition-colors hover:bg-bg-sunken",
|
|
68
|
+
children: [/* @__PURE__ */ x("span", {
|
|
69
|
+
className: "mt-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-accent",
|
|
70
|
+
"aria-hidden": "true",
|
|
71
|
+
children: /* @__PURE__ */ x(e.isInterfaith ? _ : b, { className: "h-4 w-4" })
|
|
72
|
+
}), /* @__PURE__ */ S("span", {
|
|
73
|
+
className: "min-w-0 flex-1",
|
|
74
|
+
children: [/* @__PURE__ */ x("span", {
|
|
75
|
+
className: "line-clamp-2 text-sm font-medium text-text-primary group-hover:text-accent",
|
|
76
|
+
children: e.title
|
|
77
|
+
}), /* @__PURE__ */ S("span", {
|
|
78
|
+
className: "mt-1 flex flex-wrap items-center gap-x-2.5 gap-y-1 text-xs text-text-tertiary",
|
|
79
|
+
children: [
|
|
80
|
+
e.isInterfaith && /* @__PURE__ */ S("span", {
|
|
81
|
+
className: "inline-flex items-center gap-1 rounded-full bg-[var(--color-accent-soft)] px-1.5 py-0.5 font-medium text-text-primary",
|
|
82
|
+
children: [/* @__PURE__ */ x(_, {
|
|
83
|
+
className: "h-3 w-3",
|
|
84
|
+
"aria-hidden": "true"
|
|
85
|
+
}), " Interfaith"]
|
|
89
86
|
}),
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
children: k.map((e) => /* @__PURE__ */ v(i, {
|
|
97
|
-
story: e,
|
|
98
|
-
hideStatus: !0,
|
|
99
|
-
onOpen: () => p(`stories/${e.id}`)
|
|
100
|
-
}, e.id))
|
|
101
|
-
})
|
|
102
|
-
}),
|
|
103
|
-
/* @__PURE__ */ v(r, {
|
|
104
|
-
title: "Active discussions",
|
|
105
|
-
description: "Respectful, moderated conversations from the community.",
|
|
106
|
-
action: /* @__PURE__ */ v(x, {
|
|
107
|
-
label: "All discussions",
|
|
108
|
-
onClick: () => p("discussions")
|
|
87
|
+
/* @__PURE__ */ S("span", {
|
|
88
|
+
className: "inline-flex items-center gap-1",
|
|
89
|
+
children: [/* @__PURE__ */ x(b, {
|
|
90
|
+
className: "h-3 w-3",
|
|
91
|
+
"aria-hidden": "true"
|
|
92
|
+
}), i(e.replyCount)]
|
|
109
93
|
}),
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
94
|
+
/* @__PURE__ */ x("span", { children: a(e.updatedAt) })
|
|
95
|
+
]
|
|
96
|
+
})]
|
|
97
|
+
})]
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function O({ collection: e, onOpen: n }) {
|
|
101
|
+
return /* @__PURE__ */ S("button", {
|
|
102
|
+
type: "button",
|
|
103
|
+
onClick: n,
|
|
104
|
+
"aria-label": `Open ${e.name}`,
|
|
105
|
+
className: "group flex flex-col gap-2 text-left",
|
|
106
|
+
children: [/* @__PURE__ */ S("span", {
|
|
107
|
+
className: "relative block aspect-square w-full overflow-hidden rounded-xl",
|
|
108
|
+
children: [/* @__PURE__ */ x(t, {
|
|
109
|
+
fileId: e.cover?.id,
|
|
110
|
+
alt: e.name,
|
|
111
|
+
rounded: "rounded-none",
|
|
112
|
+
className: "h-full w-full transition-transform duration-500 group-hover:scale-[1.03]",
|
|
113
|
+
icon: /* @__PURE__ */ x(y, { className: "h-6 w-6" })
|
|
114
|
+
}), /* @__PURE__ */ x(o, {
|
|
115
|
+
position: "bottom-right",
|
|
116
|
+
icon: /* @__PURE__ */ x(v, { className: "h-3 w-3" }),
|
|
117
|
+
children: i(e.itemCount)
|
|
118
|
+
})]
|
|
119
|
+
}), /* @__PURE__ */ S("span", {
|
|
120
|
+
className: "min-w-0",
|
|
121
|
+
children: [/* @__PURE__ */ x("span", {
|
|
122
|
+
className: "block truncate font-display text-sm font-semibold text-text-primary group-hover:text-accent",
|
|
123
|
+
children: e.name
|
|
124
|
+
}), e.tradition && /* @__PURE__ */ x("span", {
|
|
125
|
+
className: "block truncate text-xs text-text-tertiary",
|
|
126
|
+
children: e.tradition
|
|
127
|
+
})]
|
|
128
|
+
})]
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
function k() {
|
|
132
|
+
let { navigateTo: t } = e(), i = p({ pagination: { limit: 6 } }), a = f({
|
|
133
|
+
status: "PUBLISHED",
|
|
134
|
+
pagination: { limit: 6 }
|
|
135
|
+
}), o = d({
|
|
136
|
+
status: "APPROVED",
|
|
137
|
+
pagination: { limit: 6 }
|
|
138
|
+
}), m = u({ limit: 6 }), _ = i.data?.items ?? [], v = _.filter((e) => e.isFeatured), k = (v.length > 0 ? v : _).slice(0, 4), A = a.data?.items ?? [], j = o.data?.items ?? [], M = m.data ?? [], N = i.isLoading && a.isLoading && o.isLoading && m.isLoading, P = !i.isLoading && !a.isLoading && !o.isLoading && !m.isLoading && k.length === 0 && A.length === 0 && j.length === 0 && M.length === 0;
|
|
139
|
+
return /* @__PURE__ */ x("div", {
|
|
140
|
+
className: "flex h-full flex-col",
|
|
141
|
+
children: /* @__PURE__ */ x("div", {
|
|
142
|
+
className: "flex-1 overflow-auto",
|
|
143
|
+
children: /* @__PURE__ */ S("div", {
|
|
144
|
+
className: "mx-auto flex max-w-7xl flex-col gap-8 p-4 sm:p-6",
|
|
145
|
+
children: [/* @__PURE__ */ x(n, {
|
|
146
|
+
eyebrow: "TheCulturePost",
|
|
147
|
+
title: "Culture, religion, values & history — told with care",
|
|
148
|
+
description: "A space for respectful stories and thoughtful conversations that connect us across traditions and time — grounded in the record.",
|
|
149
|
+
actions: /* @__PURE__ */ S(C, {
|
|
150
|
+
size: "lg",
|
|
151
|
+
onClick: () => t("stories"),
|
|
152
|
+
children: [/* @__PURE__ */ x(h, {
|
|
153
|
+
className: "mr-1.5 h-4 w-4",
|
|
154
|
+
"aria-hidden": "true"
|
|
155
|
+
}), " Read stories"]
|
|
120
156
|
})
|
|
121
|
-
}),
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
157
|
+
}), N ? /* @__PURE__ */ x(r, { label: "Loading the latest…" }) : P ? /* @__PURE__ */ x(l, {
|
|
158
|
+
illustration: "onboarding",
|
|
159
|
+
icon: /* @__PURE__ */ x(h, { className: "h-10 w-10" }),
|
|
160
|
+
title: "Welcome to TheCulturePost",
|
|
161
|
+
description: "This publication is just getting started. Curate a topic, draft a story, or begin building the archive.",
|
|
162
|
+
action: /* @__PURE__ */ S("div", {
|
|
163
|
+
className: "flex flex-wrap items-center justify-center gap-3",
|
|
164
|
+
children: [/* @__PURE__ */ S(C, {
|
|
165
|
+
onClick: () => t("stories"),
|
|
166
|
+
children: [/* @__PURE__ */ x(h, {
|
|
167
|
+
className: "mr-1.5 h-4 w-4",
|
|
168
|
+
"aria-hidden": "true"
|
|
169
|
+
}), " Draft a story"]
|
|
170
|
+
}), /* @__PURE__ */ S(C, {
|
|
171
|
+
variant: "outline",
|
|
172
|
+
onClick: () => t("topics"),
|
|
173
|
+
children: [/* @__PURE__ */ x(g, {
|
|
174
|
+
className: "mr-1.5 h-4 w-4",
|
|
175
|
+
"aria-hidden": "true"
|
|
176
|
+
}), " Curate a topic"]
|
|
177
|
+
})]
|
|
139
178
|
})
|
|
140
|
-
})
|
|
141
|
-
|
|
179
|
+
}) : /* @__PURE__ */ S("div", {
|
|
180
|
+
className: "grid gap-8 lg:grid-cols-3",
|
|
181
|
+
children: [/* @__PURE__ */ S("div", {
|
|
182
|
+
className: "flex flex-col gap-10 lg:col-span-2",
|
|
183
|
+
children: [/* @__PURE__ */ x(T, {
|
|
184
|
+
title: "Featured topics",
|
|
185
|
+
description: "Curated subjects across culture, faith, history and heritage.",
|
|
186
|
+
action: /* @__PURE__ */ x(w, {
|
|
187
|
+
label: "All topics",
|
|
188
|
+
onClick: () => t("topics")
|
|
189
|
+
}),
|
|
190
|
+
children: k.length === 0 ? /* @__PURE__ */ x(l, {
|
|
191
|
+
icon: /* @__PURE__ */ x(g, { className: "h-9 w-9" }),
|
|
192
|
+
title: "No topics yet",
|
|
193
|
+
description: "Curate the first topic to organise the publication."
|
|
194
|
+
}) : /* @__PURE__ */ x("div", {
|
|
195
|
+
className: "grid gap-4 sm:grid-cols-2",
|
|
196
|
+
children: k.map((e) => /* @__PURE__ */ x(c, {
|
|
197
|
+
topic: e,
|
|
198
|
+
onOpen: () => t(`topics/${e.id}`)
|
|
199
|
+
}, e.id))
|
|
200
|
+
})
|
|
201
|
+
}), /* @__PURE__ */ x(T, {
|
|
202
|
+
title: "Latest published stories",
|
|
203
|
+
description: "Freshly published pieces from the newsroom.",
|
|
204
|
+
action: /* @__PURE__ */ x(w, {
|
|
205
|
+
label: "All stories",
|
|
206
|
+
onClick: () => t("stories")
|
|
207
|
+
}),
|
|
208
|
+
children: A.length === 0 ? /* @__PURE__ */ x(l, {
|
|
209
|
+
icon: /* @__PURE__ */ x(h, { className: "h-9 w-9" }),
|
|
210
|
+
title: "No published stories yet",
|
|
211
|
+
description: "Draft a story and move it through the editorial lifecycle to publish."
|
|
212
|
+
}) : /* @__PURE__ */ x("div", {
|
|
213
|
+
className: "grid gap-4 sm:grid-cols-2",
|
|
214
|
+
children: A.map((e) => /* @__PURE__ */ x(s, {
|
|
215
|
+
story: e,
|
|
216
|
+
hideStatus: !0,
|
|
217
|
+
onOpen: () => t(`stories/${e.id}`)
|
|
218
|
+
}, e.id))
|
|
219
|
+
})
|
|
220
|
+
})]
|
|
221
|
+
}), /* @__PURE__ */ S("aside", {
|
|
222
|
+
className: "flex flex-col gap-6",
|
|
223
|
+
children: [/* @__PURE__ */ x(E, {
|
|
224
|
+
title: "Active discussions",
|
|
225
|
+
action: /* @__PURE__ */ x("button", {
|
|
226
|
+
type: "button",
|
|
227
|
+
onClick: () => t("discussions"),
|
|
228
|
+
className: "text-xs font-medium text-accent hover:underline",
|
|
229
|
+
children: "View all"
|
|
230
|
+
}),
|
|
231
|
+
children: j.length === 0 ? /* @__PURE__ */ x(l, {
|
|
232
|
+
icon: /* @__PURE__ */ x(b, { className: "h-8 w-8" }),
|
|
233
|
+
title: "No open discussions",
|
|
234
|
+
description: "Open a discussion to invite thoughtful perspectives."
|
|
235
|
+
}) : /* @__PURE__ */ x("div", {
|
|
236
|
+
className: "-mx-2 flex flex-col",
|
|
237
|
+
children: j.map((e) => /* @__PURE__ */ x(D, {
|
|
238
|
+
discussion: e,
|
|
239
|
+
onOpen: () => t(`discussions/${e.id}`)
|
|
240
|
+
}, e.id))
|
|
241
|
+
})
|
|
242
|
+
}), /* @__PURE__ */ x(E, {
|
|
243
|
+
title: "From the archive",
|
|
244
|
+
action: /* @__PURE__ */ x("button", {
|
|
245
|
+
type: "button",
|
|
246
|
+
onClick: () => t("archive"),
|
|
247
|
+
className: "text-xs font-medium text-accent hover:underline",
|
|
248
|
+
children: "View all"
|
|
249
|
+
}),
|
|
250
|
+
children: M.length === 0 ? /* @__PURE__ */ x(l, {
|
|
251
|
+
icon: /* @__PURE__ */ x(y, { className: "h-8 w-8" }),
|
|
252
|
+
title: "The archive is empty",
|
|
253
|
+
description: "Create a collection to begin preserving heritage."
|
|
254
|
+
}) : /* @__PURE__ */ x("div", {
|
|
255
|
+
className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
|
|
256
|
+
children: M.map((e) => /* @__PURE__ */ x(O, {
|
|
257
|
+
collection: e,
|
|
258
|
+
onOpen: () => t(`archive/collections/${e.id}`)
|
|
259
|
+
}, e.id))
|
|
260
|
+
})
|
|
261
|
+
})]
|
|
262
|
+
})]
|
|
263
|
+
})]
|
|
264
|
+
})
|
|
142
265
|
})
|
|
143
266
|
});
|
|
144
267
|
}
|
|
145
268
|
//#endregion
|
|
146
|
-
export {
|
|
269
|
+
export { k as HomePage };
|
|
147
270
|
|
|
148
271
|
//# sourceMappingURL=HomePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HomePage.js","names":[],"sources":["../../../src/theculturepost/pages/HomePage.tsx"],"sourcesContent":["/**\n * HomePage — the editorial landing for TheCulturePost.\n * @module theculturepost/pages\n *\n * Surfaces featured topics (`tcpListTopics`), the latest published stories\n * (`tcpListStories status:PUBLISHED`), active discussions\n * (`tcpListDiscussions status:APPROVED`) and featured collections\n * (`tcpListCollections`). Everything links into its section; honest empty states\n * appear when a surface has no data yet.\n */\n\nimport { BookOpen, Compass, MessagesSquare, Library, ArrowRight } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Section, LoadingView } from '../components/StateViews';\nimport { StoryCard } from '../components/StoryCard';\nimport { TopicCard } from '../components/TopicCard';\nimport { DiscussionCard } from '../components/DiscussionCard';\nimport { CollectionCard } from '../components/CollectionCard';\nimport { EmptyState } from '../components/EmptyState';\nimport { useTcpTopics, useTcpStories, useTcpDiscussions, useTcpCollections } from '../hooks';\nimport { useTheCulturePost } from '../context';\n\nfunction SectionLink({ label, onClick }: { label: string; onClick: () => void }) {\n return (\n <Button variant=\"ghost\" size=\"sm\" onClick={onClick}>\n {label} <ArrowRight className=\"ml-1 h-4 w-4\" />\n </Button>\n );\n}\n\nexport function HomePage() {\n const { navigateTo } = useTheCulturePost();\n\n const topicsQuery = useTcpTopics({ pagination: { limit: 6 } });\n const storiesQuery = useTcpStories({ status: 'PUBLISHED', pagination: { limit: 6 } });\n const discussionsQuery = useTcpDiscussions({ status: 'APPROVED', pagination: { limit: 4 } });\n const collectionsQuery = useTcpCollections({ limit: 4 });\n\n const topics = topicsQuery.data?.items ?? [];\n const featuredTopics = topics.filter((t) => t.isFeatured);\n const shownTopics = (featuredTopics.length > 0 ? featuredTopics : topics).slice(0, 6);\n const stories = storiesQuery.data?.items ?? [];\n const discussions = discussionsQuery.data?.items ?? [];\n const collections = collectionsQuery.data ?? [];\n\n const anythingLoading =\n topicsQuery.isLoading &&\n storiesQuery.isLoading &&\n discussionsQuery.isLoading &&\n collectionsQuery.isLoading;\n\n const everythingEmpty =\n !topicsQuery.isLoading &&\n !storiesQuery.isLoading &&\n !discussionsQuery.isLoading &&\n !collectionsQuery.isLoading &&\n shownTopics.length === 0 &&\n stories.length === 0 &&\n discussions.length === 0 &&\n collections.length === 0;\n\n return (\n <PageLayout\n title=\"TheCulturePost\"\n titleGradient\n aurora\n description=\"Culture, religion, values and history — told with care and grounded in the record.\"\n actions={\n <Button onClick={() => navigateTo('stories')}>\n <BookOpen className=\"mr-1.5 h-4 w-4\" /> Read stories\n </Button>\n }\n >\n {anythingLoading ? (\n <LoadingView label=\"Loading the latest…\" />\n ) : everythingEmpty ? (\n <EmptyState\n illustration=\"onboarding\"\n icon={<BookOpen className=\"h-10 w-10\" />}\n title=\"Welcome to TheCulturePost\"\n description=\"This publication is just getting started. Curate a topic, draft a story, or begin building the archive.\"\n action={\n <div className=\"flex flex-wrap items-center justify-center gap-3\">\n <Button onClick={() => navigateTo('stories')}>\n <BookOpen className=\"mr-1.5 h-4 w-4\" /> Draft a story\n </Button>\n <Button variant=\"outline\" onClick={() => navigateTo('topics')}>\n <Compass className=\"mr-1.5 h-4 w-4\" /> Curate a topic\n </Button>\n </div>\n }\n />\n ) : (\n <div className=\"mx-auto flex max-w-6xl flex-col gap-2\">\n {/* Featured topics */}\n <Section\n title=\"Featured topics\"\n description=\"Curated subjects across culture, faith, history and heritage.\"\n action={<SectionLink label=\"All topics\" onClick={() => navigateTo('topics')} />}\n >\n {shownTopics.length === 0 ? (\n <EmptyState\n icon={<Compass className=\"h-9 w-9\" />}\n title=\"No topics yet\"\n description=\"Curate the first topic to organise the publication.\"\n />\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {shownTopics.map((topic) => (\n <TopicCard\n key={topic.id}\n topic={topic}\n onOpen={() => navigateTo(`topics/${topic.id}`)}\n />\n ))}\n </div>\n )}\n </Section>\n\n {/* Latest stories */}\n <Section\n title=\"Latest stories\"\n description=\"Freshly published pieces from the newsroom.\"\n action={<SectionLink label=\"All stories\" onClick={() => navigateTo('stories')} />}\n >\n {stories.length === 0 ? (\n <EmptyState\n icon={<BookOpen className=\"h-9 w-9\" />}\n title=\"No published stories yet\"\n description=\"Draft a story and move it through the editorial lifecycle to publish.\"\n />\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {stories.map((story) => (\n <StoryCard\n key={story.id}\n story={story}\n hideStatus\n onOpen={() => navigateTo(`stories/${story.id}`)}\n />\n ))}\n </div>\n )}\n </Section>\n\n {/* Active discussions */}\n <Section\n title=\"Active discussions\"\n description=\"Respectful, moderated conversations from the community.\"\n action={\n <SectionLink label=\"All discussions\" onClick={() => navigateTo('discussions')} />\n }\n >\n {discussions.length === 0 ? (\n <EmptyState\n icon={<MessagesSquare className=\"h-9 w-9\" />}\n title=\"No open discussions\"\n description=\"Open a discussion to invite thoughtful perspectives.\"\n />\n ) : (\n <div className=\"grid gap-4 md:grid-cols-2\">\n {discussions.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\n {/* Featured collections */}\n <Section\n title=\"From the archive\"\n description=\"Collections of manuscripts, photographs, recordings and objects.\"\n action={<SectionLink label=\"Open archive\" onClick={() => navigateTo('archive')} />}\n >\n {collections.length === 0 ? (\n <EmptyState\n icon={<Library className=\"h-9 w-9\" />}\n title=\"The archive is empty\"\n description=\"Create a collection to begin preserving cultural heritage.\"\n />\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {collections.map((collection) => (\n <CollectionCard\n key={collection.id}\n collection={collection}\n onOpen={() => navigateTo(`archive/collections/${collection.id}`)}\n />\n ))}\n </div>\n )}\n </Section>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HomePage.js","names":[],"sources":["../../../src/theculturepost/pages/HomePage.tsx"],"sourcesContent":["/**\n * HomePage — the editorial-magazine landing for TheCulturePost.\n * @module theculturepost/pages\n *\n * Layout: a decorative {@link PageHero}, then a two-column magazine grid —\n * - main column: \"Featured topics\" ({@link TopicCard}) + \"Latest published\n * stories\" ({@link StoryCard} status:PUBLISHED)\n * - right rail (compact): \"Active discussions\" (status:APPROVED) rows +\n * \"From the archive\" collection thumbnails.\n *\n * Every surface links into its section and shows an honest empty state when it\n * has no data. Only real schema fields are rendered — no fabricated metrics,\n * avatars or imagery (topics/discussions use token-only decorative motifs).\n */\n\nimport type { ReactNode } from 'react';\nimport {\n BookOpen,\n Compass,\n MessagesSquare,\n Library,\n Layers,\n HeartHandshake,\n ArrowRight,\n} from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { PageHero } from '../components/PageHero';\nimport { LoadingView } from '../components/StateViews';\nimport { StoryCard } from '../components/StoryCard';\nimport { TopicCard } from '../components/TopicCard';\nimport { CoverImage } from '../components/CoverImage';\nimport { OverlayBadge } from '../components/OverlayBadge';\nimport { EmptyState } from '../components/EmptyState';\nimport { useTcpTopics, useTcpStories, useTcpDiscussions, useTcpCollections } from '../hooks';\nimport { useTheCulturePost } from '../context';\nimport { formatNumber, formatRelativeTime } from '../utils/formatters';\nimport type { TcpDiscussion, TcpCollection } from '../types';\n\n// ---------------------------------------------------------------------------\n// Small presentational helpers (home-only; kept inline)\n// ---------------------------------------------------------------------------\n\nfunction SectionLink({ label, onClick }: { label: string; onClick: () => void }) {\n return (\n <Button variant=\"ghost\" size=\"sm\" onClick={onClick} className=\"shrink-0\">\n {label} <ArrowRight className=\"ml-1 h-4 w-4\" aria-hidden=\"true\" />\n </Button>\n );\n}\n\n/** A magazine section header (serif) for the main reading column. */\nfunction MagSection({\n title,\n description,\n action,\n children,\n}: {\n title: string;\n description?: string;\n action?: ReactNode;\n children: ReactNode;\n}) {\n return (\n <section className=\"flex flex-col gap-4\">\n <div className=\"flex items-end justify-between gap-3 border-b border-border-seam pb-3\">\n <div className=\"min-w-0\">\n <h2 className=\"font-display text-xl font-semibold leading-tight text-text-primary sm:text-2xl\">\n {title}\n </h2>\n {description && <p className=\"mt-1 text-sm text-text-secondary\">{description}</p>}\n </div>\n {action}\n </div>\n {children}\n </section>\n );\n}\n\n/** A bordered panel for the compact right rail. */\nfunction RailSection({\n title,\n action,\n children,\n}: {\n title: string;\n action?: ReactNode;\n children: ReactNode;\n}) {\n return (\n <section className=\"rounded-2xl border border-border-seam bg-bg-surface p-4\">\n <div className=\"mb-3 flex items-center justify-between gap-2\">\n <h3 className=\"text-xs font-semibold uppercase tracking-[0.12em] text-text-secondary\">\n {title}\n </h3>\n {action}\n </div>\n {children}\n </section>\n );\n}\n\n/** A compact discussion row for the rail — real fields only. */\nfunction DiscussionRow({ discussion, onOpen }: { discussion: TcpDiscussion; onOpen: () => void }) {\n const Icon = discussion.isInterfaith ? HeartHandshake : MessagesSquare;\n return (\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"group flex w-full items-start gap-3 rounded-xl px-2 py-2.5 text-left transition-colors hover:bg-bg-sunken\"\n >\n <span\n className=\"mt-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-accent\"\n aria-hidden=\"true\"\n >\n <Icon className=\"h-4 w-4\" />\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"line-clamp-2 text-sm font-medium text-text-primary group-hover:text-accent\">\n {discussion.title}\n </span>\n <span className=\"mt-1 flex flex-wrap items-center gap-x-2.5 gap-y-1 text-xs text-text-tertiary\">\n {discussion.isInterfaith && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-[var(--color-accent-soft)] px-1.5 py-0.5 font-medium text-text-primary\">\n <HeartHandshake className=\"h-3 w-3\" aria-hidden=\"true\" /> Interfaith\n </span>\n )}\n <span className=\"inline-flex items-center gap-1\">\n <MessagesSquare className=\"h-3 w-3\" aria-hidden=\"true\" />\n {formatNumber(discussion.replyCount)}\n </span>\n <span>{formatRelativeTime(discussion.updatedAt)}</span>\n </span>\n </span>\n </button>\n );\n}\n\n/** A compact archive-collection thumbnail for the rail (real itemCount only). */\nfunction ArchiveThumb({ collection, onOpen }: { collection: TcpCollection; onOpen: () => void }) {\n return (\n <button\n type=\"button\"\n onClick={onOpen}\n aria-label={`Open ${collection.name}`}\n className=\"group flex flex-col gap-2 text-left\"\n >\n <span className=\"relative block aspect-square w-full overflow-hidden rounded-xl\">\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-6 w-6\" />}\n />\n <OverlayBadge position=\"bottom-right\" icon={<Layers className=\"h-3 w-3\" />}>\n {formatNumber(collection.itemCount)}\n </OverlayBadge>\n </span>\n <span className=\"min-w-0\">\n <span className=\"block truncate font-display text-sm font-semibold text-text-primary group-hover:text-accent\">\n {collection.name}\n </span>\n {collection.tradition && (\n <span className=\"block truncate text-xs text-text-tertiary\">{collection.tradition}</span>\n )}\n </span>\n </button>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Page\n// ---------------------------------------------------------------------------\n\nexport function HomePage() {\n const { navigateTo } = useTheCulturePost();\n\n const topicsQuery = useTcpTopics({ pagination: { limit: 6 } });\n const storiesQuery = useTcpStories({ status: 'PUBLISHED', pagination: { limit: 6 } });\n const discussionsQuery = useTcpDiscussions({ status: 'APPROVED', pagination: { limit: 6 } });\n const collectionsQuery = useTcpCollections({ limit: 6 });\n\n const topics = topicsQuery.data?.items ?? [];\n const featuredTopics = topics.filter((t) => t.isFeatured);\n const shownTopics = (featuredTopics.length > 0 ? featuredTopics : topics).slice(0, 4);\n const stories = storiesQuery.data?.items ?? [];\n const discussions = discussionsQuery.data?.items ?? [];\n const collections = collectionsQuery.data ?? [];\n\n const anythingLoading =\n topicsQuery.isLoading &&\n storiesQuery.isLoading &&\n discussionsQuery.isLoading &&\n collectionsQuery.isLoading;\n\n const everythingEmpty =\n !topicsQuery.isLoading &&\n !storiesQuery.isLoading &&\n !discussionsQuery.isLoading &&\n !collectionsQuery.isLoading &&\n shownTopics.length === 0 &&\n stories.length === 0 &&\n discussions.length === 0 &&\n collections.length === 0;\n\n return (\n <div className=\"flex h-full flex-col\">\n <div className=\"flex-1 overflow-auto\">\n <div className=\"mx-auto flex max-w-7xl flex-col gap-8 p-4 sm:p-6\">\n <PageHero\n eyebrow=\"TheCulturePost\"\n title=\"Culture, religion, values & history — told with care\"\n description=\"A space for respectful stories and thoughtful conversations that connect us across traditions and time — grounded in the record.\"\n actions={\n <Button size=\"lg\" onClick={() => navigateTo('stories')}>\n <BookOpen className=\"mr-1.5 h-4 w-4\" aria-hidden=\"true\" /> Read stories\n </Button>\n }\n />\n\n {anythingLoading ? (\n <LoadingView label=\"Loading the latest…\" />\n ) : everythingEmpty ? (\n <EmptyState\n illustration=\"onboarding\"\n icon={<BookOpen className=\"h-10 w-10\" />}\n title=\"Welcome to TheCulturePost\"\n description=\"This publication is just getting started. Curate a topic, draft a story, or begin building the archive.\"\n action={\n <div className=\"flex flex-wrap items-center justify-center gap-3\">\n <Button onClick={() => navigateTo('stories')}>\n <BookOpen className=\"mr-1.5 h-4 w-4\" aria-hidden=\"true\" /> Draft a story\n </Button>\n <Button variant=\"outline\" onClick={() => navigateTo('topics')}>\n <Compass className=\"mr-1.5 h-4 w-4\" aria-hidden=\"true\" /> Curate a topic\n </Button>\n </div>\n }\n />\n ) : (\n <div className=\"grid gap-8 lg:grid-cols-3\">\n {/* Main reading column */}\n <div className=\"flex flex-col gap-10 lg:col-span-2\">\n {/* Featured topics */}\n <MagSection\n title=\"Featured topics\"\n description=\"Curated subjects across culture, faith, history and heritage.\"\n action={<SectionLink label=\"All topics\" onClick={() => navigateTo('topics')} />}\n >\n {shownTopics.length === 0 ? (\n <EmptyState\n icon={<Compass className=\"h-9 w-9\" />}\n title=\"No topics yet\"\n description=\"Curate the first topic to organise the publication.\"\n />\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2\">\n {shownTopics.map((topic) => (\n <TopicCard\n key={topic.id}\n topic={topic}\n onOpen={() => navigateTo(`topics/${topic.id}`)}\n />\n ))}\n </div>\n )}\n </MagSection>\n\n {/* Latest published stories */}\n <MagSection\n title=\"Latest published stories\"\n description=\"Freshly published pieces from the newsroom.\"\n action={<SectionLink label=\"All stories\" onClick={() => navigateTo('stories')} />}\n >\n {stories.length === 0 ? (\n <EmptyState\n icon={<BookOpen className=\"h-9 w-9\" />}\n title=\"No published stories yet\"\n description=\"Draft a story and move it through the editorial lifecycle to publish.\"\n />\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2\">\n {stories.map((story) => (\n <StoryCard\n key={story.id}\n story={story}\n hideStatus\n onOpen={() => navigateTo(`stories/${story.id}`)}\n />\n ))}\n </div>\n )}\n </MagSection>\n </div>\n\n {/* Compact right rail */}\n <aside className=\"flex flex-col gap-6\">\n {/* Active discussions */}\n <RailSection\n title=\"Active discussions\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('discussions')}\n className=\"text-xs font-medium text-accent hover:underline\"\n >\n View all\n </button>\n }\n >\n {discussions.length === 0 ? (\n <EmptyState\n icon={<MessagesSquare className=\"h-8 w-8\" />}\n title=\"No open discussions\"\n description=\"Open a discussion to invite thoughtful perspectives.\"\n />\n ) : (\n <div className=\"-mx-2 flex flex-col\">\n {discussions.map((discussion) => (\n <DiscussionRow\n key={discussion.id}\n discussion={discussion}\n onOpen={() => navigateTo(`discussions/${discussion.id}`)}\n />\n ))}\n </div>\n )}\n </RailSection>\n\n {/* From the archive */}\n <RailSection\n title=\"From the archive\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('archive')}\n className=\"text-xs font-medium text-accent hover:underline\"\n >\n View all\n </button>\n }\n >\n {collections.length === 0 ? (\n <EmptyState\n icon={<Library className=\"h-8 w-8\" />}\n title=\"The archive is empty\"\n description=\"Create a collection to begin preserving heritage.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n {collections.map((collection) => (\n <ArchiveThumb\n key={collection.id}\n collection={collection}\n onOpen={() => navigateTo(`archive/collections/${collection.id}`)}\n />\n ))}\n </div>\n )}\n </RailSection>\n </aside>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|