@openrails/contentkit-ui 0.71.0 → 0.72.0
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/README.md +98 -10
- package/dist/client/content/bans.d.ts +2 -0
- package/dist/client/content/bans.js +24 -12
- package/dist/client/content/bans.js.map +1 -1
- package/dist/client/content/comments.d.ts +2 -0
- package/dist/client/content/comments.js.map +1 -1
- package/dist/client/content/polls.d.ts +9 -2
- package/dist/client/content/polls.js.map +1 -1
- package/dist/client/generated/routes.d.ts +28 -2
- package/dist/client/generated/routes.js +40 -0
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +4 -0
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/index.d.ts +2 -2
- package/dist/client/taxonomy.d.ts +5 -1
- package/dist/client/taxonomy.js +7 -0
- package/dist/client/taxonomy.js.map +1 -1
- package/dist/components/admin/poll-manager.d.ts +28 -0
- package/dist/components/admin/poll-manager.js +297 -0
- package/dist/components/admin/poll-manager.js.map +1 -0
- package/dist/components/admin/post-manager.d.ts +45 -0
- package/dist/components/admin/post-manager.js +602 -0
- package/dist/components/admin/post-manager.js.map +1 -0
- package/dist/components/admin/shell.d.ts +73 -0
- package/dist/components/admin/shell.js +148 -0
- package/dist/components/admin/shell.js.map +1 -0
- package/dist/components/admin/taxonomy-manager.d.ts +54 -0
- package/dist/components/admin/taxonomy-manager.js +976 -0
- package/dist/components/admin/taxonomy-manager.js.map +1 -0
- package/dist/components/admin/user-comment-standing.d.ts +25 -0
- package/dist/components/admin/user-comment-standing.js +229 -0
- package/dist/components/admin/user-comment-standing.js.map +1 -0
- package/dist/components/social/bans.d.ts +5 -2
- package/dist/components/social/bans.js +132 -134
- package/dist/components/social/bans.js.map +1 -1
- package/dist/components/social/index.d.ts +1 -1
- package/dist/components/social/moderation.d.ts +11 -13
- package/dist/components/social/moderation.js +299 -218
- package/dist/components/social/moderation.js.map +1 -1
- package/dist/components/social/parts.d.ts +3 -2
- package/dist/components/social/parts.js +74 -48
- package/dist/components/social/parts.js.map +1 -1
- package/dist/components/social/poll-editor.js +1 -0
- package/dist/components/social/poll-editor.js.map +1 -1
- package/dist/editor/index.d.ts +1 -0
- package/dist/editor/rich-text-editor.d.ts +13 -0
- package/dist/editor/rich-text-editor.js +228 -0
- package/dist/editor/rich-text-editor.js.map +1 -0
- package/dist/editor.js +2 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +13 -8
- package/dist/locales/admin/de.d.ts +2 -0
- package/dist/locales/admin/de.js +176 -0
- package/dist/locales/admin/de.js.map +1 -0
- package/dist/locales/admin/en.d.ts +171 -0
- package/dist/locales/admin/en.js +176 -0
- package/dist/locales/admin/en.js.map +1 -0
- package/dist/locales/admin/es.d.ts +2 -0
- package/dist/locales/admin/es.js +176 -0
- package/dist/locales/admin/es.js.map +1 -0
- package/dist/locales/admin/ja.d.ts +2 -0
- package/dist/locales/admin/ja.js +176 -0
- package/dist/locales/admin/ja.js.map +1 -0
- package/dist/locales/admin/ko.d.ts +2 -0
- package/dist/locales/admin/ko.js +176 -0
- package/dist/locales/admin/ko.js.map +1 -0
- package/dist/locales/admin/zh.d.ts +2 -0
- package/dist/locales/admin/zh.js +176 -0
- package/dist/locales/admin/zh.js.map +1 -0
- package/dist/locales/de.js +5 -3
- package/dist/locales/de.js.map +1 -1
- package/dist/locales/en.d.ts +176 -0
- package/dist/locales/en.js +5 -3
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +5 -3
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/ja.js +5 -3
- package/dist/locales/ja.js.map +1 -1
- package/dist/locales/ko.js +5 -3
- package/dist/locales/ko.js.map +1 -1
- package/dist/locales/social/de.js +8 -1
- package/dist/locales/social/de.js.map +1 -1
- package/dist/locales/social/en.d.ts +7 -0
- package/dist/locales/social/en.js +8 -1
- package/dist/locales/social/en.js.map +1 -1
- package/dist/locales/social/es.js +8 -1
- package/dist/locales/social/es.js.map +1 -1
- package/dist/locales/social/ja.js +8 -1
- package/dist/locales/social/ja.js.map +1 -1
- package/dist/locales/social/ko.js +8 -1
- package/dist/locales/social/ko.js.map +1 -1
- package/dist/locales/social/zh.js +8 -1
- package/dist/locales/social/zh.js.map +1 -1
- package/dist/locales/zh.js +5 -3
- package/dist/locales/zh.js.map +1 -1
- package/dist/provider.d.ts +2 -0
- package/dist/provider.js +23 -19
- package/dist/provider.js.map +1 -1
- package/dist/react/admin.d.ts +55 -0
- package/dist/react/admin.js +97 -0
- package/dist/react/admin.js.map +1 -0
- package/dist/react/comments.d.ts +18 -2
- package/dist/react/comments.js +24 -8
- package/dist/react/comments.js.map +1 -1
- package/dist/react/context.d.ts +7 -1
- package/dist/react/context.js +6 -1
- package/dist/react/context.js.map +1 -1
- package/dist/react/index.d.ts +4 -3
- package/dist/react/polls.js +88 -87
- package/dist/react/polls.js.map +1 -1
- package/dist/react/posts.js +123 -122
- package/dist/react/posts.js.map +1 -1
- package/dist/react/resources.js +3 -0
- package/dist/react/resources.js.map +1 -1
- package/dist/react/use-resource.d.ts +16 -0
- package/dist/react/use-resource.js +20 -1
- package/dist/react/use-resource.js.map +1 -1
- package/dist/react.js +21 -20
- package/dist/styles.css +1 -1
- package/package.json +37 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taxonomy-manager.js","names":[],"sources":["../../../src/components/admin/taxonomy-manager.tsx"],"sourcesContent":["import { useEffect, useId, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport { toContentKitError, type ContentKitError } from \"../../client/errors.js\";\nimport type { Assignment, AssignmentPage, ContentRef, Edge, MergeReport, Name, NodeDetail, NodePage, NodeRow } from \"../../client/generated/wire.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { useAdminLocation, useFlowClient, useStaffAccess, type AdminLocation, type FlowClientOptions, type StaffAccess } from \"../../react/admin.js\";\nimport { useErrorReporter } from \"../../react/context.js\";\nimport { usePublicImage } from \"../../react/public.js\";\nimport { keyOf, useContentScope, useResource } from \"../../react/use-resource.js\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Input } from \"#ckui/ui/input\";\nimport { Label } from \"#ckui/ui/label\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"#ckui/ui/select\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { Tabs, TabsList, TabsTrigger } from \"#ckui/ui/tabs\";\nimport { CoverUpload } from \"../slot-upload.js\";\nimport { contentError, ErrorLine, RelativeTime, useAction } from \"../social/parts.js\";\nimport { AdminRoot, LoadFailed, NoAccess, Pager, Rows, pageOf, useConfirm, type AdminFlowProps, type AdminRouteProps } from \"./shell.js\";\n\ntype Choice = string | { value: string; label: string };\nexport type TaxonomyRelation = Edge[\"relation\"];\n\n/** One node kind the flow manages. */\nexport interface TaxonomyKind {\n /** The kind as the store registers it, e.g. \"tag\", \"series\". */\n kind: string;\n label: string;\n /** Edges a node of this kind may have, \"node is <relation> of a <to> node\": e.g. a character member_of a series. */\n relations?: readonly { relation: TaxonomyRelation; to: string; label: string; inverseLabel?: string }[];\n /** A cover in the host's media: the media kind whose items are node ids, its upload path (\"cover\") and public preset (\"cover\"). */\n cover?: { kind: string; path?: string; preset?: string };\n}\n\nexport interface TaxonomyManagerProps extends AdminFlowProps, AdminRouteProps {\n /** The kinds, in tab order; the first is at basePath. */\n kinds: readonly TaxonomyKind[];\n /** Languages names are written in; the first resolves the list's names. */\n languages?: readonly Choice[];\n /** Counts of this content kind; default every kind. */\n contentKind?: string;\n /** Host-owned fields of a node (a creator's type, a tag's restricted flag), below its names. */\n renderFields?: (node: NodeDetail) => ReactNode;\n /** One assigned content, e.g. a link with its title. Default its kind and id. */\n renderContent?: (ref: ContentRef, assignment: Assignment) => ReactNode;\n pageSize?: number;\n}\n\n/** Whether the caller may manage the taxonomy (root:taxonomy:write). */\nexport function useTaxonomyManagerAccess(o: FlowClientOptions = {}): StaffAccess<\"taxonomy\"> {\n return useStaffAccess([\"taxonomy\"] as const, o);\n}\n\nconst choices = (list?: readonly Choice[]) => (list ?? []).map((c) => (typeof c === \"string\" ? { value: c, label: c } : c));\nconst SORTS = [\"name\", \"count\", \"created\", \"updated\", \"oldest\"] as const;\nconst STATES = [\"active\", \"deleted\", \"merged\"] as const;\ntype NodeState = (typeof STATES)[number];\n\n/** A slug from a name: lowercase words joined by dashes. */\nexport function slugify(name: string): string {\n return name\n .normalize(\"NFKD\")\n .replace(/[̀-ͯ]/g, \"\")\n .toLowerCase()\n .trim()\n .replace(/[\\s/]+/g, \"-\")\n .replace(/[^\\p{L}\\p{N}-]+/gu, \"\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, 200);\n}\n\n/**\n * Staff: the taxonomy per kind. Each kind's nodes by name, state, language,\n * minimum count and order; a node's names and aliases per language, host\n * fields, relations (with a typeahead), cover, counts and assigned contents;\n * create, delete, restore and merge. Kinds are at basePath/{kind}, a node at\n * basePath/{kind}/{id}, filters in the query.\n */\nexport function TaxonomyManager({ client: own, baseUrl, auth, guard, appearance, className, language, messages, ...p }: TaxonomyManagerProps) {\n const client = useFlowClient({ client: own, baseUrl, auth });\n return (\n <AdminRoot flow=\"taxonomy-manager\" appearance={appearance} className={className} language={language} messages={messages} guard={guard}>\n <Taxonomy {...p} client={client} />\n </AdminRoot>\n );\n}\n\ntype Inner = Omit<TaxonomyManagerProps, \"client\" | \"baseUrl\" | \"auth\" | \"guard\" | \"appearance\" | \"className\" | \"language\" | \"messages\"> & { client: ContentKitClient };\ntype Ctx = Inner & { loc: AdminLocation; kind: TaxonomyKind; lang: string };\n\nfunction Taxonomy({ basePath, navigation, ...p }: Inner) {\n const { t } = useMessages();\n const loc = useAdminLocation(basePath, navigation);\n const access = useTaxonomyManagerAccess({ client: p.client });\n if (access.loading) return <Rows />;\n if (!access.allowed.taxonomy) return <NoAccess>{t(\"taxonomyManager.noAccess\")}</NoAccess>;\n if (!p.kinds.length) return null;\n const [k, sub] = loc.view.split(\"/\");\n const kind = p.kinds.find((x) => x.kind === k) ?? p.kinds[0]!;\n const ctx: Ctx = { ...p, loc, kind, lang: choices(p.languages)[0]?.value ?? \"en\" };\n return (\n <>\n {p.kinds.length > 1 && (\n <Tabs value={kind.kind} onValueChange={(v) => loc.go(String(v))}>\n <TabsList>\n {p.kinds.map((x) => (\n <TabsTrigger key={x.kind} value={x.kind}>\n {x.label}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n )}\n {!sub ? <NodeList key={kind.kind} {...ctx} /> : sub === \"new\" ? <NodeCreate key={kind.kind} {...ctx} /> : <NodeView key={sub} {...ctx} id={sub} />}\n </>\n );\n}\n\nfunction NodeList({ loc, kind, client, languages: offered, contentKind, pageSize = 25, lang }: Ctx) {\n const m = useMessages();\n const { t } = m;\n const ids = useId();\n const languages = choices(offered);\n const query = loc.query.get(\"q\") ?? \"\";\n const stateParam = loc.query.get(\"state\") ?? \"\";\n const state: NodeState = (STATES as readonly string[]).includes(stateParam) ? (stateParam as NodeState) : \"active\";\n const language = loc.query.get(\"language\") || lang;\n const minCount = Math.max(0, Number(loc.query.get(\"min_count\")) || 0);\n const sortParam = loc.query.get(\"sort\") ?? \"\";\n const sort = (SORTS as readonly string[]).includes(sortParam) ? sortParam : \"name\";\n const page = pageOf(loc.query);\n const filters: { q?: string; state?: NodeState; language?: string; min_count?: number; sort?: string } = {\n q: query,\n state: state === \"active\" ? undefined : state,\n language: language === lang ? undefined : language,\n min_count: minCount || undefined,\n sort: sort === \"name\" ? undefined : sort,\n };\n const filter = (next: Partial<typeof filters>) => loc.go(kind.kind, { ...filters, ...next });\n const [text, setText] = useState(query);\n useEffect(() => setText(query), [query]);\n const { store, scope } = useContentScope(client);\n const offset = (page - 1) * pageSize;\n const r = useResource<NodePage>(store, keyOf(\"taxonomy-nodes\", scope, kind.kind, query, state, language, minCount, sort, contentKind, offset, pageSize), { type: \"taxonomy-nodes\" }, (signal) =>\n client.taxonomy.nodes(\n { kind: kind.kind, q: query || undefined, state: [state], language, min_count: minCount || undefined, sort, content_kind: contentKind, offset, limit: pageSize },\n signal,\n ),\n );\n const nodes = r.data?.nodes ?? [];\n const total = r.data?.total ?? 0;\n const loading = r.loading || !r.loaded;\n return (\n <div className=\"grid gap-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h2 className=\"text-base font-semibold\">{kind.label}</h2>\n <Button size=\"sm\" onClick={() => loc.go(`${kind.kind}/new`)}>\n {t(\"taxonomyManager.new\")}\n </Button>\n </div>\n <div className=\"grid gap-2 sm:grid-cols-[minmax(0,1fr)_auto]\">\n <form\n className=\"flex gap-2\"\n role=\"search\"\n onSubmit={(e) => {\n e.preventDefault();\n filter({ q: text.trim() });\n }}\n >\n <Label htmlFor={`${ids}-q`} className=\"sr-only\">\n {t(\"taxonomyManager.search\")}\n </Label>\n <Input id={`${ids}-q`} className=\"h-8\" type=\"search\" value={text} placeholder={t(\"taxonomyManager.search\")} onChange={(e) => setText(e.target.value)} />\n <Button type=\"submit\" size=\"sm\" variant=\"outline\">\n {t(\"moderation.filter\")}\n </Button>\n </form>\n <div className=\"flex flex-wrap gap-2\">\n <Select value={state} onValueChange={(v) => filter({ state: v === \"active\" ? undefined : (String(v) as NodeState) })}>\n <SelectTrigger size=\"sm\" aria-label={t(\"taxonomyManager.state\")}>\n <SelectValue>{(v: string) => t(`taxonomyManager.${v as NodeState}`)}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {STATES.map((s) => (\n <SelectItem key={s} value={s}>\n {t(`taxonomyManager.${s}`)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {languages.length > 1 && (\n <Select value={language} onValueChange={(v) => filter({ language: v === lang ? undefined : String(v) })}>\n <SelectTrigger size=\"sm\" aria-label={t(\"taxonomyManager.language\")}>\n <SelectValue>{(v: string) => languages.find((l) => l.value === v)?.label ?? v}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {languages.map((l) => (\n <SelectItem key={l.value} value={l.value}>\n {l.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n <Select value={sort} onValueChange={(v) => filter({ sort: v === \"name\" ? undefined : String(v) })}>\n <SelectTrigger size=\"sm\" aria-label={t(\"taxonomyManager.sort\")}>\n <SelectValue>{(v: string) => t(`taxonomyManager.sort_${v as (typeof SORTS)[number]}`)}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {SORTS.map((s) => (\n <SelectItem key={s} value={s}>\n {t(`taxonomyManager.sort_${s}`)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <div className=\"flex items-center gap-1.5\">\n <Label htmlFor={`${ids}-min`} className=\"text-xs text-muted-foreground\">\n {t(\"taxonomyManager.minCount\")}\n </Label>\n <Input\n id={`${ids}-min`}\n className=\"h-8 w-20\"\n type=\"number\"\n min={0}\n value={minCount || \"\"}\n onChange={(e) => filter({ min_count: Number(e.target.value) || undefined })}\n />\n </div>\n </div>\n </div>\n {loading && !nodes.length ? (\n <Rows />\n ) : r.error && !nodes.length ? (\n <LoadFailed error={r.error} message={t(\"taxonomyManager.loadFailed\")} retry={r.reload} />\n ) : !nodes.length ? (\n <p className=\"text-muted-foreground\">{t(\"taxonomyManager.empty\")}</p>\n ) : (\n <ul className=\"grid divide-y divide-border rounded-lg border border-border\" aria-busy={loading}>\n {nodes.map((n) => (\n <li key={n.taxonomy_id} className=\"flex flex-wrap items-center gap-3 p-3\" data-ckui=\"node-row\" data-state={n.state}>\n <div className=\"grid min-w-0 flex-1 gap-0.5\">\n <button type=\"button\" className=\"text-left font-medium break-words hover:underline\" onClick={() => loc.go(`${kind.kind}/${n.taxonomy_id}`)}>\n {n.name || n.slug}\n </button>\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground\">\n <span>{n.slug}</span>\n {n.state !== \"active\" && <Badge variant=\"outline\">{t(`taxonomyManager.${n.state}`)}</Badge>}\n <RelativeTime at={n.updated_at} />\n </div>\n </div>\n <span className=\"text-sm tabular-nums text-muted-foreground\" title={t(\"taxonomyManager.count\")}>\n {n.count}\n </span>\n </li>\n ))}\n </ul>\n )}\n {total > 0 && <p className=\"text-center text-xs text-muted-foreground\">{m.plural(\"taxonomyManager.total\", total)}</p>}\n <Pager page={page} hasNext={offset + nodes.length < total} disabled={loading} onPage={(n) => loc.go(kind.kind, { ...filters, page: n > 1 ? n : undefined })} />\n </div>\n );\n}\n\nfunction NodeCreate({ loc, kind, client, languages: offered, lang, onError }: Ctx) {\n const m = useMessages();\n const { t } = m;\n const ids = useId();\n const languages = choices(offered);\n const [names, setNames] = useState<Record<string, string>>({});\n const [slug, setSlug] = useState(\"\");\n const [slugEdited, setSlugEdited] = useState(false);\n const create = useAction(\"taxonomy.save\", onError);\n const first = names[lang] ?? \"\";\n useEffect(() => {\n if (!slugEdited) setSlug(slugify(first));\n }, [first, slugEdited]);\n const list = languages.length ? languages : [{ value: lang, label: lang }];\n const submit = async () => {\n const given: Name[] = list.filter((l) => names[l.value]?.trim()).map((l) => ({ language: l.value, kind: \"name\", name: names[l.value]!.trim(), source_revision: 0 }));\n const made = await create.run(() => client.taxonomy.createNodes([{ kind: kind.kind, slug: slug.trim(), names: given, source_revision: 0 }]));\n if (made?.[0]) loc.go(`${kind.kind}/${made[0].taxonomy_id}`, undefined, { replace: true });\n };\n return (\n <form\n className=\"grid gap-4\"\n data-ckui=\"node-create\"\n onSubmit={(e) => {\n e.preventDefault();\n void submit();\n }}\n >\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" className=\"justify-self-start\" onClick={() => loc.go(kind.kind)}>\n {t(\"taxonomyManager.back\", { kind: kind.label })}\n </Button>\n <h2 className=\"text-base font-semibold\">{t(\"taxonomyManager.newTitle\", { kind: kind.label })}</h2>\n {list.map((l, i) => (\n <div key={l.value} className=\"grid gap-1.5\">\n <Label htmlFor={`${ids}-${l.value}`}>{t(\"taxonomyManager.nameIn\", { language: l.label })}</Label>\n <Input id={`${ids}-${l.value}`} required={i === 0} value={names[l.value] ?? \"\"} onChange={(e) => setNames((n) => ({ ...n, [l.value]: e.target.value }))} />\n </div>\n ))}\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${ids}-slug`}>{t(\"taxonomyManager.slug\")}</Label>\n <Input\n id={`${ids}-slug`}\n required\n value={slug}\n onChange={(e) => {\n setSlugEdited(true);\n setSlug(e.target.value);\n }}\n />\n </div>\n {create.error && <ErrorLine>{contentError(m, create.error)}</ErrorLine>}\n <Button type=\"submit\" className=\"justify-self-start\" disabled={create.pending || !first.trim() || !slug.trim()}>\n {create.pending ? t(\"common.saving\") : t(\"taxonomyManager.create\")}\n </Button>\n </form>\n );\n}\n\nfunction NodeView({ id, loc, kind, client, lang, ...p }: Ctx & { id: string }) {\n const m = useMessages();\n const { t } = m;\n const { store, scope } = useContentScope(client);\n const r = useResource<NodeDetail>(store, keyOf(\"taxonomy-node\", scope, id), { type: \"taxonomy-node\", id }, (signal) => client.taxonomy.node(id, signal));\n const node = r.data;\n const partnerIds = useMemo(() => [...new Set((node?.edges ?? []).flatMap((e) => [e.from_taxonomy_id, e.to_taxonomy_id]).filter((x) => x !== id))].sort(), [node?.edges, id]);\n const partners = useResource<NodePage>(\n store,\n partnerIds.length ? keyOf(\"taxonomy-partners\", scope, lang, ...partnerIds) : null,\n { type: \"taxonomy-partners\" },\n (signal) => client.taxonomy.nodes({ id: partnerIds, state: [\"active\", \"merged\", \"deleted\"], language: lang, limit: Math.min(500, partnerIds.length) }, signal),\n );\n const byId = useMemo(() => new Map((partners.data?.nodes ?? []).map((n) => [n.taxonomy_id, n])), [partners.data]);\n const save = useAction(\"taxonomy.save\", p.onError);\n const { confirm, dialog } = useConfirm();\n const back = (\n <Button variant=\"ghost\" size=\"sm\" className=\"justify-self-start\" onClick={() => loc.go(kind.kind)}>\n {t(\"taxonomyManager.back\", { kind: kind.label })}\n </Button>\n );\n if (!node) {\n return (\n <>\n {back}\n {r.error ? <LoadFailed error={r.error} message={t(\"taxonomyManager.nodeLoadFailed\")} retry={r.reload} /> : <Skeleton className=\"h-40 w-full\" />}\n </>\n );\n }\n const canonical = node.names.find((n) => n.kind === \"name\" && n.language === lang) ?? node.names.find((n) => n.kind === \"name\");\n const title = canonical?.name ?? node.slug;\n const setState = async (state: \"active\" | \"deleted\") => {\n if (state === \"deleted\" && !(await confirm({ title: t(\"taxonomyManager.deleteTitle\", { name: title }), description: t(\"taxonomyManager.deleteBody\"), confirm: t(\"taxonomyManager.delete\") }))) return;\n await save.run(() => client.taxonomy.updateNode(id, { state }));\n };\n return (\n <div className=\"grid gap-5\" data-ckui=\"node-view\" data-state={node.state}>\n {back}\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"text-base font-semibold break-words\">{title}</h2>\n <Badge variant={node.state === \"active\" ? \"outline\" : \"secondary\"}>{t(`taxonomyManager.${node.state}`)}</Badge>\n <div className=\"ms-auto flex flex-wrap gap-2\">\n {node.state === \"active\" && <MergeButton node={node} title={title} kind={kind} client={client} loc={loc} lang={lang} onError={p.onError} />}\n {node.state === \"active\" ? (\n <Button size=\"sm\" variant=\"destructive\" disabled={save.pending} onClick={() => void setState(\"deleted\")}>\n {t(\"taxonomyManager.delete\")}\n </Button>\n ) : node.state === \"deleted\" ? (\n <Button size=\"sm\" variant=\"outline\" disabled={save.pending} onClick={() => void setState(\"active\")}>\n {t(\"taxonomyManager.restore\")}\n </Button>\n ) : null}\n </div>\n </div>\n {node.state === \"merged\" && <MergedInto node={node} byId={byId} kind={kind} loc={loc} />}\n <ErrorLine error={save.error} />\n <SlugField node={node} client={client} onError={p.onError} />\n <Names node={node} client={client} languages={p.languages} lang={lang} onError={p.onError} />\n {p.renderFields && <section data-ckui=\"node-fields\">{p.renderFields(node)}</section>}\n {kind.cover && <Cover node={node} cover={kind.cover} client={client} />}\n <Relations node={node} kind={kind} kinds={p.kinds} byId={byId} client={client} loc={loc} lang={lang} onError={p.onError} />\n <Counts node={node} />\n <Contents id={id} client={client} renderContent={p.renderContent} />\n {dialog}\n </div>\n );\n}\n\nfunction Section({ title, children, ckui }: { title: ReactNode; children: ReactNode; ckui: string }) {\n return (\n <section className=\"grid gap-2\" data-ckui={ckui}>\n <h3 className=\"font-medium\">{title}</h3>\n {children}\n </section>\n );\n}\n\nfunction SlugField({ node, client, onError }: { node: NodeDetail; client: ContentKitClient; onError?: Inner[\"onError\"] }) {\n const { t } = useMessages();\n const ids = useId();\n const [slug, setSlug] = useState(node.slug);\n useEffect(() => setSlug(node.slug), [node.slug]);\n const save = useAction(\"taxonomy.save\", onError);\n return (\n <form\n className=\"flex flex-wrap items-end gap-2\"\n onSubmit={(e) => {\n e.preventDefault();\n void save.run(() => client.taxonomy.updateNode(node.taxonomy_id, { slug: slug.trim() }));\n }}\n >\n <div className=\"grid min-w-48 flex-1 gap-1.5\">\n <Label htmlFor={`${ids}-slug`}>{t(\"taxonomyManager.slug\")}</Label>\n <Input id={`${ids}-slug`} className=\"h-8\" value={slug} onChange={(e) => setSlug(e.target.value)} />\n </div>\n <Button type=\"submit\" size=\"sm\" variant=\"outline\" disabled={save.pending || !slug.trim() || slug.trim() === node.slug}>\n {t(\"common.save\")}\n </Button>\n <ErrorLine error={save.error} className=\"basis-full\" />\n </form>\n );\n}\n\nfunction Names({ node, client, languages: offered, lang, onError }: { node: NodeDetail; client: ContentKitClient; languages?: readonly Choice[]; lang: string; onError?: Inner[\"onError\"] }) {\n const { t } = useMessages();\n const ids = useId();\n const languages = choices(offered);\n const list = languages.length ? languages : [{ value: lang, label: lang }];\n const [language, setLanguage] = useState(list[0]!.value);\n const [kind, setKind] = useState<Name[\"kind\"]>(\"alias\");\n const [text, setText] = useState(\"\");\n const save = useAction(\"taxonomy.save\", onError);\n const id = node.taxonomy_id;\n const label = (code: string) => list.find((l) => l.value === code)?.label ?? code;\n const sorted = [...node.names].sort((a, b) => a.language.localeCompare(b.language) || (a.kind === b.kind ? a.name.localeCompare(b.name) : a.kind === \"name\" ? -1 : 1));\n return (\n <Section title={t(\"taxonomyManager.names\")} ckui=\"node-names\">\n {sorted.length ? (\n <ul className=\"grid divide-y divide-border rounded-lg border border-border\">\n {sorted.map((n) => (\n <li key={`${n.language}:${n.name}`} className=\"flex flex-wrap items-center gap-2 p-2.5\" data-ckui=\"node-name\" data-kind={n.kind}>\n <Badge variant=\"outline\">{label(n.language)}</Badge>\n <span className=\"min-w-0 flex-1 break-words\">{n.name}</span>\n <span className=\"text-xs text-muted-foreground\">{t(n.kind === \"name\" ? \"taxonomyManager.canonical\" : \"taxonomyManager.alias\")}</span>\n {n.kind === \"alias\" && (\n <Button size=\"xs\" variant=\"ghost\" disabled={save.pending} onClick={() => void save.run(() => client.taxonomy.names(id, \"add\", [{ ...n, kind: \"name\" }]))}>\n {t(\"taxonomyManager.makeCanonical\")}\n </Button>\n )}\n <Button size=\"xs\" variant=\"ghost\" disabled={save.pending} aria-label={t(\"taxonomyManager.removeName\", { name: n.name })} onClick={() => void save.run(() => client.taxonomy.names(id, \"remove\", [n]))}>\n {t(\"common.remove\")}\n </Button>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-muted-foreground\">{t(\"taxonomyManager.noNames\")}</p>\n )}\n <form\n className=\"flex flex-wrap items-end gap-2\"\n onSubmit={(e) => {\n e.preventDefault();\n const name = text.trim();\n if (!name) return;\n void save.run(() => client.taxonomy.names(id, \"add\", [{ language, kind, name, source_revision: 0 }])).then((d) => d && setText(\"\"));\n }}\n >\n {list.length > 1 && (\n <Select value={language} onValueChange={(v) => setLanguage(String(v))}>\n <SelectTrigger size=\"sm\" aria-label={t(\"taxonomyManager.language\")}>\n <SelectValue>{(v: string) => label(v)}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {list.map((l) => (\n <SelectItem key={l.value} value={l.value}>\n {l.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n <Select value={kind} onValueChange={(v) => setKind(v as Name[\"kind\"])}>\n <SelectTrigger size=\"sm\" aria-label={t(\"taxonomyManager.nameKind\")}>\n <SelectValue>{(v: string) => t(v === \"name\" ? \"taxonomyManager.canonical\" : \"taxonomyManager.alias\")}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"alias\">{t(\"taxonomyManager.alias\")}</SelectItem>\n <SelectItem value=\"name\">{t(\"taxonomyManager.canonical\")}</SelectItem>\n </SelectContent>\n </Select>\n <Label htmlFor={`${ids}-name`} className=\"sr-only\">\n {t(\"taxonomyManager.newName\")}\n </Label>\n <Input id={`${ids}-name`} className=\"h-8 min-w-40 flex-1\" value={text} placeholder={t(\"taxonomyManager.newName\")} onChange={(e) => setText(e.target.value)} />\n <Button type=\"submit\" size=\"sm\" variant=\"outline\" disabled={save.pending || !text.trim()}>\n {t(\"taxonomyManager.addName\")}\n </Button>\n </form>\n <ErrorLine error={save.error} />\n </Section>\n );\n}\n\nfunction Cover({ node, cover, client }: { node: NodeDetail; cover: NonNullable<TaxonomyKind[\"cover\"]>; client: ContentKitClient }) {\n const { t } = useMessages();\n const item = { kind: cover.kind, id: node.taxonomy_id };\n const { image } = usePublicImage(cover.kind, node.taxonomy_id, cover.preset ?? \"cover\", { client });\n return (\n <section className=\"grid max-w-xl gap-2\" data-ckui=\"node-cover\">\n <CoverUpload item={item} path={cover.path ?? \"cover\"} image={image} client={client} removable label={t(\"taxonomyManager.cover\")} />\n </section>\n );\n}\n\nfunction MergedInto({ node, byId, kind, loc }: { node: NodeDetail; byId: Map<string, NodeRow>; kind: TaxonomyKind; loc: AdminLocation }) {\n const { t } = useMessages();\n const into = node.edges.find((e) => e.relation === \"alias_of\" && e.from_taxonomy_id === node.taxonomy_id)?.to_taxonomy_id;\n if (!into) return null;\n const target = byId.get(into);\n return (\n <p className=\"text-muted-foreground\" data-ckui=\"merged-into\">\n {t(\"taxonomyManager.mergedInto\")}{\" \"}\n <button type=\"button\" className=\"font-medium text-foreground hover:underline\" onClick={() => loc.go(`${target?.kind ?? kind.kind}/${into}`)}>\n {target?.name || target?.slug || into}\n </button>\n </p>\n );\n}\n\nfunction MergeButton({ node, title, kind, client, loc, lang, onError }: { node: NodeDetail; title: string; kind: TaxonomyKind; client: ContentKitClient; loc: AdminLocation; lang: string; onError?: Inner[\"onError\"] }) {\n const { t } = useMessages();\n const [picking, setPicking] = useState(false);\n const merge = useAction(\"taxonomy.save\", onError);\n const { confirm, dialog } = useConfirm();\n const [report, setReport] = useState<MergeReport | null>(null);\n const pick = async (into: NodeRow) => {\n setPicking(false);\n const ok = await confirm({\n title: t(\"taxonomyManager.mergeTitle\", { from: title, into: into.name || into.slug }),\n description: t(\"taxonomyManager.mergeBody\"),\n confirm: t(\"taxonomyManager.merge\"),\n typed: t(\"taxonomyManager.mergeWord\"),\n });\n if (!ok) return;\n const r = await merge.run(() => client.taxonomy.merge(node.taxonomy_id, into.taxonomy_id));\n if (r) {\n setReport(r);\n loc.go(`${kind.kind}/${into.taxonomy_id}`);\n }\n };\n return (\n <>\n {picking ? (\n <div className=\"flex flex-wrap items-center gap-2\" data-ckui=\"merge-picker\">\n <NodePicker kind={kind.kind} exclude={node.taxonomy_id} client={client} lang={lang} label={t(\"taxonomyManager.mergeInto\")} onPick={(n) => void pick(n)} />\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setPicking(false)}>\n {t(\"common.cancel\")}\n </Button>\n </div>\n ) : (\n <Button size=\"sm\" variant=\"outline\" disabled={merge.pending} onClick={() => setPicking(true)}>\n {t(\"taxonomyManager.merge\")}\n </Button>\n )}\n {merge.error && <ErrorLine error={merge.error} className=\"basis-full\" />}\n {report && (\n <p role=\"status\" className=\"sr-only\">\n {t(\"taxonomyManager.mergeDone\", { count: report.assignments_moved })}\n </p>\n )}\n {dialog}\n </>\n );\n}\n\n/** A typeahead over one kind's active nodes. */\nfunction NodePicker({ kind, exclude, client, lang, label, onPick }: { kind: string; exclude?: string; client: ContentKitClient; lang: string; label: string; onPick: (n: NodeRow) => void }) {\n const { t } = useMessages();\n const id = useId();\n const [text, setText] = useState(\"\");\n const [results, setResults] = useState<NodeRow[]>([]);\n const [active, setActive] = useState(0);\n const [error, setError] = useState<ContentKitError | null>(null);\n const seq = useRef(0);\n useEffect(() => {\n const q = text.trim();\n const n = ++seq.current;\n if (!q) {\n setResults([]);\n return;\n }\n const ctl = new AbortController();\n const timer = setTimeout(() => {\n client.taxonomy.nodes({ kind, q, language: lang, limit: 8, sort: \"name\" }, ctl.signal).then(\n (page) => {\n if (n !== seq.current) return;\n setError(null);\n setResults(page.nodes.filter((x) => x.taxonomy_id !== exclude));\n setActive(0);\n },\n (e) => {\n const err = toContentKitError(e);\n if (err.code !== \"aborted\" && n === seq.current) setError(err);\n },\n );\n }, 200);\n return () => {\n clearTimeout(timer);\n ctl.abort();\n };\n }, [text, kind, lang, exclude, client]);\n const open = results.length > 0;\n return (\n <div className=\"relative grid min-w-56 flex-1 gap-1\" data-ckui=\"node-picker\">\n <Input\n role=\"combobox\"\n aria-label={label}\n aria-expanded={open}\n aria-controls={`${id}-list`}\n aria-activedescendant={open ? `${id}-${active}` : undefined}\n autoComplete=\"off\"\n className=\"h-8\"\n value={text}\n placeholder={t(\"taxonomyManager.searchNodes\")}\n autoFocus\n onChange={(e) => setText(e.target.value)}\n onKeyDown={(e) => {\n if (!open) return;\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActive((a) => Math.min(results.length - 1, a + 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActive((a) => Math.max(0, a - 1));\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n onPick(results[active]!);\n } else if (e.key === \"Escape\") setResults([]);\n }}\n />\n {open && (\n <ul id={`${id}-list`} role=\"listbox\" aria-label={label} className=\"absolute top-full z-10 mt-1 grid w-full overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md\">\n {results.map((n, i) => (\n <li\n key={n.taxonomy_id}\n id={`${id}-${i}`}\n role=\"option\"\n aria-selected={i === active}\n className={`cursor-pointer px-3 py-1.5 ${i === active ? \"bg-accent text-accent-foreground\" : \"\"}`}\n onMouseEnter={() => setActive(i)}\n onMouseDown={(e) => {\n e.preventDefault();\n onPick(n);\n }}\n >\n {n.name || n.slug} <span className=\"text-xs text-muted-foreground\">{n.slug}</span>\n </li>\n ))}\n </ul>\n )}\n {error && <ErrorLine error={error} />}\n </div>\n );\n}\n\nfunction Relations({\n node,\n kind,\n kinds,\n byId,\n client,\n loc,\n lang,\n onError,\n}: {\n node: NodeDetail;\n kind: TaxonomyKind;\n kinds: readonly TaxonomyKind[];\n byId: Map<string, NodeRow>;\n client: ContentKitClient;\n loc: AdminLocation;\n lang: string;\n onError?: Inner[\"onError\"];\n}) {\n const { t } = useMessages();\n const save = useAction(\"taxonomy.save\", onError);\n const [adding, setAdding] = useState<number | null>(null);\n const id = node.taxonomy_id;\n const out = node.edges.filter((e) => e.from_taxonomy_id === id && e.relation !== \"alias_of\");\n const incoming = node.edges.filter((e) => e.to_taxonomy_id === id && e.relation !== \"alias_of\");\n const own = kind.relations ?? [];\n // Relations other kinds declare toward this one, shown from this side.\n const inverse = kinds.flatMap((k) => (k.relations ?? []).filter((r) => r.to === kind.kind).map((r) => ({ ...r, from: k })));\n const link = (other: string, fallbackKind: string) => {\n const n = byId.get(other);\n return (\n <button type=\"button\" className=\"font-medium hover:underline\" onClick={() => loc.go(`${n?.kind ?? fallbackKind}/${other}`)}>\n {n?.name || n?.slug || other}\n </button>\n );\n };\n if (!own.length && !inverse.length && !out.length && !incoming.length) return null;\n return (\n <Section title={t(\"taxonomyManager.relations\")} ckui=\"node-relations\">\n {own.map((r, i) => {\n const edges = out.filter((e) => e.relation === r.relation && (byId.get(e.to_taxonomy_id)?.kind ?? r.to) === r.to);\n return (\n <div key={`${r.relation}:${r.to}`} className=\"grid gap-1.5\" data-ckui=\"relation\" data-relation={r.relation}>\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">{r.label}</span>\n {edges.map((e) => (\n <span key={e.to_taxonomy_id} className=\"inline-flex items-center gap-1 rounded-md border border-border px-2 py-0.5\" data-ckui=\"edge\">\n {link(e.to_taxonomy_id, r.to)}\n <button\n type=\"button\"\n className=\"text-muted-foreground hover:text-destructive\"\n aria-label={t(\"taxonomyManager.removeRelation\", { name: byId.get(e.to_taxonomy_id)?.name ?? e.to_taxonomy_id })}\n disabled={save.pending}\n onClick={() => void save.run(() => client.taxonomy.edges(\"remove\", [e]))}\n >\n ×\n </button>\n </span>\n ))}\n {adding !== i && (\n <Button size=\"xs\" variant=\"ghost\" onClick={() => setAdding(i)}>\n {t(\"taxonomyManager.addRelation\", { relation: r.label })}\n </Button>\n )}\n </div>\n {adding === i && (\n <div className=\"flex flex-wrap items-center gap-2\">\n <NodePicker\n kind={r.to}\n exclude={id}\n client={client}\n lang={lang}\n label={r.label}\n onPick={(n) => {\n setAdding(null);\n void save.run(() => client.taxonomy.edges(\"add\", [{ from_taxonomy_id: id, relation: r.relation, to_taxonomy_id: n.taxonomy_id, source_revision: 0 }]));\n }}\n />\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setAdding(null)}>\n {t(\"common.cancel\")}\n </Button>\n </div>\n )}\n </div>\n );\n })}\n {inverse.map((r) => {\n const edges = incoming.filter((e) => e.relation === r.relation && (byId.get(e.from_taxonomy_id)?.kind ?? r.from.kind) === r.from.kind);\n if (!edges.length) return null;\n return (\n <div key={`in:${r.relation}:${r.from.kind}`} className=\"flex flex-wrap items-center gap-2\" data-ckui=\"relation\" data-relation={`inverse:${r.relation}`}>\n <span className=\"text-sm text-muted-foreground\">{r.inverseLabel ?? r.from.label}</span>\n {edges.map((e) => (\n <span key={e.from_taxonomy_id} className=\"rounded-md border border-border px-2 py-0.5\" data-ckui=\"edge\">\n {link(e.from_taxonomy_id, r.from.kind)}\n </span>\n ))}\n </div>\n );\n })}\n <ErrorLine error={save.error} />\n </Section>\n );\n}\n\nfunction Counts({ node }: { node: NodeDetail }) {\n const { t } = useMessages();\n return (\n <Section title={t(\"taxonomyManager.counts\")} ckui=\"node-counts\">\n {node.counts.length ? (\n <ul className=\"flex flex-wrap gap-2\">\n {node.counts.map((c) => (\n <li key={`${c.content_kind}:${c.language}`} className=\"rounded-md border border-border px-2 py-1 text-xs\">\n {c.content_kind} · {c.language}: <span className=\"tabular-nums font-medium\">{c.count}</span>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-muted-foreground\">{t(\"taxonomyManager.noCounts\")}</p>\n )}\n </Section>\n );\n}\n\nfunction Contents({ id, client, renderContent }: { id: string; client: ContentKitClient; renderContent?: Inner[\"renderContent\"] }) {\n const { t } = useMessages();\n const report = useErrorReporter();\n const [pages, setPages] = useState<AssignmentPage[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<ContentKitError | null>(null);\n const load = async (cursor?: string) => {\n setLoading(true);\n setError(null);\n try {\n const page = await client.taxonomy.nodeAssignments(id, { cursor, limit: 25 });\n setPages((ps) => (cursor ? [...ps, page] : [page]));\n } catch (e) {\n const err = toContentKitError(e);\n setError(err);\n report(err, \"taxonomy.load\");\n } finally {\n setLoading(false);\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => void load(), [id, client]);\n const items = pages.flatMap((p) => p.assignments);\n const next = pages.at(-1)?.next_cursor;\n return (\n <Section title={t(\"taxonomyManager.contents\")} ckui=\"node-contents\">\n {loading && !items.length ? (\n <Rows count={2} />\n ) : error && !items.length ? (\n <LoadFailed error={error} message={t(\"taxonomyManager.contentsLoadFailed\")} retry={() => void load()} />\n ) : !items.length ? (\n <p className=\"text-muted-foreground\">{t(\"taxonomyManager.noContents\")}</p>\n ) : (\n <ul className=\"grid divide-y divide-border rounded-lg border border-border\">\n {items.map((a) => (\n <li\n key={`${a.content_kind}/${a.content_id}/${a.content_version_id ?? \"\"}/${a.relation}`}\n className=\"flex flex-wrap items-center gap-2 p-2.5\"\n data-ckui=\"node-content\"\n data-state={a.state}\n >\n <span className=\"min-w-0 flex-1 break-words\">\n {renderContent ? renderContent(a, a) : `${a.content_kind}/${a.content_id}${a.content_version_id ? ` (${a.content_version_id})` : \"\"}`}\n </span>\n <span className=\"text-xs text-muted-foreground\">{a.relation}</span>\n {a.state === \"proposed\" && <Badge variant=\"secondary\">{t(\"taxonomyManager.proposed\")}</Badge>}\n </li>\n ))}\n </ul>\n )}\n {next && (\n <Button variant=\"outline\" size=\"sm\" className=\"justify-self-center\" disabled={loading} onClick={() => void load(next)}>\n {t(\"moderation.loadMore\")}\n </Button>\n )}\n </Section>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FlowClientOptions, StaffAccess } from '../../react/admin.js';
|
|
2
|
+
import { AdminFlowProps } from './shell.js';
|
|
3
|
+
export interface UserCommentStandingProps extends AdminFlowProps {
|
|
4
|
+
/** The user's id. */
|
|
5
|
+
user: string;
|
|
6
|
+
/** Their name in headings and dialogs; else their username once known. */
|
|
7
|
+
name?: string;
|
|
8
|
+
/** A link to a commented item. */
|
|
9
|
+
itemHref?: (item: {
|
|
10
|
+
kind: string;
|
|
11
|
+
id: string;
|
|
12
|
+
}) => string | undefined;
|
|
13
|
+
/** Comments per page. Default 10. */
|
|
14
|
+
pageSize?: number;
|
|
15
|
+
}
|
|
16
|
+
type StandingArea = "bans" | "comments";
|
|
17
|
+
/** Whether the caller may manage site-wide comment bans and moderate comments: what UserCommentStanding shows. */
|
|
18
|
+
export declare function useUserCommentStandingAccess(o?: FlowClientOptions): StaffAccess<StandingArea>;
|
|
19
|
+
/**
|
|
20
|
+
* A user page's comment panel: the person's site-wide comment ban (ban,
|
|
21
|
+
* replace, lift) and their recent comments (delete, restore), each as the
|
|
22
|
+
* caller's permissions allow.
|
|
23
|
+
*/
|
|
24
|
+
export declare function UserCommentStanding({ client: own, baseUrl, auth, guard, appearance, className, language, messages, ...p }: UserCommentStandingProps): import('react').JSX.Element;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { useMessages as e } from "../../i18n/context.js";
|
|
2
|
+
import { Button as t } from "../../ui/button.js";
|
|
3
|
+
import { useAdminComments as n, useGlobalCommentBan as r } from "../../react/comments.js";
|
|
4
|
+
import { Badge as i } from "../../ui/badge.js";
|
|
5
|
+
import { Skeleton as a } from "../../ui/skeleton.js";
|
|
6
|
+
import { ConfirmDialog as o, ErrorLine as s, RelativeTime as c, formatDate as l, useAction as u } from "../social/parts.js";
|
|
7
|
+
import { AdminRoot as d, LoadFailed as f, NoAccess as p, Rows as m } from "./shell.js";
|
|
8
|
+
import { CommentBanDialog as h } from "../social/bans.js";
|
|
9
|
+
import { useFlowClient as g, useStaffAccess as _ } from "../../react/admin.js";
|
|
10
|
+
import { useState as v } from "react";
|
|
11
|
+
import { Fragment as y, jsx as b, jsxs as x } from "react/jsx-runtime";
|
|
12
|
+
import { cn as S } from "cn";
|
|
13
|
+
//#region src/components/admin/user-comment-standing.tsx
|
|
14
|
+
var C = ["bans", "comments"];
|
|
15
|
+
function w(e = {}) {
|
|
16
|
+
return _(C, e);
|
|
17
|
+
}
|
|
18
|
+
function T({ client: e, baseUrl: t, auth: n, guard: r, appearance: i, className: a, language: o, messages: s, ...c }) {
|
|
19
|
+
let l = g({
|
|
20
|
+
client: e,
|
|
21
|
+
baseUrl: t,
|
|
22
|
+
auth: n
|
|
23
|
+
});
|
|
24
|
+
return /* @__PURE__ */ b(d, {
|
|
25
|
+
flow: "user-comment-standing",
|
|
26
|
+
appearance: i,
|
|
27
|
+
className: a,
|
|
28
|
+
language: o,
|
|
29
|
+
messages: s,
|
|
30
|
+
guard: r,
|
|
31
|
+
children: /* @__PURE__ */ b(E, {
|
|
32
|
+
...c,
|
|
33
|
+
client: l
|
|
34
|
+
})
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function E(t) {
|
|
38
|
+
let { t: n } = e(), r = w({ client: t.client }), i = /* @__PURE__ */ b("h3", {
|
|
39
|
+
className: "text-base font-semibold",
|
|
40
|
+
children: n("standing.title")
|
|
41
|
+
});
|
|
42
|
+
return r.loading ? /* @__PURE__ */ x(y, { children: [i, /* @__PURE__ */ b(m, { count: 2 })] }) : r.any ? /* @__PURE__ */ x(y, { children: [
|
|
43
|
+
i,
|
|
44
|
+
r.allowed.bans && /* @__PURE__ */ b(D, { ...t }),
|
|
45
|
+
r.allowed.comments && /* @__PURE__ */ b(k, { ...t })
|
|
46
|
+
] }) : /* @__PURE__ */ x(y, { children: [i, /* @__PURE__ */ b(p, { children: n("standing.noAccess") })] });
|
|
47
|
+
}
|
|
48
|
+
function D({ user: n, name: c, client: d, onError: p }) {
|
|
49
|
+
let m = e(), { t: g } = m, _ = r(n, { client: d }), [y, S] = v(!1), [C, w] = v(!1), T = u("ban.lift", p), E = c ?? _.ban?.user?.username ?? n, D = _.ban;
|
|
50
|
+
return /* @__PURE__ */ x("section", {
|
|
51
|
+
className: "grid gap-2 rounded-lg border border-border p-3",
|
|
52
|
+
"data-ckui": "standing-ban",
|
|
53
|
+
"aria-busy": _.loading,
|
|
54
|
+
children: [
|
|
55
|
+
/* @__PURE__ */ b("h4", {
|
|
56
|
+
className: "font-medium",
|
|
57
|
+
children: g("standing.ban")
|
|
58
|
+
}),
|
|
59
|
+
_.loading && !D ? /* @__PURE__ */ b(a, { className: "h-10 w-full" }) : _.error ? /* @__PURE__ */ b(f, {
|
|
60
|
+
error: _.error,
|
|
61
|
+
message: g("standing.banLoadFailed"),
|
|
62
|
+
retry: _.reload
|
|
63
|
+
}) : D ? /* @__PURE__ */ x("div", {
|
|
64
|
+
className: "flex flex-wrap items-start justify-between gap-3",
|
|
65
|
+
children: [/* @__PURE__ */ x("div", {
|
|
66
|
+
className: "grid min-w-0 gap-0.5",
|
|
67
|
+
children: [
|
|
68
|
+
/* @__PURE__ */ b("div", { children: /* @__PURE__ */ b(i, {
|
|
69
|
+
variant: D.expired ? "outline" : "destructive",
|
|
70
|
+
children: g(D.expired ? "bans.expired" : "bans.active")
|
|
71
|
+
}) }),
|
|
72
|
+
D.reason && /* @__PURE__ */ b("p", {
|
|
73
|
+
className: "break-words",
|
|
74
|
+
children: g("bans.reason", { reason: D.reason })
|
|
75
|
+
}),
|
|
76
|
+
/* @__PURE__ */ x("p", {
|
|
77
|
+
className: "text-muted-foreground",
|
|
78
|
+
children: [
|
|
79
|
+
D.until ? g("bans.until", { date: l(m, D.until) }) : g("bans.untilLifted"),
|
|
80
|
+
" · ",
|
|
81
|
+
g("bans.bannedAt", { date: l(m, D.banned_at, !1) })
|
|
82
|
+
]
|
|
83
|
+
})
|
|
84
|
+
]
|
|
85
|
+
}), /* @__PURE__ */ x("div", {
|
|
86
|
+
className: "flex gap-2",
|
|
87
|
+
children: [/* @__PURE__ */ b(t, {
|
|
88
|
+
size: "sm",
|
|
89
|
+
variant: "outline",
|
|
90
|
+
onClick: () => S(!0),
|
|
91
|
+
children: g("bans.update")
|
|
92
|
+
}), /* @__PURE__ */ b(t, {
|
|
93
|
+
size: "sm",
|
|
94
|
+
variant: "destructive",
|
|
95
|
+
onClick: () => w(!0),
|
|
96
|
+
children: g("bans.lift")
|
|
97
|
+
})]
|
|
98
|
+
})]
|
|
99
|
+
}) : /* @__PURE__ */ x("div", {
|
|
100
|
+
className: "flex flex-wrap items-center justify-between gap-2",
|
|
101
|
+
children: [/* @__PURE__ */ b("p", {
|
|
102
|
+
className: "text-muted-foreground",
|
|
103
|
+
children: g("standing.notBanned")
|
|
104
|
+
}), /* @__PURE__ */ b(t, {
|
|
105
|
+
size: "sm",
|
|
106
|
+
variant: "destructive",
|
|
107
|
+
onClick: () => S(!0),
|
|
108
|
+
children: g("comments.ban")
|
|
109
|
+
})]
|
|
110
|
+
}),
|
|
111
|
+
/* @__PURE__ */ b(s, { error: T.error }),
|
|
112
|
+
y && /* @__PURE__ */ b(h, {
|
|
113
|
+
open: !0,
|
|
114
|
+
onOpenChange: S,
|
|
115
|
+
user: {
|
|
116
|
+
id: n,
|
|
117
|
+
name: E
|
|
118
|
+
},
|
|
119
|
+
scopes: ["global"],
|
|
120
|
+
ban: D,
|
|
121
|
+
client: d,
|
|
122
|
+
onError: p
|
|
123
|
+
}),
|
|
124
|
+
/* @__PURE__ */ b(o, {
|
|
125
|
+
open: C,
|
|
126
|
+
onOpenChange: w,
|
|
127
|
+
title: g("bans.liftTitle", { name: E }),
|
|
128
|
+
description: g("bans.liftBody"),
|
|
129
|
+
confirm: g("bans.lift"),
|
|
130
|
+
onConfirm: () => void T.run(_.lift)
|
|
131
|
+
})
|
|
132
|
+
]
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function O(e) {
|
|
136
|
+
return e.deleted ? "deleted" : e.moderation === "held" ? "held" : e.moderation === "rejected" ? "rejected" : "published";
|
|
137
|
+
}
|
|
138
|
+
function k({ user: r, client: a, itemHref: o, pageSize: l = 10, onError: d }) {
|
|
139
|
+
let { t: p } = e(), h = n({
|
|
140
|
+
author: r,
|
|
141
|
+
pageSize: l,
|
|
142
|
+
client: a
|
|
143
|
+
}), g = u("comment.delete", d), _ = u("comment.restore", d);
|
|
144
|
+
return /* @__PURE__ */ x("section", {
|
|
145
|
+
className: "grid gap-2",
|
|
146
|
+
"data-ckui": "standing-comments",
|
|
147
|
+
children: [
|
|
148
|
+
/* @__PURE__ */ b("h4", {
|
|
149
|
+
className: "font-medium",
|
|
150
|
+
children: p("standing.comments")
|
|
151
|
+
}),
|
|
152
|
+
/* @__PURE__ */ b(s, { error: g.error ?? _.error }),
|
|
153
|
+
h.loading && !h.items.length ? /* @__PURE__ */ b(m, { count: 2 }) : h.error && !h.items.length ? /* @__PURE__ */ b(f, {
|
|
154
|
+
error: h.error,
|
|
155
|
+
message: p("moderation.loadFailed"),
|
|
156
|
+
retry: h.reload
|
|
157
|
+
}) : h.items.length ? /* @__PURE__ */ b("ul", {
|
|
158
|
+
className: "grid divide-y divide-border rounded-lg border border-border",
|
|
159
|
+
children: h.items.map((e) => {
|
|
160
|
+
let n = O(e), r = o?.({
|
|
161
|
+
kind: e.content_kind,
|
|
162
|
+
id: e.content_id
|
|
163
|
+
});
|
|
164
|
+
return /* @__PURE__ */ x("li", {
|
|
165
|
+
className: "grid gap-1.5 p-3",
|
|
166
|
+
"data-ckui": "admin-comment",
|
|
167
|
+
"data-status": n,
|
|
168
|
+
children: [
|
|
169
|
+
/* @__PURE__ */ x("div", {
|
|
170
|
+
className: "flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground",
|
|
171
|
+
children: [
|
|
172
|
+
/* @__PURE__ */ b(c, { at: e.created_at }),
|
|
173
|
+
/* @__PURE__ */ b(i, {
|
|
174
|
+
variant: n === "published" ? "outline" : n === "held" ? "secondary" : "destructive",
|
|
175
|
+
children: p(`moderation.${n}`)
|
|
176
|
+
}),
|
|
177
|
+
/* @__PURE__ */ x("span", { children: [
|
|
178
|
+
p("moderation.on"),
|
|
179
|
+
" ",
|
|
180
|
+
r ? /* @__PURE__ */ x("a", {
|
|
181
|
+
className: "hover:underline",
|
|
182
|
+
href: r,
|
|
183
|
+
children: [
|
|
184
|
+
e.content_kind,
|
|
185
|
+
"/",
|
|
186
|
+
e.content_id
|
|
187
|
+
]
|
|
188
|
+
}) : `${e.content_kind}/${e.content_id}`
|
|
189
|
+
] })
|
|
190
|
+
]
|
|
191
|
+
}),
|
|
192
|
+
/* @__PURE__ */ b("p", {
|
|
193
|
+
className: S("line-clamp-3 break-words whitespace-pre-wrap", e.deleted && "text-muted-foreground line-through"),
|
|
194
|
+
children: e.body
|
|
195
|
+
}),
|
|
196
|
+
/* @__PURE__ */ b("div", { children: e.deleted ? /* @__PURE__ */ b(t, {
|
|
197
|
+
size: "sm",
|
|
198
|
+
variant: "outline",
|
|
199
|
+
disabled: _.pending,
|
|
200
|
+
onClick: () => void _.run(() => a.comments.restore(e.id)),
|
|
201
|
+
children: p("moderation.restore")
|
|
202
|
+
}) : /* @__PURE__ */ b(t, {
|
|
203
|
+
size: "sm",
|
|
204
|
+
variant: "destructive",
|
|
205
|
+
disabled: g.pending,
|
|
206
|
+
onClick: () => void g.run(() => a.comments.delete(e.id)),
|
|
207
|
+
children: p("moderation.delete")
|
|
208
|
+
}) })
|
|
209
|
+
]
|
|
210
|
+
}, e.id);
|
|
211
|
+
})
|
|
212
|
+
}) : /* @__PURE__ */ b("p", {
|
|
213
|
+
className: "text-muted-foreground",
|
|
214
|
+
children: p("standing.noComments")
|
|
215
|
+
}),
|
|
216
|
+
h.hasMore && /* @__PURE__ */ b(t, {
|
|
217
|
+
variant: "outline",
|
|
218
|
+
className: "justify-self-center",
|
|
219
|
+
disabled: h.loadingMore,
|
|
220
|
+
onClick: () => void h.loadMore(),
|
|
221
|
+
children: p("moderation.loadMore")
|
|
222
|
+
})
|
|
223
|
+
]
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
//#endregion
|
|
227
|
+
export { T as UserCommentStanding, w as useUserCommentStandingAccess };
|
|
228
|
+
|
|
229
|
+
//# sourceMappingURL=user-comment-standing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-comment-standing.js","names":[],"sources":["../../../src/components/admin/user-comment-standing.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport { useState } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { AdminComment } from \"../../client/generated/wire.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { useFlowClient, useStaffAccess, type FlowClientOptions, type StaffAccess } from \"../../react/admin.js\";\nimport { useAdminComments, useGlobalCommentBan } from \"../../react/comments.js\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { CommentBanDialog } from \"../social/bans.js\";\nimport { ConfirmDialog, ErrorLine, formatDate, RelativeTime, useAction } from \"../social/parts.js\";\nimport { AdminRoot, LoadFailed, NoAccess, Rows, type AdminFlowProps } from \"./shell.js\";\n\nexport interface UserCommentStandingProps extends AdminFlowProps {\n /** The user's id. */\n user: string;\n /** Their name in headings and dialogs; else their username once known. */\n name?: string;\n /** A link to a commented item. */\n itemHref?: (item: { kind: string; id: string }) => string | undefined;\n /** Comments per page. Default 10. */\n pageSize?: number;\n}\n\ntype StandingArea = \"bans\" | \"comments\";\nconst AREAS: readonly StandingArea[] = [\"bans\", \"comments\"];\n\n/** Whether the caller may manage site-wide comment bans and moderate comments: what UserCommentStanding shows. */\nexport function useUserCommentStandingAccess(o: FlowClientOptions = {}): StaffAccess<StandingArea> {\n return useStaffAccess(AREAS, o);\n}\n\n/**\n * A user page's comment panel: the person's site-wide comment ban (ban,\n * replace, lift) and their recent comments (delete, restore), each as the\n * caller's permissions allow.\n */\nexport function UserCommentStanding({ client: own, baseUrl, auth, guard, appearance, className, language, messages, ...p }: UserCommentStandingProps) {\n const client = useFlowClient({ client: own, baseUrl, auth });\n return (\n <AdminRoot flow=\"user-comment-standing\" appearance={appearance} className={className} language={language} messages={messages} guard={guard}>\n <Standing {...p} client={client} />\n </AdminRoot>\n );\n}\n\ntype Inner = Omit<UserCommentStandingProps, \"client\" | \"baseUrl\" | \"auth\" | \"guard\" | \"appearance\" | \"className\" | \"language\" | \"messages\"> & { client: ContentKitClient };\n\nfunction Standing(p: Inner) {\n const { t } = useMessages();\n const access = useUserCommentStandingAccess({ client: p.client });\n const title = <h3 className=\"text-base font-semibold\">{t(\"standing.title\")}</h3>;\n if (access.loading)\n return (\n <>\n {title}\n <Rows count={2} />\n </>\n );\n if (!access.any)\n return (\n <>\n {title}\n <NoAccess>{t(\"standing.noAccess\")}</NoAccess>\n </>\n );\n return (\n <>\n {title}\n {access.allowed.bans && <BanCard {...p} />}\n {access.allowed.comments && <Recent {...p} />}\n </>\n );\n}\n\nfunction BanCard({ user, name, client, onError }: Inner) {\n const m = useMessages();\n const { t } = m;\n const g = useGlobalCommentBan(user, { client });\n const [editing, setEditing] = useState(false);\n const [lifting, setLifting] = useState(false);\n const lift = useAction(\"ban.lift\", onError);\n const who = name ?? g.ban?.user?.username ?? user;\n const ban = g.ban;\n return (\n <section className=\"grid gap-2 rounded-lg border border-border p-3\" data-ckui=\"standing-ban\" aria-busy={g.loading}>\n <h4 className=\"font-medium\">{t(\"standing.ban\")}</h4>\n {g.loading && !ban ? (\n <Skeleton className=\"h-10 w-full\" />\n ) : g.error ? (\n <LoadFailed error={g.error} message={t(\"standing.banLoadFailed\")} retry={g.reload} />\n ) : !ban ? (\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <p className=\"text-muted-foreground\">{t(\"standing.notBanned\")}</p>\n <Button size=\"sm\" variant=\"destructive\" onClick={() => setEditing(true)}>\n {t(\"comments.ban\")}\n </Button>\n </div>\n ) : (\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"grid min-w-0 gap-0.5\">\n <div>\n <Badge variant={ban.expired ? \"outline\" : \"destructive\"}>{t(ban.expired ? \"bans.expired\" : \"bans.active\")}</Badge>\n </div>\n {ban.reason && <p className=\"break-words\">{t(\"bans.reason\", { reason: ban.reason })}</p>}\n <p className=\"text-muted-foreground\">\n {ban.until ? t(\"bans.until\", { date: formatDate(m, ban.until) }) : t(\"bans.untilLifted\")} · {t(\"bans.bannedAt\", { date: formatDate(m, ban.banned_at, false) })}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button size=\"sm\" variant=\"outline\" onClick={() => setEditing(true)}>\n {t(\"bans.update\")}\n </Button>\n <Button size=\"sm\" variant=\"destructive\" onClick={() => setLifting(true)}>\n {t(\"bans.lift\")}\n </Button>\n </div>\n </div>\n )}\n <ErrorLine error={lift.error} />\n {editing && <CommentBanDialog open onOpenChange={setEditing} user={{ id: user, name: who }} scopes={[\"global\"]} ban={ban} client={client} onError={onError} />}\n <ConfirmDialog\n open={lifting}\n onOpenChange={setLifting}\n title={t(\"bans.liftTitle\", { name: who })}\n description={t(\"bans.liftBody\")}\n confirm={t(\"bans.lift\")}\n onConfirm={() => void lift.run(g.lift)}\n />\n </section>\n );\n}\n\nfunction status(c: AdminComment): \"deleted\" | \"held\" | \"rejected\" | \"published\" {\n if (c.deleted) return \"deleted\";\n return c.moderation === \"held\" ? \"held\" : c.moderation === \"rejected\" ? \"rejected\" : \"published\";\n}\n\nfunction Recent({ user, client, itemHref, pageSize = 10, onError }: Inner) {\n const { t } = useMessages();\n const list = useAdminComments({ author: user, pageSize, client });\n const del = useAction(\"comment.delete\", onError);\n const restore = useAction(\"comment.restore\", onError);\n return (\n <section className=\"grid gap-2\" data-ckui=\"standing-comments\">\n <h4 className=\"font-medium\">{t(\"standing.comments\")}</h4>\n <ErrorLine error={del.error ?? restore.error} />\n {list.loading && !list.items.length ? (\n <Rows count={2} />\n ) : list.error && !list.items.length ? (\n <LoadFailed error={list.error} message={t(\"moderation.loadFailed\")} retry={list.reload} />\n ) : !list.items.length ? (\n <p className=\"text-muted-foreground\">{t(\"standing.noComments\")}</p>\n ) : (\n <ul className=\"grid divide-y divide-border rounded-lg border border-border\">\n {list.items.map((c) => {\n const s = status(c);\n const href = itemHref?.({ kind: c.content_kind, id: c.content_id });\n return (\n <li key={c.id} className=\"grid gap-1.5 p-3\" data-ckui=\"admin-comment\" data-status={s}>\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground\">\n <RelativeTime at={c.created_at} />\n <Badge variant={s === \"published\" ? \"outline\" : s === \"held\" ? \"secondary\" : \"destructive\"}>{t(`moderation.${s}`)}</Badge>\n <span>\n {t(\"moderation.on\")}{\" \"}\n {href ? (\n <a className=\"hover:underline\" href={href}>\n {c.content_kind}/{c.content_id}\n </a>\n ) : (\n `${c.content_kind}/${c.content_id}`\n )}\n </span>\n </div>\n <p className={cn(\"line-clamp-3 break-words whitespace-pre-wrap\", c.deleted && \"text-muted-foreground line-through\")}>{c.body}</p>\n <div>\n {c.deleted ? (\n <Button size=\"sm\" variant=\"outline\" disabled={restore.pending} onClick={() => void restore.run(() => client.comments.restore(c.id))}>\n {t(\"moderation.restore\")}\n </Button>\n ) : (\n <Button size=\"sm\" variant=\"destructive\" disabled={del.pending} onClick={() => void del.run(() => client.comments.delete(c.id))}>\n {t(\"moderation.delete\")}\n </Button>\n )}\n </div>\n </li>\n );\n })}\n </ul>\n )}\n {list.hasMore && (\n <Button variant=\"outline\" className=\"justify-self-center\" disabled={list.loadingMore} onClick={() => void list.loadMore()}>\n {t(\"moderation.loadMore\")}\n </Button>\n )}\n </section>\n );\n}\n\n"],"mappings":"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"}
|
|
@@ -32,11 +32,14 @@ export interface CommentBansProps {
|
|
|
32
32
|
/** "global": the site's bans (CommentBan); "owner": the caller's own. Default "global". */
|
|
33
33
|
scope?: BanScope;
|
|
34
34
|
pageSize?: number;
|
|
35
|
+
/** The page shown (from 1), when the host keeps it, e.g. in the URL; with onPageChange. */
|
|
36
|
+
page?: number;
|
|
37
|
+
onPageChange?: (page: number) => void;
|
|
35
38
|
userHref?: (user: PublicUser) => string | undefined;
|
|
36
39
|
client?: ContentKitClient;
|
|
37
40
|
onError?: ContentKitErrorHandler;
|
|
38
41
|
className?: string;
|
|
39
42
|
appearance?: ContentKitUiAppearance;
|
|
40
43
|
}
|
|
41
|
-
/** A scope's comment bans, newest first: who, why, until when; ban a user by id, update or lift a ban. */
|
|
42
|
-
export declare function CommentBans({ scope, pageSize, userHref, client, onError, className, appearance }: CommentBansProps): import('react').JSX.Element;
|
|
44
|
+
/** A scope's comment bans, newest first, a page at a time: who, why, until when; ban a user by id, update or lift a ban. */
|
|
45
|
+
export declare function CommentBans({ scope, pageSize, page: shown, onPageChange, userHref, client: own, onError, className, appearance }: CommentBansProps): import('react').JSX.Element;
|