@openrails/contentkit-ui 0.91.0 → 0.93.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.
Files changed (83) hide show
  1. package/README.md +8 -6
  2. package/dist/client/client.d.ts +2 -2
  3. package/dist/client/client.js +2 -2
  4. package/dist/client/client.js.map +1 -1
  5. package/dist/client/content/comments.js +3 -3
  6. package/dist/client/content/comments.js.map +1 -1
  7. package/dist/client/content/favorites.d.ts +2 -2
  8. package/dist/client/content/favorites.js +2 -2
  9. package/dist/client/content/favorites.js.map +1 -1
  10. package/dist/client/content/reactions.js +2 -2
  11. package/dist/client/content/reactions.js.map +1 -1
  12. package/dist/client/content/types.d.ts +2 -2
  13. package/dist/client/content/types.js.map +1 -1
  14. package/dist/client/contents.d.ts +4 -2
  15. package/dist/client/contents.js +7 -2
  16. package/dist/client/contents.js.map +1 -1
  17. package/dist/client/discovery.d.ts +2 -2
  18. package/dist/client/discovery.js +2 -2
  19. package/dist/client/discovery.js.map +1 -1
  20. package/dist/client/{groups.d.ts → entities.d.ts} +14 -14
  21. package/dist/client/{groups.js → entities.js} +19 -19
  22. package/dist/client/entities.js.map +1 -0
  23. package/dist/client/generated/error-codes.d.ts +1 -1
  24. package/dist/client/generated/error-codes.js +28 -0
  25. package/dist/client/generated/error-codes.js.map +1 -1
  26. package/dist/client/generated/routes.d.ts +158 -106
  27. package/dist/client/generated/routes.js +190 -106
  28. package/dist/client/generated/routes.js.map +1 -1
  29. package/dist/client/generated/wire.d.ts +75 -12
  30. package/dist/client/generated/wire.js.map +1 -1
  31. package/dist/client/http.d.ts +4 -2
  32. package/dist/client/http.js.map +1 -1
  33. package/dist/client/index.d.ts +1 -1
  34. package/dist/client/offers.js +4 -4
  35. package/dist/client/offers.js.map +1 -1
  36. package/dist/client.js +2 -2
  37. package/dist/components/admin/content-admin.js +1 -1
  38. package/dist/components/admin/content-admin.js.map +1 -1
  39. package/dist/components/admin/group-manager.js +2 -2
  40. package/dist/components/admin/group-manager.js.map +1 -1
  41. package/dist/components/content/card.js +3 -3
  42. package/dist/components/content/card.js.map +1 -1
  43. package/dist/components/content/editors.js +2 -2
  44. package/dist/components/content/editors.js.map +1 -1
  45. package/dist/components/content/filters.js +6 -6
  46. package/dist/components/content/filters.js.map +1 -1
  47. package/dist/components/content/search.js +3 -3
  48. package/dist/components/content/search.js.map +1 -1
  49. package/dist/components/groups/banner.d.ts +2 -2
  50. package/dist/components/groups/banner.js.map +1 -1
  51. package/dist/components/groups/editor.js +2 -2
  52. package/dist/components/groups/editor.js.map +1 -1
  53. package/dist/components/groups/header.js +1 -1
  54. package/dist/components/groups/header.js.map +1 -1
  55. package/dist/components/groups/memberships.js +6 -6
  56. package/dist/components/groups/memberships.js.map +1 -1
  57. package/dist/components/groups/parts.js +4 -4
  58. package/dist/components/groups/parts.js.map +1 -1
  59. package/dist/locales/de.js +7 -0
  60. package/dist/locales/de.js.map +1 -1
  61. package/dist/locales/en.d.ts +7 -0
  62. package/dist/locales/en.js +7 -0
  63. package/dist/locales/en.js.map +1 -1
  64. package/dist/locales/es.js +7 -0
  65. package/dist/locales/es.js.map +1 -1
  66. package/dist/locales/ja.js +7 -0
  67. package/dist/locales/ja.js.map +1 -1
  68. package/dist/locales/ko.js +7 -0
  69. package/dist/locales/ko.js.map +1 -1
  70. package/dist/locales/zh.js +7 -0
  71. package/dist/locales/zh.js.map +1 -1
  72. package/dist/react/admin.js +1 -1
  73. package/dist/react/admin.js.map +1 -1
  74. package/dist/react/discovery.d.ts +1 -1
  75. package/dist/react/discovery.js +5 -5
  76. package/dist/react/discovery.js.map +1 -1
  77. package/dist/react/groups.d.ts +5 -5
  78. package/dist/react/groups.js +21 -21
  79. package/dist/react/groups.js.map +1 -1
  80. package/dist/react/resources.js +1 -1
  81. package/dist/react/resources.js.map +1 -1
  82. package/package.json +2 -2
  83. package/dist/client/groups.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"banner.js","names":[],"sources":["../../../src/components/groups/banner.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport { useContext, useRef, useState, type ReactNode } from \"react\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { Edit, GroupAccess, GroupDetail, Sale } from \"../../client/generated/wire.js\";\nimport type { GroupImageSlot } from \"../../client/groups.js\";\nimport { decodeImage, type CropSource } from \"../../client/image.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { ContentKitContext, useContentKitClient, type ContentKitErrorHandler } from \"../../react/context.js\";\nimport { useGroup } from \"../../react/groups.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { ImageCropDialog } from \"../image-crop-dialog.js\";\nimport { contentError, ErrorLine, useAction } from \"../social/parts.js\";\nimport { priceLabel } from \"../content/paywall.js\";\nimport { GroupAvatar, GroupCover, type GroupLike } from \"./parts.js\";\n\nexport interface MembershipBoxProps {\n group: Pick<GroupDetail, \"id\" | \"kind\" | \"name\"> & { access?: GroupAccess };\n /** Buys a sold membership: the host creates the order through billing-ui. */\n onCheckout?: (o: { key: string; offer: Sale }) => void;\n /** Asks a signed-out visitor to sign in; default the provider's. */\n onSignIn?: () => void;\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/** A group's membership for the reader: member, join free, or join for its price; nothing to join while it sells no membership. */\nexport function MembershipBox({ group, onCheckout, onSignIn, client: own, onError, className, appearance }: MembershipBoxProps) {\n const m = useMessages();\n const { t } = m;\n const client = useContentKitClient(own);\n const ctx = useContext(ContentKitContext);\n const join = useAction(\"membership.join\", onError);\n const a = group.access;\n if (!a || a.editor || (!a.offer && !a.member && !a.unknown)) return null;\n const signedOut = ctx?.viewer === null;\n const signIn = onSignIn ?? ctx?.onSignIn;\n const offer: Sale | undefined = a.offer && Number(a.offer.terms.amount) > 0 ? a.offer : undefined;\n return (\n <ContentKitUiRoot appearance={appearance} className={cn(\"grid gap-2 rounded-lg border border-border p-3 text-sm\", className)} data-ckui=\"membership-box\" data-member={a.member}>\n {a.unknown ? (\n <p className=\"text-muted-foreground\">{t(\"membership.unknown\")}</p>\n ) : a.member ? (\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge>{t(\"membership.member\")}</Badge>\n {!offer && (\n <Button size=\"sm\" variant=\"ghost\" disabled={join.pending} onClick={() => void join.run(() => client.offers.join(group.id, false))}>\n {t(\"membership.leave\")}\n </Button>\n )}\n </div>\n ) : (\n <div className=\"grid gap-2\">\n <p className=\"text-muted-foreground\">{t(offer ? \"membership.paidPitch\" : \"membership.freePitch\")}</p>\n <Button\n size=\"sm\"\n className=\"justify-self-start\"\n disabled={join.pending || (!!offer && !onCheckout)}\n onClick={() => {\n if (signedOut && signIn) return signIn();\n if (offer) return onCheckout?.({ key: a.key, offer });\n void join.run(() => client.offers.join(group.id));\n }}\n >\n {offer ? t(\"membership.joinFor\", { price: priceLabel(m, offer.terms) }) : t(\"membership.join\")}\n </Button>\n </div>\n )}\n {join.error && <ErrorLine>{contentError(m, join.error)}</ErrorLine>}\n </ContentKitUiRoot>\n );\n}\n\nexport interface GroupBannerProps {\n /** The group the host already read; or give id. */\n group?: GroupDetail;\n id?: string;\n language?: string;\n onCheckout?: MembershipBoxProps[\"onCheckout\"];\n /** Beside the membership box: the host's actions (follow, share, edit). */\n children?: ReactNode;\n client?: ContentKitClient;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/** A group's page head: its cover across, its avatar, name, description, content count and membership. */\nexport function GroupBanner(p: GroupBannerProps) {\n const m = useMessages();\n const read = useGroup(p.group ? null : p.id, { language: p.language, client: p.client });\n const g = p.group ?? read.group;\n if (!g) return read.error ? <ErrorLine>{contentError(m, read.error)}</ErrorLine> : <Skeleton className=\"h-48 w-full\" />;\n const text = g.text.find((x) => x.language === (p.language ?? g.name_language)) ?? g.text.find((x) => x.description);\n const count = g.counts.filter((c) => c.language === (p.language ?? \"\")).reduce((n, c) => n + c.count, 0);\n return (\n <ContentKitUiRoot appearance={p.appearance} className={cn(\"grid gap-3 text-sm\", p.className)} data-ckui=\"group-banner\" data-kind={g.kind}>\n <GroupCover group={g} className=\"aspect-[3/1] w-full\" />\n <div className=\"flex flex-wrap items-end gap-4 px-2 sm:px-4\">\n <GroupAvatar group={g} className=\"-mt-12 size-20 border-4 border-background sm:-mt-16 sm:size-28\" />\n <div className=\"grid min-w-0 flex-1 gap-1\">\n <h1 className=\"text-xl font-semibold break-words\">{g.name || g.slug}</h1>\n <p className=\"text-xs text-muted-foreground tabular-nums\">{m.plural(\"groups.items\", count)}</p>\n </div>\n <div className=\"flex flex-wrap items-start gap-2\">\n <MembershipBox group={g} onCheckout={p.onCheckout} client={p.client} />\n {p.children}\n </div>\n </div>\n {text?.description && <p className=\"px-2 break-words whitespace-pre-line sm:px-4\">{text.description}</p>}\n </ContentKitUiRoot>\n );\n}\n\nexport interface GroupImageEditorProps {\n group: GroupLike;\n /** The cover, or a user-owned kind's avatar. */\n slot: GroupImageSlot;\n /** Crop before uploading. Default true. */\n crop?: boolean;\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n}\n\n/** A group's cover or avatar for its editors: pick (and crop) an image, upload it and select it; or go back to none (a cover: automatic). */\nexport function GroupImageEditor({ group, slot, crop = true, client, onError, className }: GroupImageEditorProps) {\n const { t } = useMessages();\n const g = useGroup(group.id, { client });\n const input = useRef<HTMLInputElement>(null);\n const save = useAction(\"group.save\", onError);\n const [source, setSource] = useState<CropSource | null>(null);\n const [file, setFile] = useState<File | null>(null);\n const shown = g.group ?? group;\n const set = slot === \"cover\" ? !!shown.cover?.image || (!!shown.cover?.content_id && !shown.cover.auto) : !!shown.avatar?.image;\n const upload = (f: Blob & { name?: string }, edit?: Edit) => save.run(() => g.uploadImage(slot, f, { wait: false, edit }));\n const close = () => {\n source?.revoke?.();\n setSource(null);\n setFile(null);\n };\n return (\n <div className={cn(\"flex flex-wrap items-center gap-3\", className)} data-ckui=\"group-image-editor\" data-slot={slot}>\n {slot === \"avatar\" ? <GroupAvatar group={shown} src={g.previews.avatar} className=\"size-16\" /> : <GroupCover group={shown} src={g.previews.cover} className=\"aspect-[3/1] w-48\" />}\n <div className=\"grid gap-2\">\n <div className=\"flex flex-wrap gap-2\">\n <Button type=\"button\" size=\"sm\" variant=\"outline\" disabled={save.pending} onClick={() => input.current?.click()}>\n {save.pending ? t(\"groupEditor.uploading\") : t(slot === \"avatar\" ? \"groupEditor.uploadAvatar\" : \"groupEditor.uploadCover\")}\n </Button>\n {set && (\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" disabled={save.pending} onClick={() => void save.run(() => g.update(slot === \"cover\" ? { cover: {} } : { avatar: {} }))}>\n {t(slot === \"avatar\" ? \"groupEditor.removeAvatar\" : \"groupEditor.coverUseAuto\")}\n </Button>\n )}\n </div>\n <input\n ref={input}\n type=\"file\"\n accept=\"image/*\"\n hidden\n aria-label={t(slot === \"avatar\" ? \"groupEditor.uploadAvatar\" : \"groupEditor.uploadCover\")}\n onChange={(e) => {\n const f = e.target.files?.[0];\n e.target.value = \"\";\n if (!f) return;\n if (!crop) return void upload(f);\n decodeImage(f).then(\n (s) => {\n setFile(f);\n setSource(s);\n },\n () => void upload(f),\n );\n }}\n />\n <ErrorLine error={save.error} />\n </div>\n <ImageCropDialog\n open={!!source}\n onOpenChange={(open) => !open && close()}\n source={source}\n aspect={slot === \"avatar\" ? \"1:1\" : \"3:1\"}\n aspects={slot === \"avatar\" ? undefined : [\"3:1\", \"16:9\", \"\"]}\n round={slot === \"avatar\"}\n onConfirm={(edit) => {\n const f = file;\n close();\n if (f) void upload(f, edit ?? undefined);\n }}\n />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"banner.js","names":[],"sources":["../../../src/components/groups/banner.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport { useContext, useRef, useState, type ReactNode } from \"react\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { Edit, GroupAccess, GroupDetail, Sale } from \"../../client/generated/wire.js\";\nimport type { EntityImageSlot } from \"../../client/entities.js\";\nimport { decodeImage, type CropSource } from \"../../client/image.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { ContentKitContext, useContentKitClient, type ContentKitErrorHandler } from \"../../react/context.js\";\nimport { useGroup } from \"../../react/groups.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { ImageCropDialog } from \"../image-crop-dialog.js\";\nimport { contentError, ErrorLine, useAction } from \"../social/parts.js\";\nimport { priceLabel } from \"../content/paywall.js\";\nimport { GroupAvatar, GroupCover, type GroupLike } from \"./parts.js\";\n\nexport interface MembershipBoxProps {\n group: Pick<GroupDetail, \"id\" | \"kind\" | \"name\"> & { access?: GroupAccess };\n /** Buys a sold membership: the host creates the order through billing-ui. */\n onCheckout?: (o: { key: string; offer: Sale }) => void;\n /** Asks a signed-out visitor to sign in; default the provider's. */\n onSignIn?: () => void;\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/** A group's membership for the reader: member, join free, or join for its price; nothing to join while it sells no membership. */\nexport function MembershipBox({ group, onCheckout, onSignIn, client: own, onError, className, appearance }: MembershipBoxProps) {\n const m = useMessages();\n const { t } = m;\n const client = useContentKitClient(own);\n const ctx = useContext(ContentKitContext);\n const join = useAction(\"membership.join\", onError);\n const a = group.access;\n if (!a || a.editor || (!a.offer && !a.member && !a.unknown)) return null;\n const signedOut = ctx?.viewer === null;\n const signIn = onSignIn ?? ctx?.onSignIn;\n const offer: Sale | undefined = a.offer && Number(a.offer.terms.amount) > 0 ? a.offer : undefined;\n return (\n <ContentKitUiRoot appearance={appearance} className={cn(\"grid gap-2 rounded-lg border border-border p-3 text-sm\", className)} data-ckui=\"membership-box\" data-member={a.member}>\n {a.unknown ? (\n <p className=\"text-muted-foreground\">{t(\"membership.unknown\")}</p>\n ) : a.member ? (\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge>{t(\"membership.member\")}</Badge>\n {!offer && (\n <Button size=\"sm\" variant=\"ghost\" disabled={join.pending} onClick={() => void join.run(() => client.offers.join(group.id, false))}>\n {t(\"membership.leave\")}\n </Button>\n )}\n </div>\n ) : (\n <div className=\"grid gap-2\">\n <p className=\"text-muted-foreground\">{t(offer ? \"membership.paidPitch\" : \"membership.freePitch\")}</p>\n <Button\n size=\"sm\"\n className=\"justify-self-start\"\n disabled={join.pending || (!!offer && !onCheckout)}\n onClick={() => {\n if (signedOut && signIn) return signIn();\n if (offer) return onCheckout?.({ key: a.key, offer });\n void join.run(() => client.offers.join(group.id));\n }}\n >\n {offer ? t(\"membership.joinFor\", { price: priceLabel(m, offer.terms) }) : t(\"membership.join\")}\n </Button>\n </div>\n )}\n {join.error && <ErrorLine>{contentError(m, join.error)}</ErrorLine>}\n </ContentKitUiRoot>\n );\n}\n\nexport interface GroupBannerProps {\n /** The group the host already read; or give id. */\n group?: GroupDetail;\n id?: string;\n language?: string;\n onCheckout?: MembershipBoxProps[\"onCheckout\"];\n /** Beside the membership box: the host's actions (follow, share, edit). */\n children?: ReactNode;\n client?: ContentKitClient;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/** A group's page head: its cover across, its avatar, name, description, content count and membership. */\nexport function GroupBanner(p: GroupBannerProps) {\n const m = useMessages();\n const read = useGroup(p.group ? null : p.id, { language: p.language, client: p.client });\n const g = p.group ?? read.group;\n if (!g) return read.error ? <ErrorLine>{contentError(m, read.error)}</ErrorLine> : <Skeleton className=\"h-48 w-full\" />;\n const text = g.text.find((x) => x.language === (p.language ?? g.name_language)) ?? g.text.find((x) => x.description);\n const count = g.counts.filter((c) => c.language === (p.language ?? \"\")).reduce((n, c) => n + c.count, 0);\n return (\n <ContentKitUiRoot appearance={p.appearance} className={cn(\"grid gap-3 text-sm\", p.className)} data-ckui=\"group-banner\" data-kind={g.kind}>\n <GroupCover group={g} className=\"aspect-[3/1] w-full\" />\n <div className=\"flex flex-wrap items-end gap-4 px-2 sm:px-4\">\n <GroupAvatar group={g} className=\"-mt-12 size-20 border-4 border-background sm:-mt-16 sm:size-28\" />\n <div className=\"grid min-w-0 flex-1 gap-1\">\n <h1 className=\"text-xl font-semibold break-words\">{g.name || g.slug}</h1>\n <p className=\"text-xs text-muted-foreground tabular-nums\">{m.plural(\"groups.items\", count)}</p>\n </div>\n <div className=\"flex flex-wrap items-start gap-2\">\n <MembershipBox group={g} onCheckout={p.onCheckout} client={p.client} />\n {p.children}\n </div>\n </div>\n {text?.description && <p className=\"px-2 break-words whitespace-pre-line sm:px-4\">{text.description}</p>}\n </ContentKitUiRoot>\n );\n}\n\nexport interface GroupImageEditorProps {\n group: GroupLike;\n /** The cover, or a user-owned kind's avatar. */\n slot: EntityImageSlot;\n /** Crop before uploading. Default true. */\n crop?: boolean;\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n}\n\n/** A group's cover or avatar for its editors: pick (and crop) an image, upload it and select it; or go back to none (a cover: automatic). */\nexport function GroupImageEditor({ group, slot, crop = true, client, onError, className }: GroupImageEditorProps) {\n const { t } = useMessages();\n const g = useGroup(group.id, { client });\n const input = useRef<HTMLInputElement>(null);\n const save = useAction(\"group.save\", onError);\n const [source, setSource] = useState<CropSource | null>(null);\n const [file, setFile] = useState<File | null>(null);\n const shown = g.group ?? group;\n const set = slot === \"cover\" ? !!shown.cover?.image || (!!shown.cover?.content_id && !shown.cover.auto) : !!shown.avatar?.image;\n const upload = (f: Blob & { name?: string }, edit?: Edit) => save.run(() => g.uploadImage(slot, f, { wait: false, edit }));\n const close = () => {\n source?.revoke?.();\n setSource(null);\n setFile(null);\n };\n return (\n <div className={cn(\"flex flex-wrap items-center gap-3\", className)} data-ckui=\"group-image-editor\" data-slot={slot}>\n {slot === \"avatar\" ? <GroupAvatar group={shown} src={g.previews.avatar} className=\"size-16\" /> : <GroupCover group={shown} src={g.previews.cover} className=\"aspect-[3/1] w-48\" />}\n <div className=\"grid gap-2\">\n <div className=\"flex flex-wrap gap-2\">\n <Button type=\"button\" size=\"sm\" variant=\"outline\" disabled={save.pending} onClick={() => input.current?.click()}>\n {save.pending ? t(\"groupEditor.uploading\") : t(slot === \"avatar\" ? \"groupEditor.uploadAvatar\" : \"groupEditor.uploadCover\")}\n </Button>\n {set && (\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" disabled={save.pending} onClick={() => void save.run(() => g.update(slot === \"cover\" ? { cover: {} } : { avatar: {} }))}>\n {t(slot === \"avatar\" ? \"groupEditor.removeAvatar\" : \"groupEditor.coverUseAuto\")}\n </Button>\n )}\n </div>\n <input\n ref={input}\n type=\"file\"\n accept=\"image/*\"\n hidden\n aria-label={t(slot === \"avatar\" ? \"groupEditor.uploadAvatar\" : \"groupEditor.uploadCover\")}\n onChange={(e) => {\n const f = e.target.files?.[0];\n e.target.value = \"\";\n if (!f) return;\n if (!crop) return void upload(f);\n decodeImage(f).then(\n (s) => {\n setFile(f);\n setSource(s);\n },\n () => void upload(f),\n );\n }}\n />\n <ErrorLine error={save.error} />\n </div>\n <ImageCropDialog\n open={!!source}\n onOpenChange={(open) => !open && close()}\n source={source}\n aspect={slot === \"avatar\" ? \"1:1\" : \"3:1\"}\n aspects={slot === \"avatar\" ? undefined : [\"3:1\", \"16:9\", \"\"]}\n round={slot === \"avatar\"}\n onConfirm={(edit) => {\n const f = file;\n close();\n if (f) void upload(f, edit ?? undefined);\n }}\n />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -22,7 +22,7 @@ import { Fragment as V, jsx as H, jsxs as U } from "react/jsx-runtime";
22
22
  import { cn as W } from "cn";
23
23
  //#region src/components/groups/editor.tsx
24
24
  function G(e) {
25
- let { t } = n(), { kinds: i, loading: c } = o({ client: e.client }), l = a(e.id, { client: e.client }), u = e.languages ?? i?.languages ?? ["en"], d = l.group?.kind ?? e.kind, f = i?.group_kinds?.[d] ?? {}, p = (t) => /* @__PURE__ */ H(r, {
25
+ let { t } = n(), { kinds: i, loading: c } = o({ client: e.client }), l = a(e.id, { client: e.client }), u = e.languages ?? i?.languages ?? ["en"], d = l.group?.kind ?? e.kind, f = i?.entity_kinds?.[d] ?? {}, p = (t) => /* @__PURE__ */ H(r, {
26
26
  appearance: e.appearance,
27
27
  className: W("grid gap-6 text-sm", e.className),
28
28
  "data-ckui": "group-editor",
@@ -760,7 +760,7 @@ function re({ group: e, onError: t, client: r }) {
760
760
  }
761
761
  var ie = /^[a-z][a-z0-9_]*$/;
762
762
  function ae({ group: e, g: t, kinds: r, labels: i, onError: a, client: o }) {
763
- let { t: c } = n(), l = R(), u = E("group.save", a), d = j(e.edges.map((t) => t.from === e.id ? t.to : t.from), { client: o }), f = Object.keys(r?.group_kinds ?? {}).sort(), [p, S] = B(""), [C, T] = B(f[0] ?? e.kind), D = e.edges.filter((t) => t.from === e.id), O = e.edges.filter((t) => t.to === e.id), M = (e) => {
763
+ let { t: c } = n(), l = R(), u = E("group.save", a), d = j(e.edges.map((t) => t.from === e.id ? t.to : t.from), { client: o }), f = Object.keys(r?.entity_kinds ?? {}).sort(), [p, S] = B(""), [C, T] = B(f[0] ?? e.kind), D = e.edges.filter((t) => t.from === e.id), O = e.edges.filter((t) => t.to === e.id), M = (e) => {
764
764
  let t = d.get(e);
765
765
  return t ? t.name || t.slug : e;
766
766
  }, N = ie.test(p.trim());
@@ -1 +1 @@
1
- {"version":3,"file":"editor.js","names":[],"sources":["../../../src/components/groups/editor.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport { useCallback, useEffect, useId, useRef, useState, type ReactNode } from \"react\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport { toContentKitError, type ContentKitError } from \"../../client/errors.js\";\nimport { parseAttributes, slugify } from \"../../client/group-fields.js\";\nimport type { ContentModel, Group, GroupCard, GroupDetail, GroupKind, GroupsText as Text, MergeReport, Name } from \"../../client/generated/wire.js\";\nimport { useLanguageName, useMessages } from \"../../i18n/context.js\";\nimport type { ContentKitErrorHandler } from \"../../react/context.js\";\nimport { useGroup, useKinds, type UseGroup } from \"../../react/groups.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from \"#ckui/ui/dialog\";\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 { Textarea } from \"#ckui/ui/textarea\";\nimport { contentError, ErrorLine, useAction } from \"../social/parts.js\";\nimport { OfferFields } from \"../content/offer-fields.js\";\nimport { AttributeFields, formOf } from \"./fields.js\";\nimport { useContentKitClient } from \"../../react/context.js\";\nimport { GroupImageEditor } from \"./banner.js\";\nimport { GroupPicker, labelOf, useGroupNames, type GroupLike, type Labels } from \"./parts.js\";\n\nexport interface GroupEditorProps {\n /** The group edited; null creates one of `kind`. */\n id: string | null;\n /** The kind a new group is created as. */\n kind: string;\n /** Languages names and text are written in; default the content model's. */\n languages?: readonly string[];\n labels?: Labels;\n onCreated?: (group: Group) => void;\n /** After a merge: the survivor's id is report.into. */\n onMerged?: (report: MergeReport) => void;\n onDeleted?: (group: Group) => void;\n /** Below the editor's sections, with the loaded group: the members, host fields. */\n children?: (group: GroupDetail) => ReactNode;\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n\n/**\n * Staff (root:groups:write): creates a group, or edits one: slug, parent,\n * scope and declared attributes; names and aliases per language; description\n * and sort key per language; cover (an upload, or automatic); edges to other\n * groups; merge into another group; delete and restore.\n */\nexport function GroupEditor(p: GroupEditorProps) {\n const { t } = useMessages();\n const { kinds, loading: kindsLoading } = useKinds({ client: p.client });\n const g = useGroup(p.id, { client: p.client });\n const languages = p.languages ?? kinds?.languages ?? [\"en\"];\n const kind = g.group?.kind ?? p.kind;\n const spec: GroupKind = kinds?.group_kinds?.[kind] ?? {};\n const root = (children: ReactNode) => (\n <ContentKitUiRoot appearance={p.appearance} className={cn(\"grid gap-6 text-sm\", p.className)} data-ckui=\"group-editor\" data-kind={kind}>\n {children}\n </ContentKitUiRoot>\n );\n if (kindsLoading) return root(<Skeleton className=\"h-40 w-full\" />);\n // A group created here is edited in place until the host routes to it.\n if (!p.id && !g.group && !g.loading) return root(<CreateForm {...p} kind={kind} spec={spec} languages={languages} g={g} />);\n if (g.deleted)\n return root(\n <Deleted\n group={g.deleted}\n onRestore={() => g.restore()}\n onError={p.onError}\n name={g.deleted.slug}\n />,\n );\n if (!g.group) {\n if (g.error)\n return root(\n <div role=\"alert\" className=\"grid justify-items-start gap-2\">\n <p className=\"text-destructive\">{t(\"groupEditor.loadFailed\")}</p>\n <Button size=\"sm\" variant=\"outline\" onClick={g.reload}>\n {t(\"common.retry\")}\n </Button>\n </div>,\n );\n return root(<Skeleton className=\"h-40 w-full\" />);\n }\n const group = g.group;\n return root(\n <>\n <Head group={group} g={g} labels={p.labels} onMerged={p.onMerged} onDeleted={p.onDeleted} onError={p.onError} client={p.client} />\n <Details key={group.id} group={group} spec={spec} g={g} labels={p.labels} onError={p.onError} client={p.client} />\n <Names group={group} g={g} languages={languages} onError={p.onError} />\n <Texts key={group.id} group={group} g={g} languages={languages} onError={p.onError} />\n <Images group={group} spec={spec} onError={p.onError} client={p.client} />\n {spec.sellable && <Membership group={group} onError={p.onError} client={p.client} />}\n <Edges group={group} g={g} kinds={kinds} labels={p.labels} onError={p.onError} client={p.client} />\n {p.children?.(group)}\n </>,\n );\n}\n\n/** Form state seeded from the record, seeded again when it changes unless edited since; settle() after a save. */\nfunction useSeeded<T>(seed: () => T, revision: unknown): [T, (next: (prev: T) => T) => void, () => void] {\n const [value, setValue] = useState(seed);\n const edited = useRef(false);\n const latest = useRef(seed);\n latest.current = seed;\n useEffect(() => {\n if (!edited.current) setValue(latest.current());\n }, [revision]);\n const set = useCallback((next: (prev: T) => T) => {\n edited.current = true;\n setValue(next);\n }, []);\n const settle = useCallback(() => {\n edited.current = false;\n }, []);\n return [value, set, settle];\n}\n\nfunction Section({ title, children, ckui, action }: { title: ReactNode; children: ReactNode; ckui: string; action?: ReactNode }) {\n return (\n <section className=\"grid gap-3\" data-ckui={ckui}>\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h3 className=\"font-medium\">{title}</h3>\n {action}\n </div>\n {children}\n </section>\n );\n}\n\nfunction Deleted({ group, name, onRestore, onError }: { group: Group; name: string; onRestore: () => Promise<Group>; onError?: ContentKitErrorHandler }) {\n const { t } = useMessages();\n const restore = useAction(\"group.save\", onError);\n return (\n <div className=\"grid justify-items-start gap-2\" data-ckui=\"group-deleted\" data-state={group.state}>\n <p>{t(\"groupEditor.deletedNotice\", { name })}</p>\n <Button size=\"sm\" variant=\"outline\" disabled={restore.pending} onClick={() => void restore.run(onRestore)}>\n {t(\"groupEditor.restore\")}\n </Button>\n <ErrorLine error={restore.error} />\n </div>\n );\n}\n\nfunction Head({\n group,\n g,\n labels,\n onMerged,\n onDeleted,\n onError,\n client,\n}: {\n group: GroupDetail;\n g: UseGroup;\n labels?: Labels;\n onMerged?: (r: MergeReport) => void;\n onDeleted?: (g: Group) => void;\n onError?: ContentKitErrorHandler;\n client?: ContentKitClient;\n}) {\n const { t } = useMessages();\n const [merging, setMerging] = useState(false);\n const [confirmDelete, setConfirmDelete] = useState(false);\n const remove = useAction(\"group.save\", onError);\n return (\n <div className=\"flex flex-wrap items-center gap-2\" data-ckui=\"group-head\">\n <h2 className=\"text-base font-semibold break-words\">{group.name || group.slug}</h2>\n <Badge variant=\"outline\">{labelOf(labels, group.kind)}</Badge>\n <div className=\"ms-auto flex flex-wrap gap-2\">\n <Button size=\"sm\" variant=\"outline\" onClick={() => setMerging(true)}>\n {t(\"groupEditor.merge\")}\n </Button>\n <Button size=\"sm\" variant=\"destructive\" disabled={remove.pending} onClick={() => setConfirmDelete(true)}>\n {t(\"groupEditor.delete\")}\n </Button>\n </div>\n <ErrorLine error={remove.error} className=\"basis-full\" />\n <GroupMergeDialog\n open={merging}\n onOpenChange={setMerging}\n group={group}\n client={client}\n onMerge={async (into) => {\n const report = await g.merge(into.id);\n onMerged?.(report);\n return report;\n }}\n />\n <Dialog open={confirmDelete} onOpenChange={setConfirmDelete}>\n <DialogContent data-ckui=\"group-delete-dialog\">\n <DialogHeader>\n <DialogTitle>{t(\"groupEditor.deleteTitle\", { name: group.name || group.slug })}</DialogTitle>\n <DialogDescription>{t(\"groupEditor.deleteBody\")}</DialogDescription>\n </DialogHeader>\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => setConfirmDelete(false)}>\n {t(\"common.cancel\")}\n </Button>\n <Button\n variant=\"destructive\"\n disabled={remove.pending}\n onClick={() => {\n setConfirmDelete(false);\n void remove.run(g.remove).then((d) => d && onDeleted?.(d));\n }}\n >\n {t(\"groupEditor.delete\")}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </div>\n );\n}\n\nexport interface GroupMergeDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** The group merged away. */\n group: GroupDetail;\n /** Merges into the chosen group: memberships, names, edges and children move, its code redirects. */\n onMerge: (into: GroupCard) => Promise<MergeReport>;\n language?: string;\n client?: ContentKitClient;\n}\n\n/** Picks a group of the same kind and merges this one into it, after typing the confirmation word. */\nexport function GroupMergeDialog({ open, onOpenChange, group, onMerge, language, client }: GroupMergeDialogProps) {\n const m = useMessages();\n const { t } = m;\n const id = useId();\n const [into, setInto] = useState<GroupCard | null>(null);\n const [word, setWord] = useState(\"\");\n const [pending, setPending] = useState(false);\n const [error, setError] = useState<ContentKitError | null>(null);\n useEffect(() => {\n if (!open) return;\n setInto(null);\n setWord(\"\");\n setError(null);\n }, [open]);\n const typed = t(\"groupEditor.mergeWord\");\n const ready = !!into && word.trim().toLowerCase() === typed.toLowerCase();\n const name = group.name || group.slug;\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent data-ckui=\"group-merge-dialog\">\n <DialogHeader>\n <DialogTitle>{t(\"groupEditor.mergeTitle\", { name })}</DialogTitle>\n <DialogDescription>{t(\"groupEditor.mergeBody\")}</DialogDescription>\n </DialogHeader>\n {into ? (\n <div className=\"flex flex-wrap items-center gap-2\" data-ckui=\"merge-target\">\n <span>{t(\"groupEditor.mergeInto\", { name: into.name || into.slug })}</span>\n <Button size=\"xs\" variant=\"ghost\" onClick={() => setInto(null)}>\n {t(\"groupEditor.change\")}\n </Button>\n </div>\n ) : (\n <GroupPicker kind={group.kind} language={language} exclude={[group.id]} label={t(\"groupEditor.mergeTarget\")} onPick={setInto} client={client} autoFocus />\n )}\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${id}-typed`}>{t(\"admin.typeToConfirm\", { word: typed })}</Label>\n <Input id={`${id}-typed`} value={word} autoComplete=\"off\" onChange={(e) => setWord(e.target.value)} />\n </div>\n {error && <ErrorLine>{contentError(m, error)}</ErrorLine>}\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)}>\n {t(\"common.cancel\")}\n </Button>\n <Button\n variant=\"destructive\"\n disabled={!ready || pending}\n onClick={async () => {\n if (!into) return;\n setPending(true);\n setError(null);\n try {\n await onMerge(into);\n onOpenChange(false);\n } catch (e) {\n setError(toContentKitError(e));\n } finally {\n setPending(false);\n }\n }}\n >\n {t(\"groupEditor.merge\")}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n\n/** A parent or scope: the chosen group with a change and a clear, or a picker. */\nfunction GroupField({ label, kind, value, onChange, exclude, required, client }: { label: string; kind: string; value: GroupLike | null; onChange: (g: GroupLike | null) => void; exclude?: string[]; required?: boolean; client?: ContentKitClient }) {\n const { t } = useMessages();\n return (\n <div className=\"grid gap-1.5\" data-ckui=\"group-field\">\n <span className=\"text-sm font-medium\">\n {label}\n {required && <span aria-hidden> *</span>}\n </span>\n {value ? (\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-md border border-border px-2 py-0.5\" data-ckui=\"group-field-value\">\n {value.name || value.slug}\n </span>\n <Button type=\"button\" size=\"xs\" variant=\"ghost\" onClick={() => onChange(null)} aria-label={t(\"groupEditor.clearField\", { field: label })}>\n {required ? t(\"groupEditor.change\") : t(\"common.remove\")}\n </Button>\n </div>\n ) : (\n <GroupPicker kind={kind} label={label} exclude={exclude} onPick={onChange} client={client} />\n )}\n </div>\n );\n}\n\nfunction CreateForm({ kind, spec, languages, labels, g, onCreated, onError, client }: GroupEditorProps & { spec: GroupKind; languages: readonly string[]; g: UseGroup }) {\n const m = useMessages();\n const { t } = m;\n const id = useId();\n const languageName = useLanguageName();\n const [names, setNames] = useState<Record<string, string>>({});\n const [slug, setSlug] = useState(\"\");\n const [slugEdited, setSlugEdited] = useState(false);\n const [parent, setParent] = useState<GroupLike | null>(null);\n const [scope, setScope] = useState<GroupLike | null>(null);\n const declared = spec.attributes ?? {};\n const [attrs, setAttrs] = useState<Record<string, string | boolean>>(() => formOf(declared, {}));\n const [invalid, setInvalid] = useState<string | null>(null);\n const create = useAction(\"group.save\", onError);\n const first = names[languages[0]!] ?? \"\";\n useEffect(() => {\n if (!slugEdited) setSlug(slugify(first));\n }, [first, slugEdited]);\n const submit = async () => {\n setInvalid(null);\n let attributes: Record<string, unknown>;\n try {\n attributes = parseAttributes(declared, attrs);\n } catch (e) {\n setInvalid((e as Error).message);\n return;\n }\n const given: Name[] = languages.filter((l) => names[l]?.trim()).map((l) => ({ language: l, kind: \"name\", name: names[l]!.trim() }));\n const made = await create.run(() =>\n g.create({ kind, slug: slug.trim(), names: given, parent_id: parent?.id, scope_id: scope?.id, attributes: Object.keys(attributes).length ? attributes : undefined }),\n );\n if (made) onCreated?.(made);\n };\n return (\n <form\n className=\"grid gap-4\"\n data-ckui=\"group-create\"\n onSubmit={(e) => {\n e.preventDefault();\n void submit();\n }}\n >\n <h2 className=\"text-base font-semibold\">{t(\"groupEditor.newTitle\", { kind: labelOf(labels, kind) })}</h2>\n {languages.map((l, i) => (\n <div key={l} className=\"grid gap-1.5\">\n <Label htmlFor={`${id}-${l}`}>{t(\"groupEditor.nameIn\", { language: languageName(l) })}</Label>\n <Input id={`${id}-${l}`} className=\"h-8\" lang={l} required={i === 0} value={names[l] ?? \"\"} onChange={(e) => setNames((n) => ({ ...n, [l]: e.target.value }))} />\n </div>\n ))}\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${id}-slug`}>{t(\"groupEditor.slug\")}</Label>\n <Input\n id={`${id}-slug`}\n className=\"h-8\"\n required\n value={slug}\n onChange={(e) => {\n setSlugEdited(true);\n setSlug(e.target.value);\n }}\n />\n </div>\n {spec.scoped_by && <GroupField label={labelOf(labels, spec.scoped_by)} kind={spec.scoped_by} value={scope} onChange={setScope} required client={client} />}\n {spec.parent && <GroupField label={t(\"groupEditor.parent\")} kind={spec.parent} value={parent} onChange={setParent} client={client} />}\n <AttributeFields declared={declared} form={attrs} onChange={(n, v) => setAttrs((a) => ({ ...a, [n]: v }))} labels={labels} />\n {invalid && <ErrorLine>{invalid}</ErrorLine>}\n {create.error && <ErrorLine>{contentError(m, create.error)}</ErrorLine>}\n <Button type=\"submit\" className=\"justify-self-start\" disabled={create.pending || !first.trim() || !slug.trim() || (!!spec.scoped_by && !scope)}>\n {create.pending ? t(\"common.saving\") : t(\"groupEditor.create\")}\n </Button>\n </form>\n );\n}\n\nfunction Details({ group, spec, g, labels, onError, client }: { group: GroupDetail; spec: GroupKind; g: UseGroup; labels?: Labels; onError?: ContentKitErrorHandler; client?: ContentKitClient }) {\n const m = useMessages();\n const { t } = m;\n const id = useId();\n const declared = spec.attributes ?? {};\n const [form, setForm, settle] = useSeeded(\n () => ({ slug: group.slug, parent: (group.parent ?? null) as GroupLike | null, scope: (group.scope ?? null) as GroupLike | null, attrs: formOf(declared, group.attributes) }),\n group.revision,\n );\n const { slug, parent, scope, attrs } = form;\n const edit = (patch: Partial<typeof form>) => {\n setSaved(false);\n setForm((f) => ({ ...f, ...patch }));\n };\n const setSlug = (v: string) => edit({ slug: v });\n const setParent = (v: GroupLike | null) => edit({ parent: v });\n const setScope = (v: GroupLike | null) => edit({ scope: v });\n const setAttrs = (fn: (a: Record<string, string | boolean>) => Record<string, string | boolean>) => edit({ attrs: fn(attrs) });\n const [invalid, setInvalid] = useState<string | null>(null);\n const [saved, setSaved] = useState(false);\n const save = useAction(\"group.save\", onError);\n const submit = async () => {\n setInvalid(null);\n setSaved(false);\n let attributes: Record<string, unknown>;\n try {\n attributes = parseAttributes(declared, attrs);\n } catch (e) {\n setInvalid((e as Error).message);\n return;\n }\n const done = await save.run(() =>\n g.update({\n slug: slug.trim(),\n attributes,\n ...(spec.parent ? { parent_id: parent?.id ?? \"\" } : {}),\n ...(spec.scoped_by && scope ? { scope_id: scope.id } : {}),\n }),\n );\n if (done) {\n settle();\n setSaved(true);\n }\n };\n return (\n <Section title={t(\"groupEditor.details\")} ckui=\"group-details\">\n <form\n className=\"grid gap-3\"\n onSubmit={(e) => {\n e.preventDefault();\n void submit();\n }}\n >\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${id}-slug`}>{t(\"groupEditor.slug\")}</Label>\n <Input id={`${id}-slug`} className=\"h-8\" required value={slug} onChange={(e) => setSlug(e.target.value)} />\n </div>\n {spec.scoped_by && <GroupField label={labelOf(labels, spec.scoped_by)} kind={spec.scoped_by} value={scope} onChange={setScope} required client={client} />}\n {spec.parent && <GroupField label={t(\"groupEditor.parent\")} kind={spec.parent} value={parent} onChange={setParent} exclude={[group.id]} client={client} />}\n <AttributeFields declared={declared} form={attrs} onChange={(n, v) => setAttrs((a) => ({ ...a, [n]: v }))} labels={labels} />\n {invalid && <ErrorLine>{invalid}</ErrorLine>}\n <ErrorLine error={save.error} />\n <div className=\"flex items-center gap-3\">\n <Button type=\"submit\" size=\"sm\" disabled={save.pending || !slug.trim() || (!!spec.scoped_by && !scope)}>\n {save.pending ? t(\"common.saving\") : t(\"common.save\")}\n </Button>\n {saved && (\n <span role=\"status\" className=\"text-muted-foreground\">\n {t(\"groupEditor.saved\")}\n </span>\n )}\n </div>\n </form>\n </Section>\n );\n}\n\nfunction Names({ group, g, languages, onError }: { group: GroupDetail; g: UseGroup; languages: readonly string[]; onError?: ContentKitErrorHandler }) {\n const { t } = useMessages();\n const id = useId();\n const languageName = useLanguageName();\n const [language, setLanguage] = useState(languages[0]!);\n const [kind, setKind] = useState<Name[\"kind\"]>(\"alias\");\n const [text, setText] = useState(\"\");\n const save = useAction(\"group.save\", onError);\n const sorted = [...group.names].sort((a, b) => a.language.localeCompare(b.language) || (a.kind === b.kind ? a.name.localeCompare(b.name) : a.kind === \"name\" ? -1 : 1));\n const offered = [...new Set([...languages, ...group.names.map((n) => n.language)])];\n return (\n <Section title={t(\"groupEditor.names\")} ckui=\"group-names-editor\">\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.kind}:${n.name}`} className=\"flex flex-wrap items-center gap-2 p-2.5\" data-ckui=\"group-name\" data-kind={n.kind} data-language={n.language}>\n <Badge variant=\"outline\">{languageName(n.language)}</Badge>\n <span className=\"min-w-0 flex-1 break-words\" lang={n.language}>\n {n.name}\n </span>\n <span className=\"text-xs text-muted-foreground\">{t(n.kind === \"name\" ? \"groupEditor.canonical\" : \"groupEditor.alias\")}</span>\n {n.kind === \"alias\" && (\n <Button size=\"xs\" variant=\"ghost\" disabled={save.pending} onClick={() => void save.run(() => g.names(\"add\", [{ ...n, kind: \"name\" }]))}>\n {t(\"groupEditor.makeCanonical\")}\n </Button>\n )}\n <Button size=\"xs\" variant=\"ghost\" disabled={save.pending} aria-label={t(\"groupEditor.removeName\", { name: n.name })} onClick={() => void save.run(() => g.names(\"remove\", [n]))}>\n {t(\"common.remove\")}\n </Button>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-muted-foreground\">{t(\"groupEditor.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) void save.run(() => g.names(\"add\", [{ language, kind, name }])).then((d) => d && setText(\"\"));\n }}\n >\n {offered.length > 1 && (\n <Select value={language} onValueChange={(v) => setLanguage(String(v))}>\n <SelectTrigger size=\"sm\" aria-label={t(\"groupEditor.language\")}>\n <SelectValue>{(v: string) => languageName(v)}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {offered.map((l) => (\n <SelectItem key={l} value={l}>\n {languageName(l)}\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(\"groupEditor.nameKind\")}>\n <SelectValue>{(v: string) => t(v === \"name\" ? \"groupEditor.canonical\" : \"groupEditor.alias\")}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"alias\">{t(\"groupEditor.alias\")}</SelectItem>\n <SelectItem value=\"name\">{t(\"groupEditor.canonical\")}</SelectItem>\n </SelectContent>\n </Select>\n <Label htmlFor={`${id}-name`} className=\"sr-only\">\n {t(\"groupEditor.newName\")}\n </Label>\n <Input id={`${id}-name`} className=\"h-8 min-w-40 flex-1\" lang={language} value={text} placeholder={t(\"groupEditor.newName\")} onChange={(e) => setText(e.target.value)} />\n <Button type=\"submit\" size=\"sm\" variant=\"outline\" disabled={save.pending || !text.trim()}>\n {t(\"groupEditor.addName\")}\n </Button>\n </form>\n <ErrorLine error={save.error} />\n </Section>\n );\n}\n\nfunction Texts({ group, g, languages, onError }: { group: GroupDetail; g: UseGroup; languages: readonly string[]; onError?: ContentKitErrorHandler }) {\n const { t } = useMessages();\n const id = useId();\n const languageName = useLanguageName();\n const offered = [...new Set([...languages, ...group.text.map((x) => x.language)])];\n const [form, setForm, settle] = useSeeded<Record<string, Text>>(\n () => Object.fromEntries(offered.map((l) => [l, group.text.find((x) => x.language === l) ?? { language: l }])),\n group.revision,\n );\n const [saved, setSaved] = useState(false);\n const save = useAction(\"group.save\", onError);\n const set = (l: string, patch: Partial<Text>) => {\n setSaved(false);\n setForm((f) => ({ ...f, [l]: { ...f[l]!, ...patch } }));\n };\n return (\n <Section title={t(\"groupEditor.text\")} ckui=\"group-text\">\n <form\n className=\"grid gap-4\"\n onSubmit={(e) => {\n e.preventDefault();\n const text = Object.values(form)\n .map((x) => ({ language: x.language, description: x.description?.trim() || undefined, sort_key: x.sort_key?.trim() || undefined }))\n .filter((x) => x.description || x.sort_key);\n void save.run(() => g.update({ text })).then((d) => {\n if (!d) return;\n settle();\n setSaved(true);\n });\n }}\n >\n {offered.map((l) => (\n <fieldset key={l} className=\"grid gap-2\" data-language={l}>\n <legend className=\"mb-1 text-xs font-medium text-muted-foreground\">{languageName(l)}</legend>\n <Label htmlFor={`${id}-${l}-d`} className=\"sr-only\">\n {t(\"groupEditor.descriptionIn\", { language: languageName(l) })}\n </Label>\n <Textarea\n id={`${id}-${l}-d`}\n lang={l}\n rows={3}\n placeholder={t(\"groupEditor.description\")}\n value={form[l]?.description ?? \"\"}\n onChange={(e) => set(l, { description: e.target.value })}\n />\n <Label htmlFor={`${id}-${l}-s`} className=\"sr-only\">\n {t(\"groupEditor.sortKeyIn\", { language: languageName(l) })}\n </Label>\n <Input\n id={`${id}-${l}-s`}\n className=\"h-8\"\n lang={l}\n placeholder={t(\"groupEditor.sortKey\")}\n value={form[l]?.sort_key ?? \"\"}\n onChange={(e) => set(l, { sort_key: e.target.value })}\n />\n </fieldset>\n ))}\n <ErrorLine error={save.error} />\n <div className=\"flex items-center gap-3\">\n <Button type=\"submit\" size=\"sm\" disabled={save.pending}>\n {save.pending ? t(\"common.saving\") : t(\"common.save\")}\n </Button>\n {saved && (\n <span role=\"status\" className=\"text-muted-foreground\">\n {t(\"groupEditor.saved\")}\n </span>\n )}\n </div>\n </form>\n </Section>\n );\n}\n\nfunction Images({ group, spec, onError, client }: { group: GroupDetail; spec: GroupKind; onError?: ContentKitErrorHandler; client?: ContentKitClient }) {\n const { t } = useMessages();\n const c = group.cover;\n const mode = c?.image ? \"image\" : c?.content_id && !c.auto ? \"content\" : \"auto\";\n return (\n <Section title={t(spec.owner === \"user\" ? \"groupEditor.images\" : \"groupEditor.cover\")} ckui=\"group-cover-editor\">\n <p className=\"text-muted-foreground\" data-ckui=\"cover-mode\">\n {t(mode === \"image\" ? \"groupEditor.coverImage\" : mode === \"content\" ? \"groupEditor.coverContent\" : \"groupEditor.coverAuto\")}\n </p>\n <GroupImageEditor group={group} slot=\"cover\" client={client} onError={onError} />\n {spec.owner === \"user\" && <GroupImageEditor group={group} slot=\"avatar\" client={client} onError={onError} />}\n </Section>\n );\n}\n\nfunction Membership({ group, onError, client }: { group: GroupDetail; onError?: ContentKitErrorHandler; client?: ContentKitClient }) {\n const { t } = useMessages();\n const ck = useContentKitClient(client);\n const offer = useAction(\"offer.save\", onError);\n return (\n <Section title={t(\"groupEditor.membershipPrice\")} ckui=\"group-offer\">\n <OfferFields\n key={group.offer?.revision}\n offer={group.offer}\n pending={offer.pending}\n onSell={(terms) => void offer.run(() => ck.offers.sellGroup(group.id, terms))}\n onWithdraw={() => void offer.run(() => ck.offers.withdrawGroup(group.id))}\n />\n <ErrorLine error={offer.error} />\n </Section>\n );\n}\n\nconst RELATION = /^[a-z][a-z0-9_]*$/;\n\nfunction Edges({ group, g, kinds, labels, onError, client }: { group: GroupDetail; g: UseGroup; kinds: ContentModel | null; labels?: Labels; onError?: ContentKitErrorHandler; client?: ContentKitClient }) {\n const { t } = useMessages();\n const id = useId();\n const save = useAction(\"group.save\", onError);\n const partners = useGroupNames(\n group.edges.map((e) => (e.from === group.id ? e.to : e.from)),\n { client },\n );\n const kindsList = Object.keys(kinds?.group_kinds ?? {}).sort();\n const [relation, setRelation] = useState(\"\");\n const [kind, setKind] = useState(kindsList[0] ?? group.kind);\n const out = group.edges.filter((e) => e.from === group.id);\n const incoming = group.edges.filter((e) => e.to === group.id);\n const nameOf = (gid: string) => {\n const x = partners.get(gid);\n return x ? x.name || x.slug : gid;\n };\n const valid = RELATION.test(relation.trim());\n return (\n <Section title={t(\"groupEditor.edges\")} ckui=\"group-edges\">\n {out.length + incoming.length ? (\n <ul className=\"grid gap-1.5\">\n {out.map((e) => (\n <li key={`${e.relation}:${e.to}`} className=\"flex flex-wrap items-center gap-2\" data-ckui=\"group-edge\" data-relation={e.relation}>\n <Badge variant=\"secondary\">{labelOf(labels, e.relation)}</Badge>\n <span>{nameOf(e.to)}</span>\n <Button size=\"xs\" variant=\"ghost\" disabled={save.pending} aria-label={t(\"groupEditor.removeEdge\", { name: nameOf(e.to) })} onClick={() => void save.run(() => g.edges(\"remove\", [{ relation: e.relation, to: e.to }]))}>\n {t(\"common.remove\")}\n </Button>\n </li>\n ))}\n {incoming.map((e) => (\n <li key={`in:${e.relation}:${e.from}`} className=\"flex flex-wrap items-center gap-2 text-muted-foreground\" data-ckui=\"group-edge\" data-relation={`inverse:${e.relation}`}>\n <span className=\"text-foreground\">{nameOf(e.from)}</span>\n <Badge variant=\"outline\">{labelOf(labels, e.relation)}</Badge>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-muted-foreground\">{t(\"groupEditor.noEdges\")}</p>\n )}\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"grid gap-1\">\n <Label htmlFor={`${id}-rel`} className=\"text-xs text-muted-foreground\">\n {t(\"groupEditor.relation\")}\n </Label>\n <Input id={`${id}-rel`} className=\"h-8 w-40\" value={relation} placeholder=\"member_of\" aria-invalid={!!relation && !valid} onChange={(e) => setRelation(e.target.value)} />\n </div>\n {kindsList.length > 1 && (\n <Select value={kind} onValueChange={(v) => setKind(String(v))}>\n <SelectTrigger size=\"sm\" aria-label={t(\"groupEditor.edgeKind\")}>\n <SelectValue>{(v: string) => labelOf(labels, v)}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {kindsList.map((k) => (\n <SelectItem key={k} value={k}>\n {labelOf(labels, k)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n {valid && (\n <GroupPicker\n key={kind}\n kind={kind}\n label={t(\"groupEditor.edgeTarget\")}\n exclude={[group.id]}\n client={client}\n onPick={(to) => void save.run(() => g.edges(\"add\", [{ relation: relation.trim(), to: to.id }])).then((d) => d && setRelation(\"\"))}\n />\n )}\n </div>\n <ErrorLine error={save.error} />\n </Section>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"editor.js","names":[],"sources":["../../../src/components/groups/editor.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport { useCallback, useEffect, useId, useRef, useState, type ReactNode } from \"react\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport { toContentKitError, type ContentKitError } from \"../../client/errors.js\";\nimport { parseAttributes, slugify } from \"../../client/group-fields.js\";\nimport type { ContentModel, Group, GroupCard, GroupDetail, GroupKind, GroupsText as Text, MergeReport, Name } from \"../../client/generated/wire.js\";\nimport { useLanguageName, useMessages } from \"../../i18n/context.js\";\nimport type { ContentKitErrorHandler } from \"../../react/context.js\";\nimport { useGroup, useKinds, type UseGroup } from \"../../react/groups.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from \"#ckui/ui/dialog\";\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 { Textarea } from \"#ckui/ui/textarea\";\nimport { contentError, ErrorLine, useAction } from \"../social/parts.js\";\nimport { OfferFields } from \"../content/offer-fields.js\";\nimport { AttributeFields, formOf } from \"./fields.js\";\nimport { useContentKitClient } from \"../../react/context.js\";\nimport { GroupImageEditor } from \"./banner.js\";\nimport { GroupPicker, labelOf, useGroupNames, type GroupLike, type Labels } from \"./parts.js\";\n\nexport interface GroupEditorProps {\n /** The group edited; null creates one of `kind`. */\n id: string | null;\n /** The kind a new group is created as. */\n kind: string;\n /** Languages names and text are written in; default the content model's. */\n languages?: readonly string[];\n labels?: Labels;\n onCreated?: (group: Group) => void;\n /** After a merge: the survivor's id is report.into. */\n onMerged?: (report: MergeReport) => void;\n onDeleted?: (group: Group) => void;\n /** Below the editor's sections, with the loaded group: the members, host fields. */\n children?: (group: GroupDetail) => ReactNode;\n client?: ContentKitClient;\n onError?: ContentKitErrorHandler;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n\n/**\n * Staff (root:groups:write): creates a group, or edits one: slug, parent,\n * scope and declared attributes; names and aliases per language; description\n * and sort key per language; cover (an upload, or automatic); edges to other\n * groups; merge into another group; delete and restore.\n */\nexport function GroupEditor(p: GroupEditorProps) {\n const { t } = useMessages();\n const { kinds, loading: kindsLoading } = useKinds({ client: p.client });\n const g = useGroup(p.id, { client: p.client });\n const languages = p.languages ?? kinds?.languages ?? [\"en\"];\n const kind = g.group?.kind ?? p.kind;\n const spec: GroupKind = kinds?.entity_kinds?.[kind] ?? {};\n const root = (children: ReactNode) => (\n <ContentKitUiRoot appearance={p.appearance} className={cn(\"grid gap-6 text-sm\", p.className)} data-ckui=\"group-editor\" data-kind={kind}>\n {children}\n </ContentKitUiRoot>\n );\n if (kindsLoading) return root(<Skeleton className=\"h-40 w-full\" />);\n // A group created here is edited in place until the host routes to it.\n if (!p.id && !g.group && !g.loading) return root(<CreateForm {...p} kind={kind} spec={spec} languages={languages} g={g} />);\n if (g.deleted)\n return root(\n <Deleted\n group={g.deleted}\n onRestore={() => g.restore()}\n onError={p.onError}\n name={g.deleted.slug}\n />,\n );\n if (!g.group) {\n if (g.error)\n return root(\n <div role=\"alert\" className=\"grid justify-items-start gap-2\">\n <p className=\"text-destructive\">{t(\"groupEditor.loadFailed\")}</p>\n <Button size=\"sm\" variant=\"outline\" onClick={g.reload}>\n {t(\"common.retry\")}\n </Button>\n </div>,\n );\n return root(<Skeleton className=\"h-40 w-full\" />);\n }\n const group = g.group;\n return root(\n <>\n <Head group={group} g={g} labels={p.labels} onMerged={p.onMerged} onDeleted={p.onDeleted} onError={p.onError} client={p.client} />\n <Details key={group.id} group={group} spec={spec} g={g} labels={p.labels} onError={p.onError} client={p.client} />\n <Names group={group} g={g} languages={languages} onError={p.onError} />\n <Texts key={group.id} group={group} g={g} languages={languages} onError={p.onError} />\n <Images group={group} spec={spec} onError={p.onError} client={p.client} />\n {spec.sellable && <Membership group={group} onError={p.onError} client={p.client} />}\n <Edges group={group} g={g} kinds={kinds} labels={p.labels} onError={p.onError} client={p.client} />\n {p.children?.(group)}\n </>,\n );\n}\n\n/** Form state seeded from the record, seeded again when it changes unless edited since; settle() after a save. */\nfunction useSeeded<T>(seed: () => T, revision: unknown): [T, (next: (prev: T) => T) => void, () => void] {\n const [value, setValue] = useState(seed);\n const edited = useRef(false);\n const latest = useRef(seed);\n latest.current = seed;\n useEffect(() => {\n if (!edited.current) setValue(latest.current());\n }, [revision]);\n const set = useCallback((next: (prev: T) => T) => {\n edited.current = true;\n setValue(next);\n }, []);\n const settle = useCallback(() => {\n edited.current = false;\n }, []);\n return [value, set, settle];\n}\n\nfunction Section({ title, children, ckui, action }: { title: ReactNode; children: ReactNode; ckui: string; action?: ReactNode }) {\n return (\n <section className=\"grid gap-3\" data-ckui={ckui}>\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h3 className=\"font-medium\">{title}</h3>\n {action}\n </div>\n {children}\n </section>\n );\n}\n\nfunction Deleted({ group, name, onRestore, onError }: { group: Group; name: string; onRestore: () => Promise<Group>; onError?: ContentKitErrorHandler }) {\n const { t } = useMessages();\n const restore = useAction(\"group.save\", onError);\n return (\n <div className=\"grid justify-items-start gap-2\" data-ckui=\"group-deleted\" data-state={group.state}>\n <p>{t(\"groupEditor.deletedNotice\", { name })}</p>\n <Button size=\"sm\" variant=\"outline\" disabled={restore.pending} onClick={() => void restore.run(onRestore)}>\n {t(\"groupEditor.restore\")}\n </Button>\n <ErrorLine error={restore.error} />\n </div>\n );\n}\n\nfunction Head({\n group,\n g,\n labels,\n onMerged,\n onDeleted,\n onError,\n client,\n}: {\n group: GroupDetail;\n g: UseGroup;\n labels?: Labels;\n onMerged?: (r: MergeReport) => void;\n onDeleted?: (g: Group) => void;\n onError?: ContentKitErrorHandler;\n client?: ContentKitClient;\n}) {\n const { t } = useMessages();\n const [merging, setMerging] = useState(false);\n const [confirmDelete, setConfirmDelete] = useState(false);\n const remove = useAction(\"group.save\", onError);\n return (\n <div className=\"flex flex-wrap items-center gap-2\" data-ckui=\"group-head\">\n <h2 className=\"text-base font-semibold break-words\">{group.name || group.slug}</h2>\n <Badge variant=\"outline\">{labelOf(labels, group.kind)}</Badge>\n <div className=\"ms-auto flex flex-wrap gap-2\">\n <Button size=\"sm\" variant=\"outline\" onClick={() => setMerging(true)}>\n {t(\"groupEditor.merge\")}\n </Button>\n <Button size=\"sm\" variant=\"destructive\" disabled={remove.pending} onClick={() => setConfirmDelete(true)}>\n {t(\"groupEditor.delete\")}\n </Button>\n </div>\n <ErrorLine error={remove.error} className=\"basis-full\" />\n <GroupMergeDialog\n open={merging}\n onOpenChange={setMerging}\n group={group}\n client={client}\n onMerge={async (into) => {\n const report = await g.merge(into.id);\n onMerged?.(report);\n return report;\n }}\n />\n <Dialog open={confirmDelete} onOpenChange={setConfirmDelete}>\n <DialogContent data-ckui=\"group-delete-dialog\">\n <DialogHeader>\n <DialogTitle>{t(\"groupEditor.deleteTitle\", { name: group.name || group.slug })}</DialogTitle>\n <DialogDescription>{t(\"groupEditor.deleteBody\")}</DialogDescription>\n </DialogHeader>\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => setConfirmDelete(false)}>\n {t(\"common.cancel\")}\n </Button>\n <Button\n variant=\"destructive\"\n disabled={remove.pending}\n onClick={() => {\n setConfirmDelete(false);\n void remove.run(g.remove).then((d) => d && onDeleted?.(d));\n }}\n >\n {t(\"groupEditor.delete\")}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </div>\n );\n}\n\nexport interface GroupMergeDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** The group merged away. */\n group: GroupDetail;\n /** Merges into the chosen group: memberships, names, edges and children move, its code redirects. */\n onMerge: (into: GroupCard) => Promise<MergeReport>;\n language?: string;\n client?: ContentKitClient;\n}\n\n/** Picks a group of the same kind and merges this one into it, after typing the confirmation word. */\nexport function GroupMergeDialog({ open, onOpenChange, group, onMerge, language, client }: GroupMergeDialogProps) {\n const m = useMessages();\n const { t } = m;\n const id = useId();\n const [into, setInto] = useState<GroupCard | null>(null);\n const [word, setWord] = useState(\"\");\n const [pending, setPending] = useState(false);\n const [error, setError] = useState<ContentKitError | null>(null);\n useEffect(() => {\n if (!open) return;\n setInto(null);\n setWord(\"\");\n setError(null);\n }, [open]);\n const typed = t(\"groupEditor.mergeWord\");\n const ready = !!into && word.trim().toLowerCase() === typed.toLowerCase();\n const name = group.name || group.slug;\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent data-ckui=\"group-merge-dialog\">\n <DialogHeader>\n <DialogTitle>{t(\"groupEditor.mergeTitle\", { name })}</DialogTitle>\n <DialogDescription>{t(\"groupEditor.mergeBody\")}</DialogDescription>\n </DialogHeader>\n {into ? (\n <div className=\"flex flex-wrap items-center gap-2\" data-ckui=\"merge-target\">\n <span>{t(\"groupEditor.mergeInto\", { name: into.name || into.slug })}</span>\n <Button size=\"xs\" variant=\"ghost\" onClick={() => setInto(null)}>\n {t(\"groupEditor.change\")}\n </Button>\n </div>\n ) : (\n <GroupPicker kind={group.kind} language={language} exclude={[group.id]} label={t(\"groupEditor.mergeTarget\")} onPick={setInto} client={client} autoFocus />\n )}\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${id}-typed`}>{t(\"admin.typeToConfirm\", { word: typed })}</Label>\n <Input id={`${id}-typed`} value={word} autoComplete=\"off\" onChange={(e) => setWord(e.target.value)} />\n </div>\n {error && <ErrorLine>{contentError(m, error)}</ErrorLine>}\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)}>\n {t(\"common.cancel\")}\n </Button>\n <Button\n variant=\"destructive\"\n disabled={!ready || pending}\n onClick={async () => {\n if (!into) return;\n setPending(true);\n setError(null);\n try {\n await onMerge(into);\n onOpenChange(false);\n } catch (e) {\n setError(toContentKitError(e));\n } finally {\n setPending(false);\n }\n }}\n >\n {t(\"groupEditor.merge\")}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n\n/** A parent or scope: the chosen group with a change and a clear, or a picker. */\nfunction GroupField({ label, kind, value, onChange, exclude, required, client }: { label: string; kind: string; value: GroupLike | null; onChange: (g: GroupLike | null) => void; exclude?: string[]; required?: boolean; client?: ContentKitClient }) {\n const { t } = useMessages();\n return (\n <div className=\"grid gap-1.5\" data-ckui=\"group-field\">\n <span className=\"text-sm font-medium\">\n {label}\n {required && <span aria-hidden> *</span>}\n </span>\n {value ? (\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-md border border-border px-2 py-0.5\" data-ckui=\"group-field-value\">\n {value.name || value.slug}\n </span>\n <Button type=\"button\" size=\"xs\" variant=\"ghost\" onClick={() => onChange(null)} aria-label={t(\"groupEditor.clearField\", { field: label })}>\n {required ? t(\"groupEditor.change\") : t(\"common.remove\")}\n </Button>\n </div>\n ) : (\n <GroupPicker kind={kind} label={label} exclude={exclude} onPick={onChange} client={client} />\n )}\n </div>\n );\n}\n\nfunction CreateForm({ kind, spec, languages, labels, g, onCreated, onError, client }: GroupEditorProps & { spec: GroupKind; languages: readonly string[]; g: UseGroup }) {\n const m = useMessages();\n const { t } = m;\n const id = useId();\n const languageName = useLanguageName();\n const [names, setNames] = useState<Record<string, string>>({});\n const [slug, setSlug] = useState(\"\");\n const [slugEdited, setSlugEdited] = useState(false);\n const [parent, setParent] = useState<GroupLike | null>(null);\n const [scope, setScope] = useState<GroupLike | null>(null);\n const declared = spec.attributes ?? {};\n const [attrs, setAttrs] = useState<Record<string, string | boolean>>(() => formOf(declared, {}));\n const [invalid, setInvalid] = useState<string | null>(null);\n const create = useAction(\"group.save\", onError);\n const first = names[languages[0]!] ?? \"\";\n useEffect(() => {\n if (!slugEdited) setSlug(slugify(first));\n }, [first, slugEdited]);\n const submit = async () => {\n setInvalid(null);\n let attributes: Record<string, unknown>;\n try {\n attributes = parseAttributes(declared, attrs);\n } catch (e) {\n setInvalid((e as Error).message);\n return;\n }\n const given: Name[] = languages.filter((l) => names[l]?.trim()).map((l) => ({ language: l, kind: \"name\", name: names[l]!.trim() }));\n const made = await create.run(() =>\n g.create({ kind, slug: slug.trim(), names: given, parent_id: parent?.id, scope_id: scope?.id, attributes: Object.keys(attributes).length ? attributes : undefined }),\n );\n if (made) onCreated?.(made);\n };\n return (\n <form\n className=\"grid gap-4\"\n data-ckui=\"group-create\"\n onSubmit={(e) => {\n e.preventDefault();\n void submit();\n }}\n >\n <h2 className=\"text-base font-semibold\">{t(\"groupEditor.newTitle\", { kind: labelOf(labels, kind) })}</h2>\n {languages.map((l, i) => (\n <div key={l} className=\"grid gap-1.5\">\n <Label htmlFor={`${id}-${l}`}>{t(\"groupEditor.nameIn\", { language: languageName(l) })}</Label>\n <Input id={`${id}-${l}`} className=\"h-8\" lang={l} required={i === 0} value={names[l] ?? \"\"} onChange={(e) => setNames((n) => ({ ...n, [l]: e.target.value }))} />\n </div>\n ))}\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${id}-slug`}>{t(\"groupEditor.slug\")}</Label>\n <Input\n id={`${id}-slug`}\n className=\"h-8\"\n required\n value={slug}\n onChange={(e) => {\n setSlugEdited(true);\n setSlug(e.target.value);\n }}\n />\n </div>\n {spec.scoped_by && <GroupField label={labelOf(labels, spec.scoped_by)} kind={spec.scoped_by} value={scope} onChange={setScope} required client={client} />}\n {spec.parent && <GroupField label={t(\"groupEditor.parent\")} kind={spec.parent} value={parent} onChange={setParent} client={client} />}\n <AttributeFields declared={declared} form={attrs} onChange={(n, v) => setAttrs((a) => ({ ...a, [n]: v }))} labels={labels} />\n {invalid && <ErrorLine>{invalid}</ErrorLine>}\n {create.error && <ErrorLine>{contentError(m, create.error)}</ErrorLine>}\n <Button type=\"submit\" className=\"justify-self-start\" disabled={create.pending || !first.trim() || !slug.trim() || (!!spec.scoped_by && !scope)}>\n {create.pending ? t(\"common.saving\") : t(\"groupEditor.create\")}\n </Button>\n </form>\n );\n}\n\nfunction Details({ group, spec, g, labels, onError, client }: { group: GroupDetail; spec: GroupKind; g: UseGroup; labels?: Labels; onError?: ContentKitErrorHandler; client?: ContentKitClient }) {\n const m = useMessages();\n const { t } = m;\n const id = useId();\n const declared = spec.attributes ?? {};\n const [form, setForm, settle] = useSeeded(\n () => ({ slug: group.slug, parent: (group.parent ?? null) as GroupLike | null, scope: (group.scope ?? null) as GroupLike | null, attrs: formOf(declared, group.attributes) }),\n group.revision,\n );\n const { slug, parent, scope, attrs } = form;\n const edit = (patch: Partial<typeof form>) => {\n setSaved(false);\n setForm((f) => ({ ...f, ...patch }));\n };\n const setSlug = (v: string) => edit({ slug: v });\n const setParent = (v: GroupLike | null) => edit({ parent: v });\n const setScope = (v: GroupLike | null) => edit({ scope: v });\n const setAttrs = (fn: (a: Record<string, string | boolean>) => Record<string, string | boolean>) => edit({ attrs: fn(attrs) });\n const [invalid, setInvalid] = useState<string | null>(null);\n const [saved, setSaved] = useState(false);\n const save = useAction(\"group.save\", onError);\n const submit = async () => {\n setInvalid(null);\n setSaved(false);\n let attributes: Record<string, unknown>;\n try {\n attributes = parseAttributes(declared, attrs);\n } catch (e) {\n setInvalid((e as Error).message);\n return;\n }\n const done = await save.run(() =>\n g.update({\n slug: slug.trim(),\n attributes,\n ...(spec.parent ? { parent_id: parent?.id ?? \"\" } : {}),\n ...(spec.scoped_by && scope ? { scope_id: scope.id } : {}),\n }),\n );\n if (done) {\n settle();\n setSaved(true);\n }\n };\n return (\n <Section title={t(\"groupEditor.details\")} ckui=\"group-details\">\n <form\n className=\"grid gap-3\"\n onSubmit={(e) => {\n e.preventDefault();\n void submit();\n }}\n >\n <div className=\"grid gap-1.5\">\n <Label htmlFor={`${id}-slug`}>{t(\"groupEditor.slug\")}</Label>\n <Input id={`${id}-slug`} className=\"h-8\" required value={slug} onChange={(e) => setSlug(e.target.value)} />\n </div>\n {spec.scoped_by && <GroupField label={labelOf(labels, spec.scoped_by)} kind={spec.scoped_by} value={scope} onChange={setScope} required client={client} />}\n {spec.parent && <GroupField label={t(\"groupEditor.parent\")} kind={spec.parent} value={parent} onChange={setParent} exclude={[group.id]} client={client} />}\n <AttributeFields declared={declared} form={attrs} onChange={(n, v) => setAttrs((a) => ({ ...a, [n]: v }))} labels={labels} />\n {invalid && <ErrorLine>{invalid}</ErrorLine>}\n <ErrorLine error={save.error} />\n <div className=\"flex items-center gap-3\">\n <Button type=\"submit\" size=\"sm\" disabled={save.pending || !slug.trim() || (!!spec.scoped_by && !scope)}>\n {save.pending ? t(\"common.saving\") : t(\"common.save\")}\n </Button>\n {saved && (\n <span role=\"status\" className=\"text-muted-foreground\">\n {t(\"groupEditor.saved\")}\n </span>\n )}\n </div>\n </form>\n </Section>\n );\n}\n\nfunction Names({ group, g, languages, onError }: { group: GroupDetail; g: UseGroup; languages: readonly string[]; onError?: ContentKitErrorHandler }) {\n const { t } = useMessages();\n const id = useId();\n const languageName = useLanguageName();\n const [language, setLanguage] = useState(languages[0]!);\n const [kind, setKind] = useState<Name[\"kind\"]>(\"alias\");\n const [text, setText] = useState(\"\");\n const save = useAction(\"group.save\", onError);\n const sorted = [...group.names].sort((a, b) => a.language.localeCompare(b.language) || (a.kind === b.kind ? a.name.localeCompare(b.name) : a.kind === \"name\" ? -1 : 1));\n const offered = [...new Set([...languages, ...group.names.map((n) => n.language)])];\n return (\n <Section title={t(\"groupEditor.names\")} ckui=\"group-names-editor\">\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.kind}:${n.name}`} className=\"flex flex-wrap items-center gap-2 p-2.5\" data-ckui=\"group-name\" data-kind={n.kind} data-language={n.language}>\n <Badge variant=\"outline\">{languageName(n.language)}</Badge>\n <span className=\"min-w-0 flex-1 break-words\" lang={n.language}>\n {n.name}\n </span>\n <span className=\"text-xs text-muted-foreground\">{t(n.kind === \"name\" ? \"groupEditor.canonical\" : \"groupEditor.alias\")}</span>\n {n.kind === \"alias\" && (\n <Button size=\"xs\" variant=\"ghost\" disabled={save.pending} onClick={() => void save.run(() => g.names(\"add\", [{ ...n, kind: \"name\" }]))}>\n {t(\"groupEditor.makeCanonical\")}\n </Button>\n )}\n <Button size=\"xs\" variant=\"ghost\" disabled={save.pending} aria-label={t(\"groupEditor.removeName\", { name: n.name })} onClick={() => void save.run(() => g.names(\"remove\", [n]))}>\n {t(\"common.remove\")}\n </Button>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-muted-foreground\">{t(\"groupEditor.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) void save.run(() => g.names(\"add\", [{ language, kind, name }])).then((d) => d && setText(\"\"));\n }}\n >\n {offered.length > 1 && (\n <Select value={language} onValueChange={(v) => setLanguage(String(v))}>\n <SelectTrigger size=\"sm\" aria-label={t(\"groupEditor.language\")}>\n <SelectValue>{(v: string) => languageName(v)}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {offered.map((l) => (\n <SelectItem key={l} value={l}>\n {languageName(l)}\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(\"groupEditor.nameKind\")}>\n <SelectValue>{(v: string) => t(v === \"name\" ? \"groupEditor.canonical\" : \"groupEditor.alias\")}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"alias\">{t(\"groupEditor.alias\")}</SelectItem>\n <SelectItem value=\"name\">{t(\"groupEditor.canonical\")}</SelectItem>\n </SelectContent>\n </Select>\n <Label htmlFor={`${id}-name`} className=\"sr-only\">\n {t(\"groupEditor.newName\")}\n </Label>\n <Input id={`${id}-name`} className=\"h-8 min-w-40 flex-1\" lang={language} value={text} placeholder={t(\"groupEditor.newName\")} onChange={(e) => setText(e.target.value)} />\n <Button type=\"submit\" size=\"sm\" variant=\"outline\" disabled={save.pending || !text.trim()}>\n {t(\"groupEditor.addName\")}\n </Button>\n </form>\n <ErrorLine error={save.error} />\n </Section>\n );\n}\n\nfunction Texts({ group, g, languages, onError }: { group: GroupDetail; g: UseGroup; languages: readonly string[]; onError?: ContentKitErrorHandler }) {\n const { t } = useMessages();\n const id = useId();\n const languageName = useLanguageName();\n const offered = [...new Set([...languages, ...group.text.map((x) => x.language)])];\n const [form, setForm, settle] = useSeeded<Record<string, Text>>(\n () => Object.fromEntries(offered.map((l) => [l, group.text.find((x) => x.language === l) ?? { language: l }])),\n group.revision,\n );\n const [saved, setSaved] = useState(false);\n const save = useAction(\"group.save\", onError);\n const set = (l: string, patch: Partial<Text>) => {\n setSaved(false);\n setForm((f) => ({ ...f, [l]: { ...f[l]!, ...patch } }));\n };\n return (\n <Section title={t(\"groupEditor.text\")} ckui=\"group-text\">\n <form\n className=\"grid gap-4\"\n onSubmit={(e) => {\n e.preventDefault();\n const text = Object.values(form)\n .map((x) => ({ language: x.language, description: x.description?.trim() || undefined, sort_key: x.sort_key?.trim() || undefined }))\n .filter((x) => x.description || x.sort_key);\n void save.run(() => g.update({ text })).then((d) => {\n if (!d) return;\n settle();\n setSaved(true);\n });\n }}\n >\n {offered.map((l) => (\n <fieldset key={l} className=\"grid gap-2\" data-language={l}>\n <legend className=\"mb-1 text-xs font-medium text-muted-foreground\">{languageName(l)}</legend>\n <Label htmlFor={`${id}-${l}-d`} className=\"sr-only\">\n {t(\"groupEditor.descriptionIn\", { language: languageName(l) })}\n </Label>\n <Textarea\n id={`${id}-${l}-d`}\n lang={l}\n rows={3}\n placeholder={t(\"groupEditor.description\")}\n value={form[l]?.description ?? \"\"}\n onChange={(e) => set(l, { description: e.target.value })}\n />\n <Label htmlFor={`${id}-${l}-s`} className=\"sr-only\">\n {t(\"groupEditor.sortKeyIn\", { language: languageName(l) })}\n </Label>\n <Input\n id={`${id}-${l}-s`}\n className=\"h-8\"\n lang={l}\n placeholder={t(\"groupEditor.sortKey\")}\n value={form[l]?.sort_key ?? \"\"}\n onChange={(e) => set(l, { sort_key: e.target.value })}\n />\n </fieldset>\n ))}\n <ErrorLine error={save.error} />\n <div className=\"flex items-center gap-3\">\n <Button type=\"submit\" size=\"sm\" disabled={save.pending}>\n {save.pending ? t(\"common.saving\") : t(\"common.save\")}\n </Button>\n {saved && (\n <span role=\"status\" className=\"text-muted-foreground\">\n {t(\"groupEditor.saved\")}\n </span>\n )}\n </div>\n </form>\n </Section>\n );\n}\n\nfunction Images({ group, spec, onError, client }: { group: GroupDetail; spec: GroupKind; onError?: ContentKitErrorHandler; client?: ContentKitClient }) {\n const { t } = useMessages();\n const c = group.cover;\n const mode = c?.image ? \"image\" : c?.content_id && !c.auto ? \"content\" : \"auto\";\n return (\n <Section title={t(spec.owner === \"user\" ? \"groupEditor.images\" : \"groupEditor.cover\")} ckui=\"group-cover-editor\">\n <p className=\"text-muted-foreground\" data-ckui=\"cover-mode\">\n {t(mode === \"image\" ? \"groupEditor.coverImage\" : mode === \"content\" ? \"groupEditor.coverContent\" : \"groupEditor.coverAuto\")}\n </p>\n <GroupImageEditor group={group} slot=\"cover\" client={client} onError={onError} />\n {spec.owner === \"user\" && <GroupImageEditor group={group} slot=\"avatar\" client={client} onError={onError} />}\n </Section>\n );\n}\n\nfunction Membership({ group, onError, client }: { group: GroupDetail; onError?: ContentKitErrorHandler; client?: ContentKitClient }) {\n const { t } = useMessages();\n const ck = useContentKitClient(client);\n const offer = useAction(\"offer.save\", onError);\n return (\n <Section title={t(\"groupEditor.membershipPrice\")} ckui=\"group-offer\">\n <OfferFields\n key={group.offer?.revision}\n offer={group.offer}\n pending={offer.pending}\n onSell={(terms) => void offer.run(() => ck.offers.sellGroup(group.id, terms))}\n onWithdraw={() => void offer.run(() => ck.offers.withdrawGroup(group.id))}\n />\n <ErrorLine error={offer.error} />\n </Section>\n );\n}\n\nconst RELATION = /^[a-z][a-z0-9_]*$/;\n\nfunction Edges({ group, g, kinds, labels, onError, client }: { group: GroupDetail; g: UseGroup; kinds: ContentModel | null; labels?: Labels; onError?: ContentKitErrorHandler; client?: ContentKitClient }) {\n const { t } = useMessages();\n const id = useId();\n const save = useAction(\"group.save\", onError);\n const partners = useGroupNames(\n group.edges.map((e) => (e.from === group.id ? e.to : e.from)),\n { client },\n );\n const kindsList = Object.keys(kinds?.entity_kinds ?? {}).sort();\n const [relation, setRelation] = useState(\"\");\n const [kind, setKind] = useState(kindsList[0] ?? group.kind);\n const out = group.edges.filter((e) => e.from === group.id);\n const incoming = group.edges.filter((e) => e.to === group.id);\n const nameOf = (gid: string) => {\n const x = partners.get(gid);\n return x ? x.name || x.slug : gid;\n };\n const valid = RELATION.test(relation.trim());\n return (\n <Section title={t(\"groupEditor.edges\")} ckui=\"group-edges\">\n {out.length + incoming.length ? (\n <ul className=\"grid gap-1.5\">\n {out.map((e) => (\n <li key={`${e.relation}:${e.to}`} className=\"flex flex-wrap items-center gap-2\" data-ckui=\"group-edge\" data-relation={e.relation}>\n <Badge variant=\"secondary\">{labelOf(labels, e.relation)}</Badge>\n <span>{nameOf(e.to)}</span>\n <Button size=\"xs\" variant=\"ghost\" disabled={save.pending} aria-label={t(\"groupEditor.removeEdge\", { name: nameOf(e.to) })} onClick={() => void save.run(() => g.edges(\"remove\", [{ relation: e.relation, to: e.to }]))}>\n {t(\"common.remove\")}\n </Button>\n </li>\n ))}\n {incoming.map((e) => (\n <li key={`in:${e.relation}:${e.from}`} className=\"flex flex-wrap items-center gap-2 text-muted-foreground\" data-ckui=\"group-edge\" data-relation={`inverse:${e.relation}`}>\n <span className=\"text-foreground\">{nameOf(e.from)}</span>\n <Badge variant=\"outline\">{labelOf(labels, e.relation)}</Badge>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"text-muted-foreground\">{t(\"groupEditor.noEdges\")}</p>\n )}\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"grid gap-1\">\n <Label htmlFor={`${id}-rel`} className=\"text-xs text-muted-foreground\">\n {t(\"groupEditor.relation\")}\n </Label>\n <Input id={`${id}-rel`} className=\"h-8 w-40\" value={relation} placeholder=\"member_of\" aria-invalid={!!relation && !valid} onChange={(e) => setRelation(e.target.value)} />\n </div>\n {kindsList.length > 1 && (\n <Select value={kind} onValueChange={(v) => setKind(String(v))}>\n <SelectTrigger size=\"sm\" aria-label={t(\"groupEditor.edgeKind\")}>\n <SelectValue>{(v: string) => labelOf(labels, v)}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {kindsList.map((k) => (\n <SelectItem key={k} value={k}>\n {labelOf(labels, k)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n {valid && (\n <GroupPicker\n key={kind}\n kind={kind}\n label={t(\"groupEditor.edgeTarget\")}\n exclude={[group.id]}\n client={client}\n onPick={(to) => void save.run(() => g.edges(\"add\", [{ relation: relation.trim(), to: to.id }])).then((d) => d && setRelation(\"\"))}\n />\n )}\n </div>\n <ErrorLine error={save.error} />\n </Section>\n );\n}\n"],"mappings":"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"}
@@ -34,7 +34,7 @@ function g(c) {
34
34
  children: _("common.retry")
35
35
  })]
36
36
  })) : S(/* @__PURE__ */ f(o, { className: "h-32 w-full" }));
37
- let C = c.language ?? x.name_language, w = x.text.find((e) => e.language === C) ?? x.text.find((e) => e.description), T = x.names.filter((e) => e.name !== x.name), E = b?.group_kinds?.[x.kind]?.attributes ?? {}, D = Object.entries(x.attributes).filter(([, e]) => e != null && e !== ""), O = x.counts.filter((e) => e.language === (c.language ?? "")).reduce((e, t) => e + t.count, 0);
37
+ let C = c.language ?? x.name_language, w = x.text.find((e) => e.language === C) ?? x.text.find((e) => e.description), T = x.names.filter((e) => e.name !== x.name), E = b?.entity_kinds?.[x.kind]?.attributes ?? {}, D = Object.entries(x.attributes).filter(([, e]) => e != null && e !== ""), O = x.counts.filter((e) => e.language === (c.language ?? "")).reduce((e, t) => e + t.count, 0);
38
38
  return S(/* @__PURE__ */ p("div", {
39
39
  className: "grid gap-4 sm:grid-cols-[10rem_minmax(0,1fr)]",
40
40
  "data-kind": x.kind,
@@ -1 +1 @@
1
- {"version":3,"file":"header.js","names":[],"sources":["../../../src/components/groups/header.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport type { ReactNode } from \"react\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { Attribute, GroupDetail } from \"../../client/generated/wire.js\";\nimport { useLanguageName, useMessages } from \"../../i18n/context.js\";\nimport type { Translator } from \"../../i18n/messages.js\";\nimport { useGroup, useKinds } from \"../../react/groups.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { contentError, formatDate } from \"../social/parts.js\";\nimport { GroupCover, GroupLink, labelOf, type GroupLike, type Labels } from \"./parts.js\";\n\nexport interface GroupHeaderProps {\n /** The group the host already read; or give id. */\n group?: GroupDetail;\n id?: string;\n /** Text, names and counts in this language; default the provider's. */\n language?: string;\n labels?: Labels;\n /** A group's link (parent, scope, children); default its canonical path. */\n href?: (group: GroupLike) => string | undefined;\n /** Below the description: the host's actions. */\n children?: ReactNode;\n client?: ContentKitClient;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/** A value as its attribute's type shows it. */\nexport function formatAttribute(m: Translator, spec: Attribute | undefined, value: unknown, labels?: Labels): string {\n if (typeof value === \"boolean\") return m.t(value ? \"groups.yes\" : \"groups.no\");\n if (spec?.type === \"time\" && typeof value === \"string\") return formatDate(m, value);\n if (spec?.type === \"int\" && typeof value === \"number\") return new Intl.NumberFormat(m.language).format(value);\n if (spec?.type === \"enum\" && typeof value === \"string\") return labelOf(labels, value);\n return String(value);\n}\n\n/** A group page's header: cover, name, other names, description, attributes, parent, scope, sub-groups and count. */\nexport function GroupHeader(p: GroupHeaderProps) {\n const m = useMessages();\n const { t } = m;\n const languageName = useLanguageName();\n const read = useGroup(p.group ? null : p.id, { language: p.language, client: p.client });\n const { kinds } = useKinds({ client: p.client });\n const g = p.group ?? read.group;\n const root = (children: ReactNode) => (\n <ContentKitUiRoot appearance={p.appearance} className={cn(\"grid gap-4 text-sm\", p.className)} data-ckui=\"group-header\">\n {children}\n </ContentKitUiRoot>\n );\n if (!g) {\n if (read.error)\n return root(\n <div role=\"alert\" className=\"grid justify-items-start gap-2\">\n <p className=\"text-destructive\">{contentError(m, read.error)}</p>\n <Button size=\"sm\" variant=\"outline\" onClick={read.reload}>\n {t(\"common.retry\")}\n </Button>\n </div>,\n );\n return root(<Skeleton className=\"h-32 w-full\" />);\n }\n const lang = p.language ?? g.name_language;\n const text = g.text.find((x) => x.language === lang) ?? g.text.find((x) => x.description);\n const others = g.names.filter((n) => n.name !== g.name);\n const declared = kinds?.group_kinds?.[g.kind]?.attributes ?? {};\n const attributes = Object.entries(g.attributes).filter(([, v]) => v !== null && v !== undefined && v !== \"\");\n const count = g.counts.filter((c) => c.language === (p.language ?? \"\")).reduce((n, c) => n + c.count, 0);\n return root(\n <div className=\"grid gap-4 sm:grid-cols-[10rem_minmax(0,1fr)]\" data-kind={g.kind}>\n <GroupCover group={g} className=\"aspect-[3/4] w-32 sm:w-40\" />\n <div className=\"grid content-start gap-3\">\n <div className=\"grid gap-1\">\n {(g.parent || g.scope) && (\n <p className=\"text-xs text-muted-foreground\" data-ckui=\"group-parent\">\n {[g.scope, g.parent]\n .filter((x, i, all): x is NonNullable<typeof x> => !!x && all.findIndex((y) => y?.id === x.id) === i)\n .map((x, i) => (\n <span key={x.id}>\n {i > 0 && \" · \"}\n <GroupLink group={x} href={p.href} className=\"hover:underline\">\n {x.name || x.slug}\n </GroupLink>\n </span>\n ))}\n </p>\n )}\n <h1 className=\"text-xl font-semibold break-words\">{g.name || g.slug}</h1>\n <p className=\"text-xs text-muted-foreground tabular-nums\">{m.plural(\"groups.items\", count)}</p>\n </div>\n {others.length > 0 && (\n <p className=\"text-muted-foreground\" data-ckui=\"group-names\">\n <span className=\"sr-only\">{t(\"groups.alsoKnownAs\")} </span>\n {others.map((n, i) => (\n <span key={`${n.language}:${n.name}`} lang={n.language}>\n {i > 0 && \" · \"}\n {n.name}\n {n.kind === \"name\" && <span className=\"text-xs\"> ({languageName(n.language)})</span>}\n </span>\n ))}\n </p>\n )}\n {text?.description && (\n <p className=\"break-words whitespace-pre-line\" lang={text.language} data-ckui=\"group-description\">\n {text.description}\n </p>\n )}\n {attributes.length > 0 && (\n <dl className=\"grid grid-cols-[auto_minmax(0,1fr)] gap-x-3 gap-y-1\" data-ckui=\"group-attributes\">\n {attributes.map(([name, v]) => (\n <div key={name} className=\"contents\">\n <dt className=\"text-muted-foreground\">{labelOf(p.labels, name)}</dt>\n <dd className=\"break-words\">{formatAttribute(m, declared[name], v, p.labels)}</dd>\n </div>\n ))}\n </dl>\n )}\n {g.children.length > 0 && (\n <nav aria-label={t(\"groups.children\")} className=\"flex flex-wrap gap-2\" data-ckui=\"group-children\">\n {g.children.map((c) => (\n <GroupLink key={c.id} group={c} href={p.href} className=\"rounded-md border border-border px-2 py-1 hover:bg-muted\">\n {c.name || c.slug}\n </GroupLink>\n ))}\n </nav>\n )}\n {p.children}\n </div>\n </div>,\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"header.js","names":[],"sources":["../../../src/components/groups/header.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport type { ReactNode } from \"react\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { Attribute, GroupDetail } from \"../../client/generated/wire.js\";\nimport { useLanguageName, useMessages } from \"../../i18n/context.js\";\nimport type { Translator } from \"../../i18n/messages.js\";\nimport { useGroup, useKinds } from \"../../react/groups.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { contentError, formatDate } from \"../social/parts.js\";\nimport { GroupCover, GroupLink, labelOf, type GroupLike, type Labels } from \"./parts.js\";\n\nexport interface GroupHeaderProps {\n /** The group the host already read; or give id. */\n group?: GroupDetail;\n id?: string;\n /** Text, names and counts in this language; default the provider's. */\n language?: string;\n labels?: Labels;\n /** A group's link (parent, scope, children); default its canonical path. */\n href?: (group: GroupLike) => string | undefined;\n /** Below the description: the host's actions. */\n children?: ReactNode;\n client?: ContentKitClient;\n className?: string;\n appearance?: ContentKitUiAppearance;\n}\n\n/** A value as its attribute's type shows it. */\nexport function formatAttribute(m: Translator, spec: Attribute | undefined, value: unknown, labels?: Labels): string {\n if (typeof value === \"boolean\") return m.t(value ? \"groups.yes\" : \"groups.no\");\n if (spec?.type === \"time\" && typeof value === \"string\") return formatDate(m, value);\n if (spec?.type === \"int\" && typeof value === \"number\") return new Intl.NumberFormat(m.language).format(value);\n if (spec?.type === \"enum\" && typeof value === \"string\") return labelOf(labels, value);\n return String(value);\n}\n\n/** A group page's header: cover, name, other names, description, attributes, parent, scope, sub-groups and count. */\nexport function GroupHeader(p: GroupHeaderProps) {\n const m = useMessages();\n const { t } = m;\n const languageName = useLanguageName();\n const read = useGroup(p.group ? null : p.id, { language: p.language, client: p.client });\n const { kinds } = useKinds({ client: p.client });\n const g = p.group ?? read.group;\n const root = (children: ReactNode) => (\n <ContentKitUiRoot appearance={p.appearance} className={cn(\"grid gap-4 text-sm\", p.className)} data-ckui=\"group-header\">\n {children}\n </ContentKitUiRoot>\n );\n if (!g) {\n if (read.error)\n return root(\n <div role=\"alert\" className=\"grid justify-items-start gap-2\">\n <p className=\"text-destructive\">{contentError(m, read.error)}</p>\n <Button size=\"sm\" variant=\"outline\" onClick={read.reload}>\n {t(\"common.retry\")}\n </Button>\n </div>,\n );\n return root(<Skeleton className=\"h-32 w-full\" />);\n }\n const lang = p.language ?? g.name_language;\n const text = g.text.find((x) => x.language === lang) ?? g.text.find((x) => x.description);\n const others = g.names.filter((n) => n.name !== g.name);\n const declared = kinds?.entity_kinds?.[g.kind]?.attributes ?? {};\n const attributes = Object.entries(g.attributes).filter(([, v]) => v !== null && v !== undefined && v !== \"\");\n const count = g.counts.filter((c) => c.language === (p.language ?? \"\")).reduce((n, c) => n + c.count, 0);\n return root(\n <div className=\"grid gap-4 sm:grid-cols-[10rem_minmax(0,1fr)]\" data-kind={g.kind}>\n <GroupCover group={g} className=\"aspect-[3/4] w-32 sm:w-40\" />\n <div className=\"grid content-start gap-3\">\n <div className=\"grid gap-1\">\n {(g.parent || g.scope) && (\n <p className=\"text-xs text-muted-foreground\" data-ckui=\"group-parent\">\n {[g.scope, g.parent]\n .filter((x, i, all): x is NonNullable<typeof x> => !!x && all.findIndex((y) => y?.id === x.id) === i)\n .map((x, i) => (\n <span key={x.id}>\n {i > 0 && \" · \"}\n <GroupLink group={x} href={p.href} className=\"hover:underline\">\n {x.name || x.slug}\n </GroupLink>\n </span>\n ))}\n </p>\n )}\n <h1 className=\"text-xl font-semibold break-words\">{g.name || g.slug}</h1>\n <p className=\"text-xs text-muted-foreground tabular-nums\">{m.plural(\"groups.items\", count)}</p>\n </div>\n {others.length > 0 && (\n <p className=\"text-muted-foreground\" data-ckui=\"group-names\">\n <span className=\"sr-only\">{t(\"groups.alsoKnownAs\")} </span>\n {others.map((n, i) => (\n <span key={`${n.language}:${n.name}`} lang={n.language}>\n {i > 0 && \" · \"}\n {n.name}\n {n.kind === \"name\" && <span className=\"text-xs\"> ({languageName(n.language)})</span>}\n </span>\n ))}\n </p>\n )}\n {text?.description && (\n <p className=\"break-words whitespace-pre-line\" lang={text.language} data-ckui=\"group-description\">\n {text.description}\n </p>\n )}\n {attributes.length > 0 && (\n <dl className=\"grid grid-cols-[auto_minmax(0,1fr)] gap-x-3 gap-y-1\" data-ckui=\"group-attributes\">\n {attributes.map(([name, v]) => (\n <div key={name} className=\"contents\">\n <dt className=\"text-muted-foreground\">{labelOf(p.labels, name)}</dt>\n <dd className=\"break-words\">{formatAttribute(m, declared[name], v, p.labels)}</dd>\n </div>\n ))}\n </dl>\n )}\n {g.children.length > 0 && (\n <nav aria-label={t(\"groups.children\")} className=\"flex flex-wrap gap-2\" data-ckui=\"group-children\">\n {g.children.map((c) => (\n <GroupLink key={c.id} group={c} href={p.href} className=\"rounded-md border border-border px-2 py-1 hover:bg-muted\">\n {c.name || c.slug}\n </GroupLink>\n ))}\n </nav>\n )}\n {p.children}\n </div>\n </div>,\n );\n}\n"],"mappings":"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"}
@@ -20,16 +20,16 @@ function I(r) {
20
20
  let o = e(), { t: s } = o, { kinds: c, loading: l } = i({ client: r.client }), u = n(r.content, {
21
21
  language: r.language,
22
22
  client: r.client
23
- }), d = E(() => r.groupKinds ?? c?.kinds[r.contentKind]?.groups ?? [], [
23
+ }), d = E(() => r.groupKinds ?? c?.kinds[r.contentKind]?.entities ?? [], [
24
24
  r.groupKinds,
25
25
  c,
26
26
  r.contentKind
27
- ]), [f, p] = O(/* @__PURE__ */ new Map()), m = E(() => new Map([...u.groups, ...f]), [u.groups, f]), v = D(0), b = E(() => u.memberships.filter((e) => d.includes(u.groups.get(e.group_id ?? "")?.kind ?? "")).map((e) => ({
27
+ ]), [f, p] = O(/* @__PURE__ */ new Map()), m = E(() => new Map([...u.entities, ...f]), [u.entities, f]), v = D(0), b = E(() => u.memberships.filter((e) => d.includes(u.entities.get(e.group_id ?? "")?.kind ?? "")).map((e) => ({
28
28
  ...e,
29
29
  content_id: void 0
30
30
  })), [
31
31
  u.memberships,
32
- u.groups,
32
+ u.entities,
33
33
  d
34
34
  ]), [x, T] = O([]), k = !F(x.map(P), b), N = D(k);
35
35
  N.current = k, w(() => {
@@ -68,7 +68,7 @@ function I(r) {
68
68
  className: "grid gap-5",
69
69
  onSubmit: (e) => {
70
70
  e.preventDefault(), z(!1), I.run(() => u.set(x.map(P), [...d])).then((e) => {
71
- e && (z(!0), T(e.memberships.filter((t) => d.includes(e.groups.find((e) => e.id === t.group_id)?.kind ?? "")).map((e) => ({
71
+ e && (z(!0), T(e.memberships.filter((t) => d.includes(e.entities.find((e) => e.id === t.group_id)?.kind ?? "")).map((e) => ({
72
72
  ...e,
73
73
  content_id: void 0,
74
74
  key: ++v.current
@@ -77,7 +77,7 @@ function I(r) {
77
77
  },
78
78
  children: [
79
79
  d.map((e) => {
80
- let t = c?.group_kinds?.[e] ?? {}, n = x.filter((t) => m.get(t.group_id ?? "")?.kind === e), i = C(r.labels, e);
80
+ let t = c?.entity_kinds?.[e] ?? {}, n = x.filter((t) => m.get(t.group_id ?? "")?.kind === e), i = C(r.labels, e);
81
81
  return /* @__PURE__ */ j("fieldset", {
82
82
  className: "grid gap-2",
83
83
  "data-ckui": "membership-kind",
@@ -276,7 +276,7 @@ function R({ from: t, until: n, name: r, onChange: i }) {
276
276
  }
277
277
  var z = (e) => `${e.content_id}|${e.version_id ?? ""}`;
278
278
  function B(n) {
279
- let c = e(), { t: l } = c, { kinds: u } = i({ client: n.client }), d = u?.group_kinds?.[n.group.kind] ?? {}, f = r(n.group.id, {
279
+ let c = e(), { t: l } = c, { kinds: u } = i({ client: n.client }), d = u?.entity_kinds?.[n.group.kind] ?? {}, f = r(n.group.id, {
280
280
  pageSize: n.pageSize,
281
281
  client: n.client
282
282
  }), p = y("membership.save", n.onError), [m, b] = O(null), [x, S] = O({}), w = (e) => n.renderContent ? n.renderContent(e) : /* @__PURE__ */ A("span", {