@openrails/contentkit-ui 0.87.0 → 0.89.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 (58) hide show
  1. package/dist/client/generated/routes.d.ts +1 -1
  2. package/dist/client/generated/routes.js +1 -1
  3. package/dist/client/generated/routes.js.map +1 -1
  4. package/dist/client/generated/wire.d.ts +7 -0
  5. package/dist/client/generated/wire.js.map +1 -1
  6. package/dist/client/media/rules.js +1 -1
  7. package/dist/client/media/rules.js.map +1 -1
  8. package/dist/client/public.d.ts +2 -1
  9. package/dist/client/public.js +2 -2
  10. package/dist/client/public.js.map +1 -1
  11. package/dist/client/stats.d.ts +1 -1
  12. package/dist/client/stats.js.map +1 -1
  13. package/dist/components/billing-notification.d.ts +11 -0
  14. package/dist/components/billing-notification.js +70 -0
  15. package/dist/components/billing-notification.js.map +1 -0
  16. package/dist/components/content/card.d.ts +1 -1
  17. package/dist/components/content/card.js +132 -120
  18. package/dist/components/content/card.js.map +1 -1
  19. package/dist/components/content/filters.d.ts +1 -1
  20. package/dist/components/content/filters.js +2 -5
  21. package/dist/components/content/filters.js.map +1 -1
  22. package/dist/components/content/reader-stats.d.ts +11 -3
  23. package/dist/components/content/reader-stats.js +41 -23
  24. package/dist/components/content/reader-stats.js.map +1 -1
  25. package/dist/index.d.ts +1 -0
  26. package/dist/index.js +3 -2
  27. package/dist/locales/content/de.js +4 -0
  28. package/dist/locales/content/de.js.map +1 -1
  29. package/dist/locales/content/en.d.ts +4 -0
  30. package/dist/locales/content/en.js +4 -0
  31. package/dist/locales/content/en.js.map +1 -1
  32. package/dist/locales/content/es.js +4 -0
  33. package/dist/locales/content/es.js.map +1 -1
  34. package/dist/locales/content/ja.js +4 -0
  35. package/dist/locales/content/ja.js.map +1 -1
  36. package/dist/locales/content/ko.js +4 -0
  37. package/dist/locales/content/ko.js.map +1 -1
  38. package/dist/locales/content/zh.js +4 -0
  39. package/dist/locales/content/zh.js.map +1 -1
  40. package/dist/locales/en.d.ts +34 -0
  41. package/dist/locales/social/de.js +30 -0
  42. package/dist/locales/social/de.js.map +1 -1
  43. package/dist/locales/social/en.d.ts +30 -0
  44. package/dist/locales/social/en.js +30 -0
  45. package/dist/locales/social/en.js.map +1 -1
  46. package/dist/locales/social/es.js +30 -0
  47. package/dist/locales/social/es.js.map +1 -1
  48. package/dist/locales/social/ja.js +30 -0
  49. package/dist/locales/social/ja.js.map +1 -1
  50. package/dist/locales/social/ko.js +30 -0
  51. package/dist/locales/social/ko.js.map +1 -1
  52. package/dist/locales/social/zh.js +30 -0
  53. package/dist/locales/social/zh.js.map +1 -1
  54. package/dist/react/public.d.ts +3 -3
  55. package/dist/react/public.js +64 -25
  56. package/dist/react/public.js.map +1 -1
  57. package/dist/styles.css +1 -1
  58. package/package.json +5 -5
@@ -1,39 +1,40 @@
1
1
  import { RenditionImg as e } from "../rendition-img.js";
2
2
  import { useLanguageName as t, useMessages as n } from "../../i18n/context.js";
3
3
  import { ContentKitContext as r } from "../../react/context.js";
4
- import { Badge as i } from "../../ui/badge.js";
5
- import { RelativeTime as a, formatDate as o } from "../social/parts.js";
6
- import { GroupAvatar as s, GroupLink as c, labelOf as l } from "../groups/parts.js";
7
- import { priceLabel as u } from "./paywall.js";
8
- import { useCallback as d, useContext as f } from "react";
9
- import { jsx as p, jsxs as m } from "react/jsx-runtime";
10
- import { cn as h } from "cn";
11
- import { FavouriteIcon as g, LockIcon as _, ThumbsUpIcon as v } from "@hugeicons/core-free-icons";
12
- import { HugeiconsIcon as y } from "@hugeicons/react";
4
+ import { HoverPreview as i } from "../hover-preview.js";
5
+ import { Badge as a } from "../../ui/badge.js";
6
+ import { RelativeTime as o, formatDate as s } from "../social/parts.js";
7
+ import { GroupAvatar as c, GroupLink as l, labelOf as u } from "../groups/parts.js";
8
+ import { priceLabel as d } from "./paywall.js";
9
+ import { useCallback as f, useContext as p, useState as m } from "react";
10
+ import { jsx as h, jsxs as g } from "react/jsx-runtime";
11
+ import { cn as _ } from "cn";
12
+ import { FavouriteIcon as v, LockIcon as y, ThumbsUpIcon as b } from "@hugeicons/core-free-icons";
13
+ import { HugeiconsIcon as x } from "@hugeicons/react";
13
14
  //#region src/components/content/card.tsx
14
- function b({ card: e, decorate: t }) {
15
+ function S({ card: e, decorate: t }) {
15
16
  let n = t?.(e);
16
- return n == null || n === !1 ? null : /* @__PURE__ */ p("span", {
17
+ return n == null || n === !1 ? null : /* @__PURE__ */ h("span", {
17
18
  className: "pointer-events-none absolute inset-0",
18
19
  "data-ckui": "card-decorations",
19
20
  children: n
20
21
  });
21
22
  }
22
- var x = (e, t) => new Intl.NumberFormat(t, {
23
+ var C = (e, t) => new Intl.NumberFormat(t, {
23
24
  notation: "compact",
24
25
  maximumFractionDigits: 1
25
26
  }).format(e);
26
- function S(e, t, n = [], r) {
27
+ function w(e, t, n = [], r) {
27
28
  if (t.allowed) return null;
28
29
  if (t.unknown) return e.t("contents.unknownAccess");
29
30
  let i = t.offers?.[0];
30
- if (i) return i.target.kind === "group" && Number(i.terms.amount) === 0 ? e.t("contents.joinFree") : u(e, i.terms);
31
+ if (i) return i.target.kind === "group" && Number(i.terms.amount) === 0 ? e.t("contents.joinFree") : d(e, i.terms);
31
32
  let a = t.sell?.find((e) => n.includes(e));
32
- return a ? l(r, a) : t.sell?.some((e) => e.includes(":group:")) ? e.t("contents.members") : t.sell?.length ? e.t("contents.forSale") : e.t("contents.locked");
33
+ return a ? u(r, a) : t.sell?.some((e) => e.includes(":group:")) ? e.t("contents.members") : t.sell?.length ? e.t("contents.forSale") : e.t("contents.locked");
33
34
  }
34
- function C(e, t) {
35
- let n = f(r)?.navigate;
36
- return d((r) => {
35
+ function T(e, t) {
36
+ let n = p(r)?.navigate;
37
+ return f((r) => {
37
38
  t?.(), !(!n || !e || r.defaultPrevented || r.button !== 0 || r.metaKey || r.ctrlKey || r.shiftKey || r.altKey) && (r.preventDefault(), n(e));
38
39
  }, [
39
40
  n,
@@ -41,226 +42,237 @@ function C(e, t) {
41
42
  t
42
43
  ]);
43
44
  }
44
- function w({ card: r, href: a, onOpen: s, shape: c = "portrait", groupKinds: u, chips: f = 3, tiers: w, labels: D, owner: O = !0, ownerHref: k, decorate: A, children: j, className: M }) {
45
- let N = n(), { t: P } = N, F = t(), I = a ? a(r) : r.path, L = C(I, d(() => s?.(r), [s, r])), R = S(N, r.access, w, D), z = r.version, B = r.viewer && r.viewer.progress_max > 0 ? Math.min(1, r.viewer.progress / r.viewer.progress_max) : 0, V = u ?? Object.keys(r.groups), H = z.duration_ms ? Math.round(z.duration_ms / 6e4) : 0, U = [
46
- ...z.languages.map(F),
47
- ...z.traits.map((e) => l(D, e)),
48
- z.pages ? N.plural("contents.pages", z.pages) : null,
49
- H ? N.plural("contents.minutes", H) : null
50
- ].filter(Boolean), W = r.title || r.code;
51
- return /* @__PURE__ */ m("article", {
52
- className: h("group/card grid content-start gap-2", M),
45
+ function E({ card: r, href: o, onOpen: c, shape: l = "portrait", groupKinds: d, chips: p = 3, tiers: E, labels: k, owner: A = !0, ownerHref: j, decorate: M, children: N, className: P }) {
46
+ let F = n(), { t: I } = F, L = t(), R = o ? o(r) : r.path, z = T(R, f(() => c?.(r), [c, r])), B = w(F, r.access, E, k), V = r.version, H = r.viewer && r.viewer.progress_max > 0 ? Math.min(1, r.viewer.progress / r.viewer.progress_max) : 0, U = d ?? Object.keys(r.groups), W = V.duration_ms ? Math.round(V.duration_ms / 6e4) : 0, G = [
47
+ ...V.languages.map(L),
48
+ ...V.traits.map((e) => u(k, e)),
49
+ V.pages ? F.plural("contents.pages", V.pages) : null,
50
+ W ? F.plural("contents.minutes", W) : null
51
+ ].filter(Boolean), K = r.title || r.code, [q, J] = m(null);
52
+ return /* @__PURE__ */ g("article", {
53
+ ref: J,
54
+ className: _("group/card grid content-start gap-2", P),
53
55
  "data-ckui": "content-card",
54
56
  "data-id": r.id,
55
- "data-locked": R ? "" : void 0,
57
+ "data-locked": B ? "" : void 0,
56
58
  lang: r.language || void 0,
57
- children: [/* @__PURE__ */ m("div", {
59
+ children: [/* @__PURE__ */ g("div", {
58
60
  className: "relative overflow-hidden rounded-lg",
59
- children: [/* @__PURE__ */ m("a", {
60
- href: I,
61
- onClick: L,
61
+ children: [/* @__PURE__ */ g("a", {
62
+ href: R,
63
+ onClick: z,
62
64
  className: "relative block overflow-hidden rounded-lg bg-muted",
63
65
  tabIndex: -1,
64
66
  "aria-hidden": !0,
65
67
  children: [
66
- /* @__PURE__ */ p("div", {
67
- className: c === "landscape" ? "aspect-video" : "aspect-[3/4]",
68
- children: /* @__PURE__ */ p(e, {
68
+ /* @__PURE__ */ h("div", {
69
+ className: l === "landscape" ? "aspect-video" : "aspect-[3/4]",
70
+ children: /* @__PURE__ */ h(e, {
69
71
  outputs: r.cover,
70
72
  alt: "",
71
73
  fit: "cover",
72
74
  skeleton: !0,
73
75
  className: "size-full transition-transform group-hover/card:scale-[1.02]",
74
- fallback: /* @__PURE__ */ p("span", {
76
+ fallback: /* @__PURE__ */ h("span", {
75
77
  className: "grid size-full place-items-center text-2xl font-semibold text-muted-foreground",
76
- children: W.charAt(0).toUpperCase()
78
+ children: K.charAt(0).toUpperCase()
77
79
  })
78
80
  })
79
81
  }),
80
- R && /* @__PURE__ */ m("span", {
82
+ V.hls && /* @__PURE__ */ h(i, {
83
+ item: {
84
+ kind: r.kind,
85
+ id: r.id,
86
+ version: V.id
87
+ },
88
+ dir: V.hls,
89
+ duration: V.duration_ms ? V.duration_ms / 1e3 : void 0,
90
+ target: q
91
+ }),
92
+ B && /* @__PURE__ */ g("span", {
81
93
  className: "absolute top-2 left-2 inline-flex items-center gap-1 rounded-md bg-background/85 px-1.5 py-0.5 text-xs font-medium text-foreground shadow-sm",
82
94
  "data-ckui": "card-lock",
83
- children: [/* @__PURE__ */ p(y, {
84
- icon: _,
95
+ children: [/* @__PURE__ */ h(x, {
96
+ icon: y,
85
97
  strokeWidth: 2,
86
98
  className: "size-3.5",
87
99
  "aria-hidden": !0
88
- }), R]
100
+ }), B]
89
101
  }),
90
- B > 0 && /* @__PURE__ */ p("span", {
102
+ H > 0 && /* @__PURE__ */ h("span", {
91
103
  className: "absolute inset-x-0 bottom-0 h-1 bg-background/60",
92
104
  "data-ckui": "card-progress",
93
- children: /* @__PURE__ */ p("span", {
105
+ children: /* @__PURE__ */ h("span", {
94
106
  className: "block h-full bg-primary",
95
- style: { width: `${Math.round(B * 100)}%` }
107
+ style: { width: `${Math.round(H * 100)}%` }
96
108
  })
97
109
  })
98
110
  ]
99
- }), /* @__PURE__ */ p(b, {
111
+ }), /* @__PURE__ */ h(S, {
100
112
  card: r,
101
- decorate: A
113
+ decorate: M
102
114
  })]
103
- }), /* @__PURE__ */ m("div", {
115
+ }), /* @__PURE__ */ g("div", {
104
116
  className: "grid gap-1",
105
117
  children: [
106
- /* @__PURE__ */ m("a", {
107
- href: I,
108
- onClick: L,
118
+ /* @__PURE__ */ g("a", {
119
+ href: R,
120
+ onClick: z,
109
121
  className: "line-clamp-2 font-medium break-words hover:underline",
110
122
  "data-ckui": "card-title",
111
- children: [W, R && /* @__PURE__ */ m("span", {
123
+ children: [K, B && /* @__PURE__ */ g("span", {
112
124
  className: "sr-only",
113
125
  children: [
114
126
  " (",
115
- R,
127
+ B,
116
128
  ")"
117
129
  ]
118
130
  })]
119
131
  }),
120
- O && r.owner && /* @__PURE__ */ p(T, {
132
+ A && r.owner && /* @__PURE__ */ h(D, {
121
133
  group: r.owner,
122
- href: k
134
+ href: j
123
135
  }),
124
- U.length > 0 && /* @__PURE__ */ p("p", {
136
+ G.length > 0 && /* @__PURE__ */ h("p", {
125
137
  className: "text-xs text-muted-foreground",
126
- children: U.join(" · ")
138
+ children: G.join(" · ")
127
139
  }),
128
- r.viewer?.completed && /* @__PURE__ */ p(i, {
140
+ r.viewer?.completed && /* @__PURE__ */ h(a, {
129
141
  variant: "secondary",
130
142
  className: "justify-self-start",
131
- children: P("contents.completed")
143
+ children: I("contents.completed")
132
144
  }),
133
- !r.access.allowed && r.access.free_after && /* @__PURE__ */ p("p", {
145
+ !r.access.allowed && r.access.free_after && /* @__PURE__ */ h("p", {
134
146
  className: "text-xs text-muted-foreground",
135
- children: P("contents.freeFrom", { date: o(N, r.access.free_after, !1) })
147
+ children: I("contents.freeFrom", { date: s(F, r.access.free_after, !1) })
136
148
  }),
137
- V.some((e) => r.groups[e]?.length) && /* @__PURE__ */ p("ul", {
149
+ U.some((e) => r.groups[e]?.length) && /* @__PURE__ */ h("ul", {
138
150
  className: "flex flex-wrap gap-1",
139
151
  "data-ckui": "card-groups",
140
- children: V.flatMap((e) => (r.groups[e] ?? []).slice(0, f).map((t) => /* @__PURE__ */ p("li", {
152
+ children: U.flatMap((e) => (r.groups[e] ?? []).slice(0, p).map((t) => /* @__PURE__ */ h("li", {
141
153
  "data-kind": e,
142
- children: /* @__PURE__ */ p(E, {
154
+ children: /* @__PURE__ */ h(O, {
143
155
  url: t.path,
144
156
  name: t.name || t.slug
145
157
  })
146
158
  }, `${e}:${t.id}`)))
147
159
  }),
148
- (r.counts.favorites !== void 0 || r.counts.likes !== void 0) && /* @__PURE__ */ m("p", {
160
+ (r.counts.favorites !== void 0 || r.counts.likes !== void 0) && /* @__PURE__ */ g("p", {
149
161
  className: "flex items-center gap-3 text-xs text-muted-foreground tabular-nums",
150
162
  "data-ckui": "card-counts",
151
- children: [r.counts.favorites !== void 0 && /* @__PURE__ */ m("span", {
163
+ children: [r.counts.favorites !== void 0 && /* @__PURE__ */ g("span", {
152
164
  className: "inline-flex items-center gap-1",
153
- title: P("contents.favorites"),
165
+ title: I("contents.favorites"),
154
166
  children: [
155
- /* @__PURE__ */ p(y, {
156
- icon: g,
167
+ /* @__PURE__ */ h(x, {
168
+ icon: v,
157
169
  strokeWidth: 2,
158
- className: h("size-3.5", r.viewer?.favorited && "fill-current text-primary"),
170
+ className: _("size-3.5", r.viewer?.favorited && "fill-current text-primary"),
159
171
  "aria-hidden": !0
160
172
  }),
161
- /* @__PURE__ */ p("span", {
173
+ /* @__PURE__ */ h("span", {
162
174
  className: "sr-only",
163
- children: P("contents.favorites")
175
+ children: I("contents.favorites")
164
176
  }),
165
- x(r.counts.favorites, N.language)
177
+ C(r.counts.favorites, F.language)
166
178
  ]
167
- }), r.counts.likes !== void 0 && /* @__PURE__ */ m("span", {
179
+ }), r.counts.likes !== void 0 && /* @__PURE__ */ g("span", {
168
180
  className: "inline-flex items-center gap-1",
169
- title: P("contents.likes"),
181
+ title: I("contents.likes"),
170
182
  children: [
171
- /* @__PURE__ */ p(y, {
172
- icon: v,
183
+ /* @__PURE__ */ h(x, {
184
+ icon: b,
173
185
  strokeWidth: 2,
174
186
  className: "size-3.5",
175
187
  "aria-hidden": !0
176
188
  }),
177
- /* @__PURE__ */ p("span", {
189
+ /* @__PURE__ */ h("span", {
178
190
  className: "sr-only",
179
- children: P("contents.likes")
191
+ children: I("contents.likes")
180
192
  }),
181
- x(r.counts.likes, N.language)
193
+ C(r.counts.likes, F.language)
182
194
  ]
183
195
  })]
184
196
  }),
185
- j
197
+ N
186
198
  ]
187
199
  })]
188
200
  });
189
201
  }
190
- function T({ group: e, href: t, className: n }) {
191
- return /* @__PURE__ */ p("span", {
192
- className: h("flex min-w-0 text-xs text-muted-foreground", n),
202
+ function D({ group: e, href: t, className: n }) {
203
+ return /* @__PURE__ */ h("span", {
204
+ className: _("flex min-w-0 text-xs text-muted-foreground", n),
193
205
  "data-ckui": "card-owner",
194
206
  "data-id": e.id,
195
- children: /* @__PURE__ */ m(c, {
207
+ children: /* @__PURE__ */ g(l, {
196
208
  group: e,
197
209
  href: t,
198
210
  className: "inline-flex min-w-0 items-center gap-1.5 hover:text-foreground",
199
- children: [/* @__PURE__ */ p(s, {
211
+ children: [/* @__PURE__ */ h(c, {
200
212
  group: e,
201
213
  className: "size-5 shrink-0 text-[0.625rem]"
202
- }), /* @__PURE__ */ p("span", {
214
+ }), /* @__PURE__ */ h("span", {
203
215
  className: "truncate",
204
216
  children: e.name || e.slug
205
217
  })]
206
218
  })
207
219
  });
208
220
  }
209
- function E({ url: e, name: t }) {
210
- let n = C(e), r = "inline-block rounded-md border border-border px-1.5 py-0.5 text-xs text-muted-foreground";
211
- return e ? /* @__PURE__ */ p("a", {
221
+ function O({ url: e, name: t }) {
222
+ let n = T(e), r = "inline-block rounded-md border border-border px-1.5 py-0.5 text-xs text-muted-foreground";
223
+ return e ? /* @__PURE__ */ h("a", {
212
224
  href: e,
213
225
  onClick: n,
214
- className: h(r, "hover:bg-muted hover:text-foreground"),
226
+ className: _(r, "hover:bg-muted hover:text-foreground"),
215
227
  children: t
216
- }) : /* @__PURE__ */ p("span", {
228
+ }) : /* @__PURE__ */ h("span", {
217
229
  className: r,
218
230
  children: t
219
231
  });
220
232
  }
221
- function D({ card: t, href: r, onOpen: i, tiers: o, labels: s, byline: c, owner: l = !0, ownerHref: u, decorate: f, children: v, className: w }) {
222
- let E = n(), D = r ? r(t) : t.path, O = C(D, d(() => i?.(t), [i, t])), k = S(E, t.access, o, s), A = t.title || t.code;
223
- return /* @__PURE__ */ m("article", {
224
- className: h("grid gap-3 rounded-lg border border-border p-3", w),
233
+ function k({ card: t, href: r, onOpen: i, tiers: a, labels: s, byline: c, owner: l = !0, ownerHref: u, decorate: d, children: p, className: m }) {
234
+ let b = n(), E = r ? r(t) : t.path, O = T(E, f(() => i?.(t), [i, t])), k = w(b, t.access, a, s), A = t.title || t.code;
235
+ return /* @__PURE__ */ g("article", {
236
+ className: _("grid gap-3 rounded-lg border border-border p-3", m),
225
237
  "data-ckui": "post-card",
226
238
  "data-id": t.id,
227
239
  "data-locked": k ? "" : void 0,
228
240
  lang: t.language || void 0,
229
241
  children: [
230
- c ?? (l && t.owner && /* @__PURE__ */ p(T, {
242
+ c ?? (l && t.owner && /* @__PURE__ */ h(D, {
231
243
  group: t.owner,
232
244
  href: u,
233
245
  className: "text-sm"
234
246
  })),
235
- /* @__PURE__ */ m("a", {
236
- href: D,
247
+ /* @__PURE__ */ g("a", {
248
+ href: E,
237
249
  onClick: O,
238
250
  className: "grid gap-2",
239
- children: [/* @__PURE__ */ p("span", {
251
+ children: [/* @__PURE__ */ h("span", {
240
252
  className: "font-medium break-words hover:underline",
241
253
  "data-ckui": "card-title",
242
254
  children: A
243
- }), t.cover.length > 0 && /* @__PURE__ */ m("span", {
255
+ }), t.cover.length > 0 && /* @__PURE__ */ g("span", {
244
256
  className: "relative block aspect-video overflow-hidden rounded-md bg-muted",
245
257
  children: [
246
- /* @__PURE__ */ p(e, {
258
+ /* @__PURE__ */ h(e, {
247
259
  outputs: t.cover,
248
260
  alt: "",
249
261
  fit: "cover",
250
262
  skeleton: !0,
251
- className: h("size-full", k && "blur-md")
263
+ className: _("size-full", k && "blur-md")
252
264
  }),
253
- /* @__PURE__ */ p(b, {
265
+ /* @__PURE__ */ h(S, {
254
266
  card: t,
255
- decorate: f
267
+ decorate: d
256
268
  }),
257
- k && /* @__PURE__ */ p("span", {
269
+ k && /* @__PURE__ */ h("span", {
258
270
  className: "absolute inset-0 grid place-items-center",
259
- children: /* @__PURE__ */ m("span", {
271
+ children: /* @__PURE__ */ g("span", {
260
272
  className: "inline-flex items-center gap-1 rounded-md bg-background/85 px-2 py-1 text-xs font-medium shadow-sm",
261
273
  "data-ckui": "card-lock",
262
- children: [/* @__PURE__ */ p(y, {
263
- icon: _,
274
+ children: [/* @__PURE__ */ h(x, {
275
+ icon: y,
264
276
  strokeWidth: 2,
265
277
  className: "size-3.5",
266
278
  "aria-hidden": !0
@@ -270,38 +282,38 @@ function D({ card: t, href: r, onOpen: i, tiers: o, labels: s, byline: c, owner:
270
282
  ]
271
283
  })]
272
284
  }),
273
- /* @__PURE__ */ m("p", {
285
+ /* @__PURE__ */ g("p", {
274
286
  className: "flex flex-wrap items-center gap-3 text-xs text-muted-foreground",
275
287
  children: [
276
- t.published_at && /* @__PURE__ */ p(a, { at: t.published_at }),
277
- !t.cover.length && k && /* @__PURE__ */ p("span", {
288
+ t.published_at && /* @__PURE__ */ h(o, { at: t.published_at }),
289
+ !t.cover.length && k && /* @__PURE__ */ h("span", {
278
290
  "data-ckui": "card-lock",
279
291
  children: k
280
292
  }),
281
- t.counts.favorites !== void 0 && /* @__PURE__ */ m("span", {
293
+ t.counts.favorites !== void 0 && /* @__PURE__ */ g("span", {
282
294
  className: "inline-flex items-center gap-1 tabular-nums",
283
295
  "data-ckui": "card-counts",
284
296
  children: [
285
- /* @__PURE__ */ p(y, {
286
- icon: g,
297
+ /* @__PURE__ */ h(x, {
298
+ icon: v,
287
299
  strokeWidth: 2,
288
- className: h("size-3.5", t.viewer?.favorited && "fill-current text-primary"),
300
+ className: _("size-3.5", t.viewer?.favorited && "fill-current text-primary"),
289
301
  "aria-hidden": !0
290
302
  }),
291
- /* @__PURE__ */ p("span", {
303
+ /* @__PURE__ */ h("span", {
292
304
  className: "sr-only",
293
- children: E.t("contents.favorites")
305
+ children: b.t("contents.favorites")
294
306
  }),
295
- x(t.counts.favorites, E.language)
307
+ C(t.counts.favorites, b.language)
296
308
  ]
297
309
  })
298
310
  ]
299
311
  }),
300
- v
312
+ p
301
313
  ]
302
314
  });
303
315
  }
304
316
  //#endregion
305
- export { w as ContentCard, T as OwnerChip, D as PostCard, S as lockLabel };
317
+ export { E as ContentCard, D as OwnerChip, k as PostCard, w as lockLabel };
306
318
 
307
319
  //# sourceMappingURL=card.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"card.js","names":[],"sources":["../../../src/components/content/card.tsx"],"sourcesContent":["import { FavouriteIcon, LockIcon, ThumbsUpIcon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useCallback, useContext, type MouseEvent, type ReactNode } from \"react\";\nimport type { Card, CardAccess } from \"../../client/generated/wire.js\";\nimport { useLanguageName, useMessages } from \"../../i18n/context.js\";\nimport type { Translator } from \"../../i18n/messages.js\";\nimport { ContentKitContext } from \"../../react/context.js\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { RenditionImg } from \"../rendition-img.js\";\nimport { formatDate, RelativeTime } from \"../social/parts.js\";\nimport { GroupAvatar, GroupLink, labelOf, type GroupLike, type Labels } from \"../groups/parts.js\";\nimport { priceLabel } from \"./paywall.js\";\n\nexport interface ContentCardProps {\n card: Card;\n /** The card's link; default its canonical path. */\n href?: (card: Card) => string | undefined;\n /** Before the card's link is followed: a click signal. */\n onOpen?: (card: Card) => void;\n /** Cover shape: \"portrait\" (3:4, readers) or \"landscape\" (16:9, players). Default portrait. */\n shape?: \"portrait\" | \"landscape\";\n /** The group kinds whose chips show, in order; default every kind the card names. */\n groupKinds?: readonly string[];\n /** Chips per group kind. Default 3. */\n chips?: number;\n /** Tiers the site sells, so a lock names them; others show as \"for sale\". */\n tiers?: readonly string[];\n /** Display names of kinds, traits and tiers by identifier. */\n labels?: Labels;\n /** Show the owner group (a channel) when the card has one; default true, false on that group's own feed. */\n owner?: boolean;\n /** The owner group's link; default its canonical path. */\n ownerHref?: (g: GroupLike) => string | undefined;\n /** Over the cover: the host's badges for the card, placed in the cover's box; clicks reach the card. */\n decorate?: (card: Card) => ReactNode;\n /** Below the meta line: the host's own. */\n children?: ReactNode;\n className?: string;\n}\n\n/** The host's badges over a cover. */\nfunction Decorations({ card, decorate }: { card: Card; decorate?: (card: Card) => ReactNode }) {\n const badges = decorate?.(card);\n if (badges == null || badges === false) return null;\n return (\n <span className=\"pointer-events-none absolute inset-0\" data-ckui=\"card-decorations\">\n {badges}\n </span>\n );\n}\n\nconst compact = (n: number, language?: string) => new Intl.NumberFormat(language, { notation: \"compact\", maximumFractionDigits: 1 }).format(n);\n\n/** Why a card is locked, in words (its price when it is on sale); null when it opens. */\nexport function lockLabel(m: Translator, a: CardAccess, tiers: readonly string[] = [], labels?: Labels): string | null {\n if (a.allowed) return null;\n if (a.unknown) return m.t(\"contents.unknownAccess\");\n const offer = a.offers?.[0];\n if (offer) return offer.target.kind === \"group\" && Number(offer.terms.amount) === 0 ? m.t(\"contents.joinFree\") : priceLabel(m, offer.terms);\n const tier = a.sell?.find((k) => tiers.includes(k));\n if (tier) return labelOf(labels, tier);\n if (a.sell?.some((k) => k.includes(\":group:\"))) return m.t(\"contents.members\");\n if (a.sell?.length) return m.t(\"contents.forSale\");\n return m.t(\"contents.locked\");\n}\n\n/** A link followed in-app through the provider's navigate. */\nfunction useLink(url: string | undefined, before?: () => void) {\n const navigate = useContext(ContentKitContext)?.navigate;\n return useCallback(\n (e: MouseEvent<HTMLAnchorElement>) => {\n before?.();\n if (!navigate || !url || e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;\n e.preventDefault();\n navigate(url);\n },\n [navigate, url, before],\n );\n}\n\n/** One content in a listing: cover, title, version, groups, counts, the reader's progress and why it is locked; what its kind's locked view hides is absent. */\nexport function ContentCard({ card, href, onOpen, shape = \"portrait\", groupKinds, chips = 3, tiers, labels, owner = true, ownerHref, decorate, children, className }: ContentCardProps) {\n const m = useMessages();\n const { t } = m;\n const languageName = useLanguageName();\n const url = href ? href(card) : card.path;\n const open = useCallback(() => onOpen?.(card), [onOpen, card]);\n const onClick = useLink(url, open);\n const lock = lockLabel(m, card.access, tiers, labels);\n const v = card.version;\n const progress = card.viewer && card.viewer.progress_max > 0 ? Math.min(1, card.viewer.progress / card.viewer.progress_max) : 0;\n const kinds = groupKinds ?? Object.keys(card.groups);\n const minutes = v.duration_ms ? Math.round(v.duration_ms / 60_000) : 0;\n const meta = [\n ...v.languages.map(languageName),\n ...v.traits.map((x) => labelOf(labels, x)),\n v.pages ? m.plural(\"contents.pages\", v.pages) : null,\n minutes ? m.plural(\"contents.minutes\", minutes) : null,\n ].filter(Boolean);\n const title = card.title || card.code;\n return (\n <article className={cn(\"group/card grid content-start gap-2\", className)} data-ckui=\"content-card\" data-id={card.id} data-locked={lock ? \"\" : undefined} lang={card.language || undefined}>\n <div className=\"relative overflow-hidden rounded-lg\">\n <a href={url} onClick={onClick} className=\"relative block overflow-hidden rounded-lg bg-muted\" tabIndex={-1} aria-hidden>\n <div className={shape === \"landscape\" ? \"aspect-video\" : \"aspect-[3/4]\"}>\n <RenditionImg\n outputs={card.cover}\n alt=\"\"\n fit=\"cover\"\n skeleton\n className=\"size-full transition-transform group-hover/card:scale-[1.02]\"\n fallback={<span className=\"grid size-full place-items-center text-2xl font-semibold text-muted-foreground\">{title.charAt(0).toUpperCase()}</span>}\n />\n </div>\n {lock && (\n <span className=\"absolute top-2 left-2 inline-flex items-center gap-1 rounded-md bg-background/85 px-1.5 py-0.5 text-xs font-medium text-foreground shadow-sm\" data-ckui=\"card-lock\">\n <HugeiconsIcon icon={LockIcon} strokeWidth={2} className=\"size-3.5\" aria-hidden />\n {lock}\n </span>\n )}\n {progress > 0 && (\n <span className=\"absolute inset-x-0 bottom-0 h-1 bg-background/60\" data-ckui=\"card-progress\">\n <span className=\"block h-full bg-primary\" style={{ width: `${Math.round(progress * 100)}%` }} />\n </span>\n )}\n </a>\n <Decorations card={card} decorate={decorate} />\n </div>\n <div className=\"grid gap-1\">\n <a href={url} onClick={onClick} className=\"line-clamp-2 font-medium break-words hover:underline\" data-ckui=\"card-title\">\n {title}\n {lock && <span className=\"sr-only\"> ({lock})</span>}\n </a>\n {owner && card.owner && <OwnerChip group={card.owner} href={ownerHref} />}\n {meta.length > 0 && <p className=\"text-xs text-muted-foreground\">{meta.join(\" · \")}</p>}\n {card.viewer?.completed && (\n <Badge variant=\"secondary\" className=\"justify-self-start\">\n {t(\"contents.completed\")}\n </Badge>\n )}\n {!card.access.allowed && card.access.free_after && <p className=\"text-xs text-muted-foreground\">{t(\"contents.freeFrom\", { date: formatDate(m, card.access.free_after, false) })}</p>}\n {kinds.some((k) => card.groups[k]?.length) && (\n <ul className=\"flex flex-wrap gap-1\" data-ckui=\"card-groups\">\n {kinds.flatMap((k) =>\n (card.groups[k] ?? []).slice(0, chips).map((g) => (\n <li key={`${k}:${g.id}`} data-kind={k}>\n <Chip url={g.path} name={g.name || g.slug} />\n </li>\n )),\n )}\n </ul>\n )}\n {(card.counts.favorites !== undefined || card.counts.likes !== undefined) && (\n <p className=\"flex items-center gap-3 text-xs text-muted-foreground tabular-nums\" data-ckui=\"card-counts\">\n {card.counts.favorites !== undefined && (\n <span className=\"inline-flex items-center gap-1\" title={t(\"contents.favorites\")}>\n <HugeiconsIcon icon={FavouriteIcon} strokeWidth={2} className={cn(\"size-3.5\", card.viewer?.favorited && \"fill-current text-primary\")} aria-hidden />\n <span className=\"sr-only\">{t(\"contents.favorites\")}</span>\n {compact(card.counts.favorites, m.language)}\n </span>\n )}\n {card.counts.likes !== undefined && (\n <span className=\"inline-flex items-center gap-1\" title={t(\"contents.likes\")}>\n <HugeiconsIcon icon={ThumbsUpIcon} strokeWidth={2} className=\"size-3.5\" aria-hidden />\n <span className=\"sr-only\">{t(\"contents.likes\")}</span>\n {compact(card.counts.likes, m.language)}\n </span>\n )}\n </p>\n )}\n {children}\n </div>\n </article>\n );\n}\n\n/** The group that owns a content (a channel): its avatar and name, linking to its page. */\nexport function OwnerChip({ group, href, className }: { group: GroupLike; href?: (g: GroupLike) => string | undefined; className?: string }) {\n return (\n <span className={cn(\"flex min-w-0 text-xs text-muted-foreground\", className)} data-ckui=\"card-owner\" data-id={group.id}>\n <GroupLink group={group} href={href} className=\"inline-flex min-w-0 items-center gap-1.5 hover:text-foreground\">\n <GroupAvatar group={group} className=\"size-5 shrink-0 text-[0.625rem]\" />\n <span className=\"truncate\">{group.name || group.slug}</span>\n </GroupLink>\n </span>\n );\n}\n\nfunction Chip({ url, name }: { url?: string; name: string }) {\n const onClick = useLink(url);\n const cls = \"inline-block rounded-md border border-border px-1.5 py-0.5 text-xs text-muted-foreground\";\n return url ? (\n <a href={url} onClick={onClick} className={cn(cls, \"hover:bg-muted hover:text-foreground\")}>\n {name}\n </a>\n ) : (\n <span className={cls}>{name}</span>\n );\n}\n\nexport interface PostCardProps extends Omit<ContentCardProps, \"shape\" | \"chips\" | \"groupKinds\"> {\n /** Above the title: the post's channel or author; default its owner group's chip. */\n byline?: ReactNode;\n}\n\n/** A post in a feed: a wide cover, its title, when it was published and what unlocking it costs. */\nexport function PostCard({ card, href, onOpen, tiers, labels, byline, owner = true, ownerHref, decorate, children, className }: PostCardProps) {\n const m = useMessages();\n const url = href ? href(card) : card.path;\n const open = useCallback(() => onOpen?.(card), [onOpen, card]);\n const onClick = useLink(url, open);\n const lock = lockLabel(m, card.access, tiers, labels);\n const title = card.title || card.code;\n return (\n <article className={cn(\"grid gap-3 rounded-lg border border-border p-3\", className)} data-ckui=\"post-card\" data-id={card.id} data-locked={lock ? \"\" : undefined} lang={card.language || undefined}>\n {byline ?? (owner && card.owner && <OwnerChip group={card.owner} href={ownerHref} className=\"text-sm\" />)}\n <a href={url} onClick={onClick} className=\"grid gap-2\">\n <span className=\"font-medium break-words hover:underline\" data-ckui=\"card-title\">\n {title}\n </span>\n {card.cover.length > 0 && (\n <span className=\"relative block aspect-video overflow-hidden rounded-md bg-muted\">\n <RenditionImg outputs={card.cover} alt=\"\" fit=\"cover\" skeleton className={cn(\"size-full\", lock && \"blur-md\")} />\n <Decorations card={card} decorate={decorate} />\n {lock && (\n <span className=\"absolute inset-0 grid place-items-center\">\n <span className=\"inline-flex items-center gap-1 rounded-md bg-background/85 px-2 py-1 text-xs font-medium shadow-sm\" data-ckui=\"card-lock\">\n <HugeiconsIcon icon={LockIcon} strokeWidth={2} className=\"size-3.5\" aria-hidden />\n {lock}\n </span>\n </span>\n )}\n </span>\n )}\n </a>\n <p className=\"flex flex-wrap items-center gap-3 text-xs text-muted-foreground\">\n {card.published_at && <RelativeTime at={card.published_at} />}\n {!card.cover.length && lock && <span data-ckui=\"card-lock\">{lock}</span>}\n {card.counts.favorites !== undefined && (\n <span className=\"inline-flex items-center gap-1 tabular-nums\" data-ckui=\"card-counts\">\n <HugeiconsIcon icon={FavouriteIcon} strokeWidth={2} className={cn(\"size-3.5\", card.viewer?.favorited && \"fill-current text-primary\")} aria-hidden />\n <span className=\"sr-only\">{m.t(\"contents.favorites\")}</span>\n {compact(card.counts.favorites, m.language)}\n </span>\n )}\n </p>\n {children}\n </article>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"card.js","names":[],"sources":["../../../src/components/content/card.tsx"],"sourcesContent":["import { FavouriteIcon, LockIcon, ThumbsUpIcon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { cn } from \"cn\";\nimport { useCallback, useContext, useState, type MouseEvent, type ReactNode } from \"react\";\nimport type { Card, CardAccess } from \"../../client/generated/wire.js\";\nimport { useLanguageName, useMessages } from \"../../i18n/context.js\";\nimport type { Translator } from \"../../i18n/messages.js\";\nimport { ContentKitContext } from \"../../react/context.js\";\nimport { Badge } from \"#ckui/ui/badge\";\nimport { HoverPreview } from \"../hover-preview.js\";\nimport { RenditionImg } from \"../rendition-img.js\";\nimport { formatDate, RelativeTime } from \"../social/parts.js\";\nimport { GroupAvatar, GroupLink, labelOf, type GroupLike, type Labels } from \"../groups/parts.js\";\nimport { priceLabel } from \"./paywall.js\";\n\nexport interface ContentCardProps {\n card: Card;\n /** The card's link; default its canonical path. */\n href?: (card: Card) => string | undefined;\n /** Before the card's link is followed: a click signal. */\n onOpen?: (card: Card) => void;\n /** Cover shape: \"portrait\" (3:4, readers) or \"landscape\" (16:9, players). Default portrait. */\n shape?: \"portrait\" | \"landscape\";\n /** The group kinds whose chips show, in order; default every kind the card names. */\n groupKinds?: readonly string[];\n /** Chips per group kind. Default 3. */\n chips?: number;\n /** Tiers the site sells, so a lock names them; others show as \"for sale\". */\n tiers?: readonly string[];\n /** Display names of kinds, traits and tiers by identifier. */\n labels?: Labels;\n /** Show the owner group (a channel) when the card has one; default true, false on that group's own feed. */\n owner?: boolean;\n /** The owner group's link; default its canonical path. */\n ownerHref?: (g: GroupLike) => string | undefined;\n /** Over the cover: the host's badges for the card, placed in the cover's box; clicks reach the card. */\n decorate?: (card: Card) => ReactNode;\n /** Below the meta line: the host's own. */\n children?: ReactNode;\n className?: string;\n}\n\n/** The host's badges over a cover. */\nfunction Decorations({ card, decorate }: { card: Card; decorate?: (card: Card) => ReactNode }) {\n const badges = decorate?.(card);\n if (badges == null || badges === false) return null;\n return (\n <span className=\"pointer-events-none absolute inset-0\" data-ckui=\"card-decorations\">\n {badges}\n </span>\n );\n}\n\nconst compact = (n: number, language?: string) => new Intl.NumberFormat(language, { notation: \"compact\", maximumFractionDigits: 1 }).format(n);\n\n/** Why a card is locked, in words (its price when it is on sale); null when it opens. */\nexport function lockLabel(m: Translator, a: CardAccess, tiers: readonly string[] = [], labels?: Labels): string | null {\n if (a.allowed) return null;\n if (a.unknown) return m.t(\"contents.unknownAccess\");\n const offer = a.offers?.[0];\n if (offer) return offer.target.kind === \"group\" && Number(offer.terms.amount) === 0 ? m.t(\"contents.joinFree\") : priceLabel(m, offer.terms);\n const tier = a.sell?.find((k) => tiers.includes(k));\n if (tier) return labelOf(labels, tier);\n if (a.sell?.some((k) => k.includes(\":group:\"))) return m.t(\"contents.members\");\n if (a.sell?.length) return m.t(\"contents.forSale\");\n return m.t(\"contents.locked\");\n}\n\n/** A link followed in-app through the provider's navigate. */\nfunction useLink(url: string | undefined, before?: () => void) {\n const navigate = useContext(ContentKitContext)?.navigate;\n return useCallback(\n (e: MouseEvent<HTMLAnchorElement>) => {\n before?.();\n if (!navigate || !url || e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;\n e.preventDefault();\n navigate(url);\n },\n [navigate, url, before],\n );\n}\n\n/** One content in a listing: cover (a video the reader opens previews over it on hover), title, version, groups, counts, the reader's progress and why it is locked; what its kind's locked view hides is absent. */\nexport function ContentCard({ card, href, onOpen, shape = \"portrait\", groupKinds, chips = 3, tiers, labels, owner = true, ownerHref, decorate, children, className }: ContentCardProps) {\n const m = useMessages();\n const { t } = m;\n const languageName = useLanguageName();\n const url = href ? href(card) : card.path;\n const open = useCallback(() => onOpen?.(card), [onOpen, card]);\n const onClick = useLink(url, open);\n const lock = lockLabel(m, card.access, tiers, labels);\n const v = card.version;\n const progress = card.viewer && card.viewer.progress_max > 0 ? Math.min(1, card.viewer.progress / card.viewer.progress_max) : 0;\n const kinds = groupKinds ?? Object.keys(card.groups);\n const minutes = v.duration_ms ? Math.round(v.duration_ms / 60_000) : 0;\n const meta = [\n ...v.languages.map(languageName),\n ...v.traits.map((x) => labelOf(labels, x)),\n v.pages ? m.plural(\"contents.pages\", v.pages) : null,\n minutes ? m.plural(\"contents.minutes\", minutes) : null,\n ].filter(Boolean);\n const title = card.title || card.code;\n const [article, setArticle] = useState<HTMLElement | null>(null);\n return (\n <article ref={setArticle} className={cn(\"group/card grid content-start gap-2\", className)} data-ckui=\"content-card\" data-id={card.id} data-locked={lock ? \"\" : undefined} lang={card.language || undefined}>\n <div className=\"relative overflow-hidden rounded-lg\">\n <a href={url} onClick={onClick} className=\"relative block overflow-hidden rounded-lg bg-muted\" tabIndex={-1} aria-hidden>\n <div className={shape === \"landscape\" ? \"aspect-video\" : \"aspect-[3/4]\"}>\n <RenditionImg\n outputs={card.cover}\n alt=\"\"\n fit=\"cover\"\n skeleton\n className=\"size-full transition-transform group-hover/card:scale-[1.02]\"\n fallback={<span className=\"grid size-full place-items-center text-2xl font-semibold text-muted-foreground\">{title.charAt(0).toUpperCase()}</span>}\n />\n </div>\n {v.hls && <HoverPreview item={{ kind: card.kind, id: card.id, version: v.id }} dir={v.hls} duration={v.duration_ms ? v.duration_ms / 1000 : undefined} target={article} />}\n {lock && (\n <span className=\"absolute top-2 left-2 inline-flex items-center gap-1 rounded-md bg-background/85 px-1.5 py-0.5 text-xs font-medium text-foreground shadow-sm\" data-ckui=\"card-lock\">\n <HugeiconsIcon icon={LockIcon} strokeWidth={2} className=\"size-3.5\" aria-hidden />\n {lock}\n </span>\n )}\n {progress > 0 && (\n <span className=\"absolute inset-x-0 bottom-0 h-1 bg-background/60\" data-ckui=\"card-progress\">\n <span className=\"block h-full bg-primary\" style={{ width: `${Math.round(progress * 100)}%` }} />\n </span>\n )}\n </a>\n <Decorations card={card} decorate={decorate} />\n </div>\n <div className=\"grid gap-1\">\n <a href={url} onClick={onClick} className=\"line-clamp-2 font-medium break-words hover:underline\" data-ckui=\"card-title\">\n {title}\n {lock && <span className=\"sr-only\"> ({lock})</span>}\n </a>\n {owner && card.owner && <OwnerChip group={card.owner} href={ownerHref} />}\n {meta.length > 0 && <p className=\"text-xs text-muted-foreground\">{meta.join(\" · \")}</p>}\n {card.viewer?.completed && (\n <Badge variant=\"secondary\" className=\"justify-self-start\">\n {t(\"contents.completed\")}\n </Badge>\n )}\n {!card.access.allowed && card.access.free_after && <p className=\"text-xs text-muted-foreground\">{t(\"contents.freeFrom\", { date: formatDate(m, card.access.free_after, false) })}</p>}\n {kinds.some((k) => card.groups[k]?.length) && (\n <ul className=\"flex flex-wrap gap-1\" data-ckui=\"card-groups\">\n {kinds.flatMap((k) =>\n (card.groups[k] ?? []).slice(0, chips).map((g) => (\n <li key={`${k}:${g.id}`} data-kind={k}>\n <Chip url={g.path} name={g.name || g.slug} />\n </li>\n )),\n )}\n </ul>\n )}\n {(card.counts.favorites !== undefined || card.counts.likes !== undefined) && (\n <p className=\"flex items-center gap-3 text-xs text-muted-foreground tabular-nums\" data-ckui=\"card-counts\">\n {card.counts.favorites !== undefined && (\n <span className=\"inline-flex items-center gap-1\" title={t(\"contents.favorites\")}>\n <HugeiconsIcon icon={FavouriteIcon} strokeWidth={2} className={cn(\"size-3.5\", card.viewer?.favorited && \"fill-current text-primary\")} aria-hidden />\n <span className=\"sr-only\">{t(\"contents.favorites\")}</span>\n {compact(card.counts.favorites, m.language)}\n </span>\n )}\n {card.counts.likes !== undefined && (\n <span className=\"inline-flex items-center gap-1\" title={t(\"contents.likes\")}>\n <HugeiconsIcon icon={ThumbsUpIcon} strokeWidth={2} className=\"size-3.5\" aria-hidden />\n <span className=\"sr-only\">{t(\"contents.likes\")}</span>\n {compact(card.counts.likes, m.language)}\n </span>\n )}\n </p>\n )}\n {children}\n </div>\n </article>\n );\n}\n\n/** The group that owns a content (a channel): its avatar and name, linking to its page. */\nexport function OwnerChip({ group, href, className }: { group: GroupLike; href?: (g: GroupLike) => string | undefined; className?: string }) {\n return (\n <span className={cn(\"flex min-w-0 text-xs text-muted-foreground\", className)} data-ckui=\"card-owner\" data-id={group.id}>\n <GroupLink group={group} href={href} className=\"inline-flex min-w-0 items-center gap-1.5 hover:text-foreground\">\n <GroupAvatar group={group} className=\"size-5 shrink-0 text-[0.625rem]\" />\n <span className=\"truncate\">{group.name || group.slug}</span>\n </GroupLink>\n </span>\n );\n}\n\nfunction Chip({ url, name }: { url?: string; name: string }) {\n const onClick = useLink(url);\n const cls = \"inline-block rounded-md border border-border px-1.5 py-0.5 text-xs text-muted-foreground\";\n return url ? (\n <a href={url} onClick={onClick} className={cn(cls, \"hover:bg-muted hover:text-foreground\")}>\n {name}\n </a>\n ) : (\n <span className={cls}>{name}</span>\n );\n}\n\nexport interface PostCardProps extends Omit<ContentCardProps, \"shape\" | \"chips\" | \"groupKinds\"> {\n /** Above the title: the post's channel or author; default its owner group's chip. */\n byline?: ReactNode;\n}\n\n/** A post in a feed: a wide cover, its title, when it was published and what unlocking it costs. */\nexport function PostCard({ card, href, onOpen, tiers, labels, byline, owner = true, ownerHref, decorate, children, className }: PostCardProps) {\n const m = useMessages();\n const url = href ? href(card) : card.path;\n const open = useCallback(() => onOpen?.(card), [onOpen, card]);\n const onClick = useLink(url, open);\n const lock = lockLabel(m, card.access, tiers, labels);\n const title = card.title || card.code;\n return (\n <article className={cn(\"grid gap-3 rounded-lg border border-border p-3\", className)} data-ckui=\"post-card\" data-id={card.id} data-locked={lock ? \"\" : undefined} lang={card.language || undefined}>\n {byline ?? (owner && card.owner && <OwnerChip group={card.owner} href={ownerHref} className=\"text-sm\" />)}\n <a href={url} onClick={onClick} className=\"grid gap-2\">\n <span className=\"font-medium break-words hover:underline\" data-ckui=\"card-title\">\n {title}\n </span>\n {card.cover.length > 0 && (\n <span className=\"relative block aspect-video overflow-hidden rounded-md bg-muted\">\n <RenditionImg outputs={card.cover} alt=\"\" fit=\"cover\" skeleton className={cn(\"size-full\", lock && \"blur-md\")} />\n <Decorations card={card} decorate={decorate} />\n {lock && (\n <span className=\"absolute inset-0 grid place-items-center\">\n <span className=\"inline-flex items-center gap-1 rounded-md bg-background/85 px-2 py-1 text-xs font-medium shadow-sm\" data-ckui=\"card-lock\">\n <HugeiconsIcon icon={LockIcon} strokeWidth={2} className=\"size-3.5\" aria-hidden />\n {lock}\n </span>\n </span>\n )}\n </span>\n )}\n </a>\n <p className=\"flex flex-wrap items-center gap-3 text-xs text-muted-foreground\">\n {card.published_at && <RelativeTime at={card.published_at} />}\n {!card.cover.length && lock && <span data-ckui=\"card-lock\">{lock}</span>}\n {card.counts.favorites !== undefined && (\n <span className=\"inline-flex items-center gap-1 tabular-nums\" data-ckui=\"card-counts\">\n <HugeiconsIcon icon={FavouriteIcon} strokeWidth={2} className={cn(\"size-3.5\", card.viewer?.favorited && \"fill-current text-primary\")} aria-hidden />\n <span className=\"sr-only\">{m.t(\"contents.favorites\")}</span>\n {compact(card.counts.favorites, m.language)}\n </span>\n )}\n </p>\n {children}\n </article>\n );\n}\n"],"mappings":"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"}
@@ -13,7 +13,7 @@ export interface ContentFilterSettingsProps {
13
13
  appearance?: ContentKitUiAppearance;
14
14
  }
15
15
  /** The signed-in reader's content filters: show or hide each configured group, and go back to its default. */
16
- export declare function ContentFilterSettings(p: ContentFilterSettingsProps): import('react').JSX.Element;
16
+ export declare function ContentFilterSettings(p: ContentFilterSettingsProps): import('react').JSX.Element | null;
17
17
  export interface ReleaseDateIndexProps {
18
18
  /** Which contents count: the listing's filters. */
19
19
  query?: ReleaseDatesQuery;
@@ -27,7 +27,7 @@ function v(d) {
27
27
  }));
28
28
  if (!S.filters) return S.error ? w(/* @__PURE__ */ h(o, { children: s(v, S.error) })) : w(/* @__PURE__ */ h(a, { className: "h-24 w-full" }));
29
29
  let T = S.filters;
30
- return w(/* @__PURE__ */ g(m, { children: [
30
+ return !T.filters.length && d.includeDeleted === !1 ? null : w(/* @__PURE__ */ g(m, { children: [
31
31
  T.filters.length ? /* @__PURE__ */ h("ul", {
32
32
  className: "grid divide-y divide-border rounded-lg border border-border",
33
33
  children: T.filters.map((e) => /* @__PURE__ */ g("li", {
@@ -66,10 +66,7 @@ function v(d) {
66
66
  })
67
67
  ]
68
68
  }, e.group.id))
69
- }) : /* @__PURE__ */ h("p", {
70
- className: "text-muted-foreground",
71
- children: y("contents.noFilters")
72
- }),
69
+ }) : null,
73
70
  d.includeDeleted !== !1 && /* @__PURE__ */ g("div", {
74
71
  className: "flex items-center gap-3",
75
72
  children: [/* @__PURE__ */ h(l, {