@openrails/contentkit-ui 0.83.0 → 0.86.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -7
- package/dist/client/beacons.d.ts +18 -6
- package/dist/client/beacons.js +26 -11
- package/dist/client/beacons.js.map +1 -1
- package/dist/client/client.d.ts +3 -0
- package/dist/client/client.js +29 -27
- package/dist/client/client.js.map +1 -1
- package/dist/client/codes.d.ts +6 -1
- package/dist/client/codes.js +4 -1
- package/dist/client/codes.js.map +1 -1
- package/dist/client/content/moderation.d.ts +14 -2
- package/dist/client/content/moderation.js +34 -0
- package/dist/client/content/moderation.js.map +1 -1
- package/dist/client/content/types.d.ts +13 -0
- package/dist/client/content/types.js.map +1 -1
- package/dist/client/discovery.d.ts +6 -0
- package/dist/client/discovery.js.map +1 -1
- package/dist/client/generated/error-codes.d.ts +1 -1
- package/dist/client/generated/error-codes.js +9 -1
- package/dist/client/generated/error-codes.js.map +1 -1
- package/dist/client/generated/routes.d.ts +91 -13
- package/dist/client/generated/routes.js +123 -2
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +81 -0
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/index.d.ts +4 -2
- package/dist/client/media/queue.d.ts +4 -2
- package/dist/client/media/queue.js +18 -12
- package/dist/client/media/queue.js.map +1 -1
- package/dist/client/media/rules.d.ts +7 -1
- package/dist/client/media/rules.js +27 -21
- package/dist/client/media/rules.js.map +1 -1
- package/dist/client/reader-meta.d.ts +27 -0
- package/dist/client/reader-meta.js +99 -0
- package/dist/client/reader-meta.js.map +1 -0
- package/dist/client/stats.d.ts +32 -0
- package/dist/client/stats.js +35 -0
- package/dist/client/stats.js.map +1 -0
- package/dist/client/versions.d.ts +1 -1
- package/dist/client/versions.js +7 -2
- package/dist/client/versions.js.map +1 -1
- package/dist/client.js +30 -28
- package/dist/components/admin/content-manager.js +206 -206
- package/dist/components/admin/content-manager.js.map +1 -1
- package/dist/components/admin/group-manager.js +71 -70
- package/dist/components/admin/group-manager.js.map +1 -1
- package/dist/components/admin/media-item-panel.d.ts +24 -7
- package/dist/components/admin/media-item-panel.js +209 -197
- package/dist/components/admin/media-item-panel.js.map +1 -1
- package/dist/components/admin/poll-manager.js +25 -25
- package/dist/components/admin/reader-manifest.d.ts +18 -0
- package/dist/components/admin/reader-manifest.js +490 -0
- package/dist/components/admin/reader-manifest.js.map +1 -0
- package/dist/components/admin/stats-dashboard.d.ts +22 -0
- package/dist/components/admin/stats-dashboard.js +257 -0
- package/dist/components/admin/stats-dashboard.js.map +1 -0
- package/dist/components/content/card.js +43 -43
- package/dist/components/content/card.js.map +1 -1
- package/dist/components/content/editors.d.ts +2 -1
- package/dist/components/content/editors.js +479 -416
- package/dist/components/content/editors.js.map +1 -1
- package/dist/components/content/grid.js +47 -47
- package/dist/components/content/index.d.ts +2 -1
- package/dist/components/content/listing.js +34 -34
- package/dist/components/content/listing.js.map +1 -1
- package/dist/components/content/paywall.d.ts +17 -5
- package/dist/components/content/paywall.js +115 -100
- package/dist/components/content/paywall.js.map +1 -1
- package/dist/components/content/reader-stats.d.ts +12 -0
- package/dist/components/content/reader-stats.js +47 -0
- package/dist/components/content/reader-stats.js.map +1 -0
- package/dist/components/groups/banner.d.ts +1 -1
- package/dist/components/groups/banner.js +34 -34
- package/dist/components/groups/banner.js.map +1 -1
- package/dist/components/groups/directory.js +11 -11
- package/dist/components/groups/editor.js +294 -294
- package/dist/components/groups/editor.js.map +1 -1
- package/dist/components/groups/header.js +27 -27
- package/dist/components/groups/header.js.map +1 -1
- package/dist/components/groups/memberships.js +180 -180
- package/dist/components/groups/parts.d.ts +2 -4
- package/dist/components/groups/parts.js +69 -88
- package/dist/components/groups/parts.js.map +1 -1
- package/dist/components/media-folder-editor.js +239 -189
- package/dist/components/media-folder-editor.js.map +1 -1
- package/dist/components/notifications.js +17 -17
- package/dist/components/slot-upload.d.ts +2 -2
- package/dist/components/slot-upload.js +84 -79
- package/dist/components/slot-upload.js.map +1 -1
- package/dist/components/social/bans.js +34 -34
- package/dist/components/social/comments.js +59 -45
- package/dist/components/social/comments.js.map +1 -1
- package/dist/components/social/index.d.ts +1 -0
- package/dist/components/social/moderation.d.ts +5 -4
- package/dist/components/social/moderation.js +177 -160
- package/dist/components/social/moderation.js.map +1 -1
- package/dist/components/social/parts.js +22 -14
- package/dist/components/social/parts.js.map +1 -1
- package/dist/components/social/rules.d.ts +23 -0
- package/dist/components/social/rules.js +261 -0
- package/dist/components/social/rules.js.map +1 -0
- package/dist/components/video-player.d.ts +2 -0
- package/dist/components/video-player.js +318 -314
- package/dist/components/video-player.js.map +1 -1
- package/dist/i18n/context.d.ts +2 -0
- package/dist/i18n/context.js +23 -5
- package/dist/i18n/context.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +28 -24
- package/dist/locales/admin/de.js +105 -0
- package/dist/locales/admin/de.js.map +1 -1
- package/dist/locales/admin/en.d.ts +105 -0
- package/dist/locales/admin/en.js +105 -0
- package/dist/locales/admin/en.js.map +1 -1
- package/dist/locales/admin/es.js +105 -0
- package/dist/locales/admin/es.js.map +1 -1
- package/dist/locales/admin/ja.js +105 -0
- package/dist/locales/admin/ja.js.map +1 -1
- package/dist/locales/admin/ko.js +105 -0
- package/dist/locales/admin/ko.js.map +1 -1
- package/dist/locales/admin/zh.js +105 -0
- package/dist/locales/admin/zh.js.map +1 -1
- package/dist/locales/content/de.js +6 -0
- package/dist/locales/content/de.js.map +1 -1
- package/dist/locales/content/en.d.ts +6 -0
- package/dist/locales/content/en.js +6 -0
- package/dist/locales/content/en.js.map +1 -1
- package/dist/locales/content/es.js +6 -0
- package/dist/locales/content/es.js.map +1 -1
- package/dist/locales/content/ja.js +6 -0
- package/dist/locales/content/ja.js.map +1 -1
- package/dist/locales/content/ko.js +6 -0
- package/dist/locales/content/ko.js.map +1 -1
- package/dist/locales/content/zh.js +6 -0
- package/dist/locales/content/zh.js.map +1 -1
- package/dist/locales/de.js +4 -1
- package/dist/locales/de.js.map +1 -1
- package/dist/locales/discovery/de.js +1 -0
- package/dist/locales/discovery/de.js.map +1 -1
- package/dist/locales/discovery/en.d.ts +1 -0
- package/dist/locales/discovery/en.js +1 -0
- package/dist/locales/discovery/en.js.map +1 -1
- package/dist/locales/discovery/es.js +1 -0
- package/dist/locales/discovery/es.js.map +1 -1
- package/dist/locales/discovery/ja.js +1 -0
- package/dist/locales/discovery/ja.js.map +1 -1
- package/dist/locales/discovery/ko.js +1 -0
- package/dist/locales/discovery/ko.js.map +1 -1
- package/dist/locales/discovery/zh.js +1 -0
- package/dist/locales/discovery/zh.js.map +1 -1
- package/dist/locales/en.d.ts +118 -0
- package/dist/locales/en.js +4 -1
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +4 -1
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/ja.js +4 -1
- package/dist/locales/ja.js.map +1 -1
- package/dist/locales/ko.js +4 -1
- package/dist/locales/ko.js.map +1 -1
- package/dist/locales/social/de.js +3 -0
- package/dist/locales/social/de.js.map +1 -1
- package/dist/locales/social/en.d.ts +3 -0
- package/dist/locales/social/en.js +3 -0
- package/dist/locales/social/en.js.map +1 -1
- package/dist/locales/social/es.js +3 -0
- package/dist/locales/social/es.js.map +1 -1
- package/dist/locales/social/ja.js +3 -0
- package/dist/locales/social/ja.js.map +1 -1
- package/dist/locales/social/ko.js +3 -0
- package/dist/locales/social/ko.js.map +1 -1
- package/dist/locales/social/zh.js +3 -0
- package/dist/locales/social/zh.js.map +1 -1
- package/dist/locales/zh.js +4 -1
- package/dist/locales/zh.js.map +1 -1
- package/dist/react/admin.d.ts +1 -1
- package/dist/react/admin.js +24 -23
- package/dist/react/admin.js.map +1 -1
- package/dist/react/canonical.d.ts +4 -3
- package/dist/react/canonical.js +34 -33
- package/dist/react/canonical.js.map +1 -1
- package/dist/react/comments.d.ts +29 -1
- package/dist/react/comments.js +30 -2
- package/dist/react/comments.js.map +1 -1
- package/dist/react/contents.js +144 -144
- package/dist/react/contents.js.map +1 -1
- package/dist/react/context.d.ts +1 -1
- package/dist/react/context.js.map +1 -1
- package/dist/react/detail.d.ts +12 -6
- package/dist/react/detail.js +31 -24
- package/dist/react/detail.js.map +1 -1
- package/dist/react/discovery.js +1 -1
- package/dist/react/discovery.js.map +1 -1
- package/dist/react/folder.d.ts +7 -2
- package/dist/react/folder.js +165 -147
- package/dist/react/folder.js.map +1 -1
- package/dist/react/groups.d.ts +0 -1
- package/dist/react/groups.js +13 -12
- package/dist/react/groups.js.map +1 -1
- package/dist/react/index.d.ts +5 -3
- package/dist/react/location.d.ts +11 -0
- package/dist/react/location.js +18 -0
- package/dist/react/location.js.map +1 -0
- package/dist/react/public.d.ts +8 -0
- package/dist/react/public.js +32 -27
- package/dist/react/public.js.map +1 -1
- package/dist/react/resources.js +6 -0
- package/dist/react/resources.js.map +1 -1
- package/dist/react/stats.d.ts +24 -0
- package/dist/react/stats.js +28 -0
- package/dist/react/stats.js.map +1 -0
- package/dist/react/use-resource.js +8 -7
- package/dist/react/use-resource.js.map +1 -1
- package/dist/react/versions.js +20 -20
- package/dist/react.js +26 -24
- package/dist/styles.css +1 -1
- package/dist/urls/index.d.ts +35 -10
- package/dist/urls.js +100 -70
- package/dist/urls.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { useMessages as e } from "../../i18n/context.js";
|
|
2
|
+
import { Select as t, SelectContent as n, SelectItem as r, SelectTrigger as i, SelectValue as a } from "../../ui/select.js";
|
|
3
|
+
import { AdminRoot as o, LoadFailed as s, NoAccess as c, Rows as l } from "./shell.js";
|
|
4
|
+
import { useFlowClient as u } from "../../react/admin.js";
|
|
5
|
+
import { useActivity as d, useTopContents as f } from "../../react/stats.js";
|
|
6
|
+
import { useState as p } from "react";
|
|
7
|
+
import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
8
|
+
//#region src/components/admin/stats-dashboard.tsx
|
|
9
|
+
var _ = (e) => e.map((e) => typeof e == "string" ? {
|
|
10
|
+
value: e,
|
|
11
|
+
label: e
|
|
12
|
+
} : e), v = [
|
|
13
|
+
7,
|
|
14
|
+
30,
|
|
15
|
+
90
|
|
16
|
+
], y = ["views", "comments"], b = [
|
|
17
|
+
"7d",
|
|
18
|
+
"30d",
|
|
19
|
+
"90d",
|
|
20
|
+
"365d",
|
|
21
|
+
"all"
|
|
22
|
+
], x = (e) => e?.code === "forbidden" || e?.code === "unauthorized";
|
|
23
|
+
function S({ client: e, baseUrl: t, auth: n, guard: r, appearance: i, className: a, language: s, messages: c, ...l }) {
|
|
24
|
+
let d = u({
|
|
25
|
+
client: e,
|
|
26
|
+
baseUrl: t,
|
|
27
|
+
auth: n
|
|
28
|
+
});
|
|
29
|
+
return /* @__PURE__ */ h(o, {
|
|
30
|
+
flow: "stats-dashboard",
|
|
31
|
+
appearance: i,
|
|
32
|
+
className: a,
|
|
33
|
+
language: s,
|
|
34
|
+
messages: c,
|
|
35
|
+
guard: r,
|
|
36
|
+
children: /* @__PURE__ */ h(C, {
|
|
37
|
+
...l,
|
|
38
|
+
client: d
|
|
39
|
+
})
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function C({ kinds: t, contentHref: n, limit: r = 10, client: i }) {
|
|
43
|
+
let { t: a } = e(), o = _(t), [u, S] = p(o[0]?.value ?? ""), [C, T] = p(7), [E, D] = p("views"), [O, k] = p("30d"), A = d(u ? {
|
|
44
|
+
kind: u,
|
|
45
|
+
days: C
|
|
46
|
+
} : null, { client: i }), j = f(u ? {
|
|
47
|
+
kind: u,
|
|
48
|
+
metric: E,
|
|
49
|
+
period: O,
|
|
50
|
+
limit: r
|
|
51
|
+
} : null, { client: i });
|
|
52
|
+
if (x(A.error) || x(j.error)) return /* @__PURE__ */ h(c, { children: a("stats.noAccess") });
|
|
53
|
+
let M = A.data?.days ?? [], N = Math.max(1, ...M.map((e) => e.views)), P = M.reduce((e, t) => e + t.views, 0);
|
|
54
|
+
return /* @__PURE__ */ g(m, { children: [
|
|
55
|
+
/* @__PURE__ */ g("div", {
|
|
56
|
+
className: "flex flex-wrap items-center justify-between gap-2",
|
|
57
|
+
children: [/* @__PURE__ */ h("h2", {
|
|
58
|
+
className: "text-base font-semibold",
|
|
59
|
+
children: a("stats.title")
|
|
60
|
+
}), o.length > 1 && /* @__PURE__ */ h(w, {
|
|
61
|
+
label: a("stats.kind"),
|
|
62
|
+
value: u,
|
|
63
|
+
onChange: S,
|
|
64
|
+
options: o
|
|
65
|
+
})]
|
|
66
|
+
}),
|
|
67
|
+
/* @__PURE__ */ g("section", {
|
|
68
|
+
className: "grid gap-3",
|
|
69
|
+
"data-ckui": "stats-activity",
|
|
70
|
+
children: [/* @__PURE__ */ g("div", {
|
|
71
|
+
className: "flex flex-wrap items-center justify-between gap-2",
|
|
72
|
+
children: [/* @__PURE__ */ h("h3", {
|
|
73
|
+
className: "font-medium",
|
|
74
|
+
children: a("stats.activity")
|
|
75
|
+
}), /* @__PURE__ */ h(w, {
|
|
76
|
+
label: a("stats.days"),
|
|
77
|
+
value: String(C),
|
|
78
|
+
onChange: (e) => T(Number(e)),
|
|
79
|
+
options: v.map((e) => ({
|
|
80
|
+
value: String(e),
|
|
81
|
+
label: a("stats.lastDays", { count: e })
|
|
82
|
+
}))
|
|
83
|
+
})]
|
|
84
|
+
}), A.unavailable ? /* @__PURE__ */ h("p", {
|
|
85
|
+
className: "text-muted-foreground",
|
|
86
|
+
role: "status",
|
|
87
|
+
children: a("stats.unavailable")
|
|
88
|
+
}) : A.error ? /* @__PURE__ */ h(s, {
|
|
89
|
+
error: A.error,
|
|
90
|
+
message: a("stats.loadFailed"),
|
|
91
|
+
retry: A.reload
|
|
92
|
+
}) : A.loading && !A.data ? /* @__PURE__ */ h(l, { count: 2 }) : M.length ? /* @__PURE__ */ g("table", {
|
|
93
|
+
className: "w-full text-left tabular-nums",
|
|
94
|
+
"aria-busy": A.loading,
|
|
95
|
+
children: [
|
|
96
|
+
/* @__PURE__ */ h("thead", {
|
|
97
|
+
className: "text-xs text-muted-foreground",
|
|
98
|
+
children: /* @__PURE__ */ g("tr", { children: [
|
|
99
|
+
/* @__PURE__ */ h("th", {
|
|
100
|
+
className: "py-1 font-medium",
|
|
101
|
+
children: a("stats.date")
|
|
102
|
+
}),
|
|
103
|
+
/* @__PURE__ */ h("th", {
|
|
104
|
+
className: "py-1 font-medium",
|
|
105
|
+
children: a("stats.views")
|
|
106
|
+
}),
|
|
107
|
+
/* @__PURE__ */ h("th", {
|
|
108
|
+
className: "py-1 text-end font-medium",
|
|
109
|
+
children: a("stats.viewers")
|
|
110
|
+
}),
|
|
111
|
+
/* @__PURE__ */ h("th", {
|
|
112
|
+
className: "py-1 text-end font-medium",
|
|
113
|
+
children: a("stats.users")
|
|
114
|
+
})
|
|
115
|
+
] })
|
|
116
|
+
}),
|
|
117
|
+
/* @__PURE__ */ h("tbody", { children: M.map((e) => /* @__PURE__ */ g("tr", {
|
|
118
|
+
className: "border-t border-border",
|
|
119
|
+
"data-ckui": "stats-day",
|
|
120
|
+
children: [
|
|
121
|
+
/* @__PURE__ */ h("td", {
|
|
122
|
+
className: "py-1.5 pe-3 whitespace-nowrap",
|
|
123
|
+
children: e.date
|
|
124
|
+
}),
|
|
125
|
+
/* @__PURE__ */ h("td", {
|
|
126
|
+
className: "w-1/2 py-1.5 pe-3",
|
|
127
|
+
children: /* @__PURE__ */ g("span", {
|
|
128
|
+
className: "flex items-center gap-2",
|
|
129
|
+
children: [/* @__PURE__ */ h("span", {
|
|
130
|
+
"aria-hidden": !0,
|
|
131
|
+
className: "h-2 rounded-full bg-primary",
|
|
132
|
+
style: { width: `${Math.max(2, e.views / N * 100)}%` }
|
|
133
|
+
}), e.views]
|
|
134
|
+
})
|
|
135
|
+
}),
|
|
136
|
+
/* @__PURE__ */ h("td", {
|
|
137
|
+
className: "py-1.5 text-end",
|
|
138
|
+
children: e.viewers
|
|
139
|
+
}),
|
|
140
|
+
/* @__PURE__ */ h("td", {
|
|
141
|
+
className: "py-1.5 text-end",
|
|
142
|
+
children: e.users
|
|
143
|
+
})
|
|
144
|
+
]
|
|
145
|
+
}, e.date)) }),
|
|
146
|
+
/* @__PURE__ */ h("tfoot", { children: /* @__PURE__ */ g("tr", {
|
|
147
|
+
className: "border-t border-border font-medium",
|
|
148
|
+
children: [
|
|
149
|
+
/* @__PURE__ */ h("td", {
|
|
150
|
+
className: "py-1.5",
|
|
151
|
+
children: a("stats.total")
|
|
152
|
+
}),
|
|
153
|
+
/* @__PURE__ */ h("td", {
|
|
154
|
+
className: "py-1.5",
|
|
155
|
+
"data-ckui": "stats-total",
|
|
156
|
+
children: P
|
|
157
|
+
}),
|
|
158
|
+
/* @__PURE__ */ h("td", {}),
|
|
159
|
+
/* @__PURE__ */ h("td", {})
|
|
160
|
+
]
|
|
161
|
+
}) })
|
|
162
|
+
]
|
|
163
|
+
}) : /* @__PURE__ */ h("p", {
|
|
164
|
+
className: "text-muted-foreground",
|
|
165
|
+
children: a("stats.noActivity")
|
|
166
|
+
})]
|
|
167
|
+
}),
|
|
168
|
+
/* @__PURE__ */ g("section", {
|
|
169
|
+
className: "grid gap-3",
|
|
170
|
+
"data-ckui": "stats-top",
|
|
171
|
+
children: [/* @__PURE__ */ g("div", {
|
|
172
|
+
className: "flex flex-wrap items-center justify-between gap-2",
|
|
173
|
+
children: [/* @__PURE__ */ h("h3", {
|
|
174
|
+
className: "font-medium",
|
|
175
|
+
children: a("stats.top")
|
|
176
|
+
}), /* @__PURE__ */ g("div", {
|
|
177
|
+
className: "flex flex-wrap gap-2",
|
|
178
|
+
children: [/* @__PURE__ */ h(w, {
|
|
179
|
+
label: a("stats.metric"),
|
|
180
|
+
value: E,
|
|
181
|
+
onChange: (e) => D(e),
|
|
182
|
+
options: y.map((e) => ({
|
|
183
|
+
value: e,
|
|
184
|
+
label: a(`stats.metric_${e}`)
|
|
185
|
+
}))
|
|
186
|
+
}), /* @__PURE__ */ h(w, {
|
|
187
|
+
label: a("stats.period"),
|
|
188
|
+
value: O,
|
|
189
|
+
onChange: (e) => k(e),
|
|
190
|
+
options: b.map((e) => ({
|
|
191
|
+
value: e,
|
|
192
|
+
label: a(`stats.period_${e}`)
|
|
193
|
+
}))
|
|
194
|
+
})]
|
|
195
|
+
})]
|
|
196
|
+
}), j.unavailable ? /* @__PURE__ */ h("p", {
|
|
197
|
+
className: "text-muted-foreground",
|
|
198
|
+
role: "status",
|
|
199
|
+
children: a("stats.unavailable")
|
|
200
|
+
}) : j.error ? /* @__PURE__ */ h(s, {
|
|
201
|
+
error: j.error,
|
|
202
|
+
message: a("stats.loadFailed"),
|
|
203
|
+
retry: j.reload
|
|
204
|
+
}) : j.loading && !j.data ? /* @__PURE__ */ h(l, { count: 3 }) : j.data?.contents.length ? /* @__PURE__ */ h("ol", {
|
|
205
|
+
className: "grid divide-y divide-border rounded-lg border border-border",
|
|
206
|
+
"aria-busy": j.loading,
|
|
207
|
+
children: j.data.contents.map((e, t) => {
|
|
208
|
+
let r = n ? n(e) : e.path;
|
|
209
|
+
return /* @__PURE__ */ g("li", {
|
|
210
|
+
className: "flex items-center gap-3 p-2.5",
|
|
211
|
+
"data-ckui": "stats-ranked",
|
|
212
|
+
children: [
|
|
213
|
+
/* @__PURE__ */ h("span", {
|
|
214
|
+
className: "w-6 text-end text-muted-foreground tabular-nums",
|
|
215
|
+
children: t + 1
|
|
216
|
+
}),
|
|
217
|
+
r ? /* @__PURE__ */ h("a", {
|
|
218
|
+
className: "min-w-0 flex-1 break-words hover:underline",
|
|
219
|
+
href: r,
|
|
220
|
+
children: e.title
|
|
221
|
+
}) : /* @__PURE__ */ h("span", {
|
|
222
|
+
className: "min-w-0 flex-1 break-words",
|
|
223
|
+
children: e.title
|
|
224
|
+
}),
|
|
225
|
+
/* @__PURE__ */ h("span", {
|
|
226
|
+
className: "tabular-nums",
|
|
227
|
+
"data-ckui": "stats-value",
|
|
228
|
+
children: e.value
|
|
229
|
+
})
|
|
230
|
+
]
|
|
231
|
+
}, e.id);
|
|
232
|
+
})
|
|
233
|
+
}) : /* @__PURE__ */ h("p", {
|
|
234
|
+
className: "text-muted-foreground",
|
|
235
|
+
children: a("stats.noTop")
|
|
236
|
+
})]
|
|
237
|
+
})
|
|
238
|
+
] });
|
|
239
|
+
}
|
|
240
|
+
function w({ label: e, value: o, onChange: s, options: c }) {
|
|
241
|
+
return /* @__PURE__ */ g(t, {
|
|
242
|
+
value: o,
|
|
243
|
+
onValueChange: (e) => s(String(e)),
|
|
244
|
+
children: [/* @__PURE__ */ h(i, {
|
|
245
|
+
size: "sm",
|
|
246
|
+
"aria-label": e,
|
|
247
|
+
children: /* @__PURE__ */ h(a, { children: (e) => c.find((t) => t.value === e)?.label ?? e })
|
|
248
|
+
}), /* @__PURE__ */ h(n, { children: c.map((e) => /* @__PURE__ */ h(r, {
|
|
249
|
+
value: e.value,
|
|
250
|
+
children: e.label
|
|
251
|
+
}, e.value)) })]
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
//#endregion
|
|
255
|
+
export { S as StatsDashboard };
|
|
256
|
+
|
|
257
|
+
//# sourceMappingURL=stats-dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats-dashboard.js","names":[],"sources":["../../../src/components/admin/stats-dashboard.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { ContentKitError } from \"../../client/errors.js\";\nimport type { Period } from \"../../client/discovery.js\";\nimport type { RankedContent } from \"../../client/generated/wire.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { useFlowClient } from \"../../react/admin.js\";\nimport { useActivity, useTopContents } from \"../../react/stats.js\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"#ckui/ui/select\";\nimport { AdminRoot, LoadFailed, NoAccess, Rows, type AdminFlowProps } from \"./shell.js\";\n\ntype Choice = string | { value: string; label: string };\ntype Metric = \"views\" | \"comments\";\n\nexport interface StatsDashboardProps extends AdminFlowProps {\n /** Content kinds offered: codes, or codes with labels; the first shows first. */\n kinds: readonly Choice[];\n /** A ranked item's link; default its path. */\n contentHref?: (content: RankedContent) => string | undefined;\n /** Rows in the ranking. Default 10. */\n limit?: number;\n}\n\nconst choices = (list: readonly Choice[]) => list.map((c) => (typeof c === \"string\" ? { value: c, label: c } : c));\nconst DAYS = [7, 30, 90] as const;\nconst METRICS: readonly Metric[] = [\"views\", \"comments\"];\nconst PERIODS: readonly Period[] = [\"7d\", \"30d\", \"90d\", \"365d\", \"all\"];\nconst refused = (e?: ContentKitError) => e?.code === \"forbidden\" || e?.code === \"unauthorized\";\n\n/**\n * Content statistics for staff (root:content:view-restricted): a kind's views\n * per day (view sessions, distinct and signed-in viewers) and its content\n * ranked by views or comments over a period. Views need the signal plane;\n * without it the dashboard says so and still ranks by comments.\n */\nexport function StatsDashboard({ client: own, baseUrl, auth, guard, appearance, className, language, messages, ...p }: StatsDashboardProps) {\n const client = useFlowClient({ client: own, baseUrl, auth });\n return (\n <AdminRoot flow=\"stats-dashboard\" appearance={appearance} className={className} language={language} messages={messages} guard={guard}>\n <Dashboard {...p} client={client} />\n </AdminRoot>\n );\n}\n\ntype Inner = Omit<StatsDashboardProps, \"client\" | \"baseUrl\" | \"auth\" | \"guard\" | \"appearance\" | \"className\" | \"language\" | \"messages\"> & { client: ContentKitClient };\n\nfunction Dashboard({ kinds, contentHref, limit = 10, client }: Inner) {\n const { t } = useMessages();\n const options = choices(kinds);\n const [kind, setKind] = useState(options[0]?.value ?? \"\");\n const [days, setDays] = useState<number>(7);\n const [metric, setMetric] = useState<Metric>(\"views\");\n const [period, setPeriod] = useState<Period>(\"30d\");\n const activity = useActivity(kind ? { kind, days } : null, { client });\n const top = useTopContents(kind ? { kind, metric, period, limit } : null, { client });\n if (refused(activity.error) || refused(top.error)) return <NoAccess>{t(\"stats.noAccess\")}</NoAccess>;\n const rows = activity.data?.days ?? [];\n const most = Math.max(1, ...rows.map((d) => d.views));\n const total = rows.reduce((n, d) => n + d.views, 0);\n return (\n <>\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h2 className=\"text-base font-semibold\">{t(\"stats.title\")}</h2>\n {options.length > 1 && (\n <Pick label={t(\"stats.kind\")} value={kind} onChange={setKind} options={options} />\n )}\n </div>\n\n <section className=\"grid gap-3\" data-ckui=\"stats-activity\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h3 className=\"font-medium\">{t(\"stats.activity\")}</h3>\n <Pick label={t(\"stats.days\")} value={String(days)} onChange={(v) => setDays(Number(v))} options={DAYS.map((d) => ({ value: String(d), label: t(\"stats.lastDays\", { count: d }) }))} />\n </div>\n {activity.unavailable ? (\n <p className=\"text-muted-foreground\" role=\"status\">\n {t(\"stats.unavailable\")}\n </p>\n ) : activity.error ? (\n <LoadFailed error={activity.error} message={t(\"stats.loadFailed\")} retry={activity.reload} />\n ) : activity.loading && !activity.data ? (\n <Rows count={2} />\n ) : !rows.length ? (\n <p className=\"text-muted-foreground\">{t(\"stats.noActivity\")}</p>\n ) : (\n <table className=\"w-full text-left tabular-nums\" aria-busy={activity.loading}>\n <thead className=\"text-xs text-muted-foreground\">\n <tr>\n <th className=\"py-1 font-medium\">{t(\"stats.date\")}</th>\n <th className=\"py-1 font-medium\">{t(\"stats.views\")}</th>\n <th className=\"py-1 text-end font-medium\">{t(\"stats.viewers\")}</th>\n <th className=\"py-1 text-end font-medium\">{t(\"stats.users\")}</th>\n </tr>\n </thead>\n <tbody>\n {rows.map((d) => (\n <tr key={d.date} className=\"border-t border-border\" data-ckui=\"stats-day\">\n <td className=\"py-1.5 pe-3 whitespace-nowrap\">{d.date}</td>\n <td className=\"w-1/2 py-1.5 pe-3\">\n <span className=\"flex items-center gap-2\">\n <span aria-hidden className=\"h-2 rounded-full bg-primary\" style={{ width: `${Math.max(2, (d.views / most) * 100)}%` }} />\n {d.views}\n </span>\n </td>\n <td className=\"py-1.5 text-end\">{d.viewers}</td>\n <td className=\"py-1.5 text-end\">{d.users}</td>\n </tr>\n ))}\n </tbody>\n <tfoot>\n <tr className=\"border-t border-border font-medium\">\n <td className=\"py-1.5\">{t(\"stats.total\")}</td>\n <td className=\"py-1.5\" data-ckui=\"stats-total\">\n {total}\n </td>\n <td />\n <td />\n </tr>\n </tfoot>\n </table>\n )}\n </section>\n\n <section className=\"grid gap-3\" data-ckui=\"stats-top\">\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <h3 className=\"font-medium\">{t(\"stats.top\")}</h3>\n <div className=\"flex flex-wrap gap-2\">\n <Pick label={t(\"stats.metric\")} value={metric} onChange={(v) => setMetric(v as Metric)} options={METRICS.map((x) => ({ value: x, label: t(`stats.metric_${x}`) }))} />\n <Pick label={t(\"stats.period\")} value={period} onChange={(v) => setPeriod(v as Period)} options={PERIODS.map((x) => ({ value: x, label: t(`stats.period_${x}`) }))} />\n </div>\n </div>\n {top.unavailable ? (\n <p className=\"text-muted-foreground\" role=\"status\">\n {t(\"stats.unavailable\")}\n </p>\n ) : top.error ? (\n <LoadFailed error={top.error} message={t(\"stats.loadFailed\")} retry={top.reload} />\n ) : top.loading && !top.data ? (\n <Rows count={3} />\n ) : !top.data?.contents.length ? (\n <p className=\"text-muted-foreground\">{t(\"stats.noTop\")}</p>\n ) : (\n <ol className=\"grid divide-y divide-border rounded-lg border border-border\" aria-busy={top.loading}>\n {top.data.contents.map((c, i) => {\n const href = contentHref ? contentHref(c) : c.path;\n return (\n <li key={c.id} className=\"flex items-center gap-3 p-2.5\" data-ckui=\"stats-ranked\">\n <span className=\"w-6 text-end text-muted-foreground tabular-nums\">{i + 1}</span>\n {href ? (\n <a className=\"min-w-0 flex-1 break-words hover:underline\" href={href}>\n {c.title}\n </a>\n ) : (\n <span className=\"min-w-0 flex-1 break-words\">{c.title}</span>\n )}\n <span className=\"tabular-nums\" data-ckui=\"stats-value\">\n {c.value}\n </span>\n </li>\n );\n })}\n </ol>\n )}\n </section>\n </>\n );\n}\n\nfunction Pick({ label, value, onChange, options }: { label: string; value: string; onChange: (v: string) => void; options: { value: string; label: string }[] }) {\n return (\n <Select value={value} onValueChange={(v) => onChange(String(v))}>\n <SelectTrigger size=\"sm\" aria-label={label}>\n <SelectValue>{(v: string) => options.find((o) => o.value === v)?.label ?? v}</SelectValue>\n </SelectTrigger>\n <SelectContent>\n {options.map((o) => (\n <SelectItem key={o.value} value={o.value}>\n {o.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { RenditionImg as e } from "../rendition-img.js";
|
|
2
|
-
import {
|
|
3
|
-
import { ContentKitContext as
|
|
4
|
-
import { Badge as
|
|
5
|
-
import { RelativeTime as
|
|
6
|
-
import { GroupAvatar as
|
|
2
|
+
import { useLanguageName as t, useMessages as n } from "../../i18n/context.js";
|
|
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
7
|
import { priceLabel as u } from "./paywall.js";
|
|
8
8
|
import { useCallback as d, useContext as f } from "react";
|
|
9
9
|
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
@@ -19,33 +19,33 @@ function x(e, t, n = [], r) {
|
|
|
19
19
|
if (t.allowed) return null;
|
|
20
20
|
if (t.unknown) return e.t("contents.unknownAccess");
|
|
21
21
|
let i = t.offers?.[0];
|
|
22
|
-
if (i) return u(e, i.terms);
|
|
22
|
+
if (i) return i.target.kind === "group" && Number(i.terms.amount) === 0 ? e.t("contents.joinFree") : u(e, i.terms);
|
|
23
23
|
let a = t.sell?.find((e) => n.includes(e));
|
|
24
|
-
return a ?
|
|
24
|
+
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");
|
|
25
25
|
}
|
|
26
26
|
function S(e, t) {
|
|
27
|
-
let
|
|
28
|
-
return d((
|
|
29
|
-
t?.(), !(!
|
|
27
|
+
let n = f(r)?.navigate;
|
|
28
|
+
return d((r) => {
|
|
29
|
+
t?.(), !(!n || !e || r.defaultPrevented || r.button !== 0 || r.metaKey || r.ctrlKey || r.shiftKey || r.altKey) && (r.preventDefault(), n(e));
|
|
30
30
|
}, [
|
|
31
|
-
|
|
31
|
+
n,
|
|
32
32
|
e,
|
|
33
33
|
t
|
|
34
34
|
]);
|
|
35
35
|
}
|
|
36
|
-
function C({ card:
|
|
37
|
-
let j =
|
|
36
|
+
function C({ card: r, href: a, onOpen: s, shape: c = "portrait", groupKinds: u, chips: f = 3, tiers: C, labels: E, owner: D = !0, ownerHref: O, children: k, className: A }) {
|
|
37
|
+
let j = n(), { t: M } = j, N = t(), P = a ? a(r) : r.path, F = S(P, d(() => s?.(r), [s, r])), I = x(j, r.access, C, E), L = r.version, R = r.viewer && r.viewer.progress_max > 0 ? Math.min(1, r.viewer.progress / r.viewer.progress_max) : 0, z = u ?? Object.keys(r.groups), B = L.duration_ms ? Math.round(L.duration_ms / 6e4) : 0, V = [
|
|
38
38
|
...L.languages.map(N),
|
|
39
|
-
...L.traits.map((e) =>
|
|
39
|
+
...L.traits.map((e) => l(E, e)),
|
|
40
40
|
L.pages ? j.plural("contents.pages", L.pages) : null,
|
|
41
41
|
B ? j.plural("contents.minutes", B) : null
|
|
42
|
-
].filter(Boolean), H =
|
|
42
|
+
].filter(Boolean), H = r.title || r.code;
|
|
43
43
|
return /* @__PURE__ */ m("article", {
|
|
44
44
|
className: h("group/card grid content-start gap-2", A),
|
|
45
45
|
"data-ckui": "content-card",
|
|
46
|
-
"data-id":
|
|
46
|
+
"data-id": r.id,
|
|
47
47
|
"data-locked": I ? "" : void 0,
|
|
48
|
-
lang:
|
|
48
|
+
lang: r.language || void 0,
|
|
49
49
|
children: [/* @__PURE__ */ m("a", {
|
|
50
50
|
href: P,
|
|
51
51
|
onClick: F,
|
|
@@ -54,9 +54,9 @@ function C({ card: n, href: i, onOpen: o, shape: s = "portrait", groupKinds: u,
|
|
|
54
54
|
"aria-hidden": !0,
|
|
55
55
|
children: [
|
|
56
56
|
/* @__PURE__ */ p("div", {
|
|
57
|
-
className:
|
|
57
|
+
className: c === "landscape" ? "aspect-video" : "aspect-[3/4]",
|
|
58
58
|
children: /* @__PURE__ */ p(e, {
|
|
59
|
-
outputs:
|
|
59
|
+
outputs: r.cover,
|
|
60
60
|
alt: "",
|
|
61
61
|
fit: "cover",
|
|
62
62
|
skeleton: !0,
|
|
@@ -103,27 +103,27 @@ function C({ card: n, href: i, onOpen: o, shape: s = "portrait", groupKinds: u,
|
|
|
103
103
|
]
|
|
104
104
|
})]
|
|
105
105
|
}),
|
|
106
|
-
D &&
|
|
107
|
-
group:
|
|
106
|
+
D && r.owner && /* @__PURE__ */ p(w, {
|
|
107
|
+
group: r.owner,
|
|
108
108
|
href: O
|
|
109
109
|
}),
|
|
110
110
|
V.length > 0 && /* @__PURE__ */ p("p", {
|
|
111
111
|
className: "text-xs text-muted-foreground",
|
|
112
112
|
children: V.join(" · ")
|
|
113
113
|
}),
|
|
114
|
-
|
|
114
|
+
r.viewer?.completed && /* @__PURE__ */ p(i, {
|
|
115
115
|
variant: "secondary",
|
|
116
116
|
className: "justify-self-start",
|
|
117
117
|
children: M("contents.completed")
|
|
118
118
|
}),
|
|
119
|
-
!
|
|
119
|
+
!r.access.allowed && r.access.free_after && /* @__PURE__ */ p("p", {
|
|
120
120
|
className: "text-xs text-muted-foreground",
|
|
121
|
-
children: M("contents.freeFrom", { date:
|
|
121
|
+
children: M("contents.freeFrom", { date: o(j, r.access.free_after, !1) })
|
|
122
122
|
}),
|
|
123
|
-
z.some((e) =>
|
|
123
|
+
z.some((e) => r.groups[e]?.length) && /* @__PURE__ */ p("ul", {
|
|
124
124
|
className: "flex flex-wrap gap-1",
|
|
125
125
|
"data-ckui": "card-groups",
|
|
126
|
-
children: z.flatMap((e) => (
|
|
126
|
+
children: z.flatMap((e) => (r.groups[e] ?? []).slice(0, f).map((t) => /* @__PURE__ */ p("li", {
|
|
127
127
|
"data-kind": e,
|
|
128
128
|
children: /* @__PURE__ */ p(T, {
|
|
129
129
|
url: t.path,
|
|
@@ -141,14 +141,14 @@ function C({ card: n, href: i, onOpen: o, shape: s = "portrait", groupKinds: u,
|
|
|
141
141
|
/* @__PURE__ */ p(y, {
|
|
142
142
|
icon: g,
|
|
143
143
|
strokeWidth: 2,
|
|
144
|
-
className: h("size-3.5",
|
|
144
|
+
className: h("size-3.5", r.viewer?.favorited && "fill-current text-primary"),
|
|
145
145
|
"aria-hidden": !0
|
|
146
146
|
}),
|
|
147
147
|
/* @__PURE__ */ p("span", {
|
|
148
148
|
className: "sr-only",
|
|
149
149
|
children: M("contents.favorites")
|
|
150
150
|
}),
|
|
151
|
-
b(
|
|
151
|
+
b(r.counts.favorites, j.language)
|
|
152
152
|
]
|
|
153
153
|
}), /* @__PURE__ */ m("span", {
|
|
154
154
|
className: "inline-flex items-center gap-1",
|
|
@@ -164,7 +164,7 @@ function C({ card: n, href: i, onOpen: o, shape: s = "portrait", groupKinds: u,
|
|
|
164
164
|
className: "sr-only",
|
|
165
165
|
children: M("contents.likes")
|
|
166
166
|
}),
|
|
167
|
-
b(
|
|
167
|
+
b(r.counts.likes, j.language)
|
|
168
168
|
]
|
|
169
169
|
})]
|
|
170
170
|
}),
|
|
@@ -178,11 +178,11 @@ function w({ group: e, href: t, className: n }) {
|
|
|
178
178
|
className: h("flex min-w-0 text-xs text-muted-foreground", n),
|
|
179
179
|
"data-ckui": "card-owner",
|
|
180
180
|
"data-id": e.id,
|
|
181
|
-
children: /* @__PURE__ */ m(
|
|
181
|
+
children: /* @__PURE__ */ m(c, {
|
|
182
182
|
group: e,
|
|
183
183
|
href: t,
|
|
184
184
|
className: "inline-flex min-w-0 items-center gap-1.5 hover:text-foreground",
|
|
185
|
-
children: [/* @__PURE__ */ p(
|
|
185
|
+
children: [/* @__PURE__ */ p(s, {
|
|
186
186
|
group: e,
|
|
187
187
|
className: "size-5 shrink-0 text-[0.625rem]"
|
|
188
188
|
}), /* @__PURE__ */ p("span", {
|
|
@@ -204,17 +204,17 @@ function T({ url: e, name: t }) {
|
|
|
204
204
|
children: t
|
|
205
205
|
});
|
|
206
206
|
}
|
|
207
|
-
function E({ card:
|
|
208
|
-
let C =
|
|
207
|
+
function E({ card: t, href: r, onOpen: i, tiers: o, labels: s, byline: c, owner: l = !0, ownerHref: u, children: f, className: v }) {
|
|
208
|
+
let C = n(), T = r ? r(t) : t.path, E = S(T, d(() => i?.(t), [i, t])), D = x(C, t.access, o, s), O = t.title || t.code;
|
|
209
209
|
return /* @__PURE__ */ m("article", {
|
|
210
210
|
className: h("grid gap-3 rounded-lg border border-border p-3", v),
|
|
211
211
|
"data-ckui": "post-card",
|
|
212
|
-
"data-id":
|
|
212
|
+
"data-id": t.id,
|
|
213
213
|
"data-locked": D ? "" : void 0,
|
|
214
|
-
lang:
|
|
214
|
+
lang: t.language || void 0,
|
|
215
215
|
children: [
|
|
216
|
-
c ?? (l &&
|
|
217
|
-
group:
|
|
216
|
+
c ?? (l && t.owner && /* @__PURE__ */ p(w, {
|
|
217
|
+
group: t.owner,
|
|
218
218
|
href: u,
|
|
219
219
|
className: "text-sm"
|
|
220
220
|
})),
|
|
@@ -226,10 +226,10 @@ function E({ card: n, href: r, onOpen: a, tiers: o, labels: s, byline: c, owner:
|
|
|
226
226
|
className: "font-medium break-words hover:underline",
|
|
227
227
|
"data-ckui": "card-title",
|
|
228
228
|
children: O
|
|
229
|
-
}),
|
|
229
|
+
}), t.cover.length > 0 && /* @__PURE__ */ m("span", {
|
|
230
230
|
className: "relative block aspect-video overflow-hidden rounded-md bg-muted",
|
|
231
231
|
children: [/* @__PURE__ */ p(e, {
|
|
232
|
-
outputs:
|
|
232
|
+
outputs: t.cover,
|
|
233
233
|
alt: "",
|
|
234
234
|
fit: "cover",
|
|
235
235
|
skeleton: !0,
|
|
@@ -252,8 +252,8 @@ function E({ card: n, href: r, onOpen: a, tiers: o, labels: s, byline: c, owner:
|
|
|
252
252
|
/* @__PURE__ */ m("p", {
|
|
253
253
|
className: "flex flex-wrap items-center gap-3 text-xs text-muted-foreground",
|
|
254
254
|
children: [
|
|
255
|
-
|
|
256
|
-
!
|
|
255
|
+
t.published_at && /* @__PURE__ */ p(a, { at: t.published_at }),
|
|
256
|
+
!t.cover.length && D && /* @__PURE__ */ p("span", {
|
|
257
257
|
"data-ckui": "card-lock",
|
|
258
258
|
children: D
|
|
259
259
|
}),
|
|
@@ -263,14 +263,14 @@ function E({ card: n, href: r, onOpen: a, tiers: o, labels: s, byline: c, owner:
|
|
|
263
263
|
/* @__PURE__ */ p(y, {
|
|
264
264
|
icon: g,
|
|
265
265
|
strokeWidth: 2,
|
|
266
|
-
className: h("size-3.5",
|
|
266
|
+
className: h("size-3.5", t.viewer?.favorited && "fill-current text-primary"),
|
|
267
267
|
"aria-hidden": !0
|
|
268
268
|
}),
|
|
269
269
|
/* @__PURE__ */ p("span", {
|
|
270
270
|
className: "sr-only",
|
|
271
271
|
children: C.t("contents.favorites")
|
|
272
272
|
}),
|
|
273
|
-
b(
|
|
273
|
+
b(t.counts.favorites, C.language)
|
|
274
274
|
]
|
|
275
275
|
})
|
|
276
276
|
]
|
|
@@ -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 { 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, useLanguageName, 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 /** Below the meta line: the host's own. */\n children?: ReactNode;\n className?: string;\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 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. */\nexport function ContentCard({ card, href, onOpen, shape = \"portrait\", groupKinds, chips = 3, tiers, labels, owner = true, ownerHref, 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 <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 <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 <p className=\"flex items-center gap-3 text-xs text-muted-foreground tabular-nums\" data-ckui=\"card-counts\">\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 <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 </p>\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, 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 {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 <span className=\"inline-flex items-center gap-1 tabular-nums\">\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 </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, 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 /** Below the meta line: the host's own. */\n children?: ReactNode;\n className?: string;\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. */\nexport function ContentCard({ card, href, onOpen, shape = \"portrait\", groupKinds, chips = 3, tiers, labels, owner = true, ownerHref, 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 <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 <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 <p className=\"flex items-center gap-3 text-xs text-muted-foreground tabular-nums\" data-ckui=\"card-counts\">\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 <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 </p>\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, 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 {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 <span className=\"inline-flex items-center gap-1 tabular-nums\">\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 </p>\n {children}\n </article>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAuCA,IAAM,KAAW,GAAW,MAAsB,IAAI,KAAK,aAAa,GAAU;CAAE,UAAU;CAAW,uBAAuB;AAAE,CAAC,CAAC,CAAC,OAAO,CAAC;AAG7I,SAAgB,EAAU,GAAe,GAAe,IAA2B,CAAC,GAAG,GAAgC;CACrH,IAAI,EAAE,SAAS,OAAO;CACtB,IAAI,EAAE,SAAS,OAAO,EAAE,EAAE,wBAAwB;CAClD,IAAM,IAAQ,EAAE,SAAS;CACzB,IAAI,GAAO,OAAO,EAAM,OAAO,SAAS,WAAW,OAAO,EAAM,MAAM,MAAM,MAAM,IAAI,EAAE,EAAE,mBAAmB,IAAI,EAAW,GAAG,EAAM,KAAK;CAC1I,IAAM,IAAO,EAAE,MAAM,MAAM,MAAM,EAAM,SAAS,CAAC,CAAC;CAIlD,OAHI,IAAa,EAAQ,GAAQ,CAAI,IACjC,EAAE,MAAM,MAAM,MAAM,EAAE,SAAS,SAAS,CAAC,IAAU,EAAE,EAAE,kBAAkB,IACzE,EAAE,MAAM,SAAe,EAAE,EAAE,kBAAkB,IAC1C,EAAE,EAAE,iBAAiB;AAC9B;AAGA,SAAS,EAAQ,GAAyB,GAAqB;CAC7D,IAAM,IAAW,EAAW,CAAiB,CAAC,EAAE;CAChD,OAAO,GACJ,MAAqC;EACpC,IAAS,GACL,GAAC,KAAY,CAAC,KAAO,EAAE,oBAAoB,EAAE,WAAW,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAC3G,EAAE,eAAe,GACjB,EAAS,CAAG;CACd,GACA;EAAC;EAAU;EAAK;CAAM,CACxB;AACF;AAGA,SAAgB,EAAY,EAAE,SAAM,SAAM,WAAQ,WAAQ,YAAY,eAAY,WAAQ,GAAG,UAAO,WAAQ,WAAQ,IAAM,cAAW,aAAU,gBAA+B;CAC5K,IAAM,IAAI,EAAY,GAChB,EAAE,SAAM,GACR,IAAe,EAAgB,GAC/B,IAAM,IAAO,EAAK,CAAI,IAAI,EAAK,MAE/B,IAAU,EAAQ,GADX,QAAkB,IAAS,CAAI,GAAG,CAAC,GAAQ,CAAI,CAC/B,CAAI,GAC3B,IAAO,EAAU,GAAG,EAAK,QAAQ,GAAO,CAAM,GAC9C,IAAI,EAAK,SACT,IAAW,EAAK,UAAU,EAAK,OAAO,eAAe,IAAI,KAAK,IAAI,GAAG,EAAK,OAAO,WAAW,EAAK,OAAO,YAAY,IAAI,GACxH,IAAQ,KAAc,OAAO,KAAK,EAAK,MAAM,GAC7C,IAAU,EAAE,cAAc,KAAK,MAAM,EAAE,cAAc,GAAM,IAAI,GAC/D,IAAO;EACX,GAAG,EAAE,UAAU,IAAI,CAAY;EAC/B,GAAG,EAAE,OAAO,KAAK,MAAM,EAAQ,GAAQ,CAAC,CAAC;EACzC,EAAE,QAAQ,EAAE,OAAO,kBAAkB,EAAE,KAAK,IAAI;EAChD,IAAU,EAAE,OAAO,oBAAoB,CAAO,IAAI;CACpD,CAAC,CAAC,OAAO,OAAO,GACV,IAAQ,EAAK,SAAS,EAAK;CACjC,OACE,kBAAC,WAAD;EAAS,WAAW,EAAG,uCAAuC,CAAS;EAAG,aAAU;EAAe,WAAS,EAAK;EAAI,eAAa,IAAO,KAAK,KAAA;EAAW,MAAM,EAAK,YAAY,KAAA;EAAhL,UAAA,CACE,kBAAC,KAAD;GAAG,MAAM;GAAc;GAAS,WAAU;GAAqD,UAAU;GAAI,eAAA;GAA7G,UAAA;IACE,kBAAC,OAAD;KAAK,WAAW,MAAU,cAAc,iBAAiB;KACvD,UAAA,kBAAC,GAAD;MACE,SAAS,EAAK;MACd,KAAI;MACJ,KAAI;MACJ,UAAA;MACA,WAAU;MACV,UAAU,kBAAC,QAAD;OAAM,WAAU;OAAkF,UAAA,EAAM,OAAO,CAAC,CAAC,CAAC,YAAY;MAAQ,CAAA;KACjJ,CAAA;IACE,CAAA;IACJ,KACC,kBAAC,QAAD;KAAM,WAAU;KAA+I,aAAU;KAAzK,UAAA,CACE,kBAAC,GAAD;MAAe,MAAM;MAAU,aAAa;MAAG,WAAU;MAAW,eAAA;KAAa,CAAA,GAChF,CACG;;IAEP,IAAW,KACV,kBAAC,QAAD;KAAM,WAAU;KAAmD,aAAU;KAC3E,UAAA,kBAAC,QAAD;MAAM,WAAU;MAA0B,OAAO,EAAE,OAAO,GAAG,KAAK,MAAM,IAAW,GAAG,EAAE,GAAG;KAAI,CAAA;IAC3F,CAAA;GAEP;EACH,CAAA,GAAA,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACE,kBAAC,KAAD;KAAG,MAAM;KAAc;KAAS,WAAU;KAAuD,aAAU;KAA3G,UAAA,CACG,GACA,KAAQ,kBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA;OAA0B;OAAG;OAAK;MAAO;KACjD,CAAA,CAAA;;IACF,KAAS,EAAK,SAAS,kBAAC,GAAD;KAAW,OAAO,EAAK;KAAO,MAAM;IAAY,CAAA;IACvE,EAAK,SAAS,KAAK,kBAAC,KAAD;KAAG,WAAU;KAAiC,UAAA,EAAK,KAAK,KAAK;IAAK,CAAA;IACrF,EAAK,QAAQ,aACZ,kBAAC,GAAD;KAAO,SAAQ;KAAY,WAAU;KAClC,UAAA,EAAE,oBAAoB;IAClB,CAAA;IAER,CAAC,EAAK,OAAO,WAAW,EAAK,OAAO,cAAc,kBAAC,KAAD;KAAG,WAAU;KAAiC,UAAA,EAAE,qBAAqB,EAAE,MAAM,EAAW,GAAG,EAAK,OAAO,YAAY,EAAK,EAAE,CAAC;IAAK,CAAA;IAClL,EAAM,MAAM,MAAM,EAAK,OAAO,EAAE,EAAE,MAAM,KACvC,kBAAC,MAAD;KAAI,WAAU;KAAuB,aAAU;KAC5C,UAAA,EAAM,SAAS,OACb,EAAK,OAAO,MAAM,CAAC,EAAA,CAAG,MAAM,GAAG,CAAK,CAAC,CAAC,KAAK,MAC1C,kBAAC,MAAD;MAAyB,aAAW;MAClC,UAAA,kBAAC,GAAD;OAAM,KAAK,EAAE;OAAM,MAAM,EAAE,QAAQ,EAAE;MAAO,CAAA;KAC1C,GAFK,GAAG,EAAE,GAAG,EAAE,IAEf,CACL,CACH;IACE,CAAA;IAEN,kBAAC,KAAD;KAAG,WAAU;KAAqE,aAAU;KAA5F,UAAA,CACE,kBAAC,QAAD;MAAM,WAAU;MAAiC,OAAO,EAAE,oBAAoB;MAA9E,UAAA;OACE,kBAAC,GAAD;QAAe,MAAM;QAAe,aAAa;QAAG,WAAW,EAAG,YAAY,EAAK,QAAQ,aAAa,2BAA2B;QAAG,eAAA;OAAa,CAAA;OACnJ,kBAAC,QAAD;QAAM,WAAU;QAAW,UAAA,EAAE,oBAAoB;OAAQ,CAAA;OACxD,EAAQ,EAAK,OAAO,WAAW,EAAE,QAAQ;MACtC;KACN,CAAA,GAAA,kBAAC,QAAD;MAAM,WAAU;MAAiC,OAAO,EAAE,gBAAgB;MAA1E,UAAA;OACE,kBAAC,GAAD;QAAe,MAAM;QAAc,aAAa;QAAG,WAAU;QAAW,eAAA;OAAa,CAAA;OACrF,kBAAC,QAAD;QAAM,WAAU;QAAW,UAAA,EAAE,gBAAgB;OAAQ,CAAA;OACpD,EAAQ,EAAK,OAAO,OAAO,EAAE,QAAQ;MAClC;KACL,CAAA,CAAA;;IACF;GACE;EACE,CAAA,CAAA;;AAEb;AAGA,SAAgB,EAAU,EAAE,UAAO,SAAM,gBAAoG;CAC3I,OACE,kBAAC,QAAD;EAAM,WAAW,EAAG,8CAA8C,CAAS;EAAG,aAAU;EAAa,WAAS,EAAM;EAClH,UAAA,kBAAC,GAAD;GAAkB;GAAa;GAAM,WAAU;GAA/C,UAAA,CACE,kBAAC,GAAD;IAAoB;IAAO,WAAU;GAAmC,CAAA,GACxE,kBAAC,QAAD;IAAM,WAAU;IAAY,UAAA,EAAM,QAAQ,EAAM;GAAW,CAAA,CAClD;;CACP,CAAA;AAEV;AAEA,SAAS,EAAK,EAAE,QAAK,WAAwC;CAC3D,IAAM,IAAU,EAAQ,CAAG,GACrB,IAAM;CACZ,OAAO,IACL,kBAAC,KAAD;EAAG,MAAM;EAAc;EAAS,WAAW,EAAG,GAAK,sCAAsC;EACtF,UAAA;CACA,CAAA,IAEH,kBAAC,QAAD;EAAM,WAAW;EAAM,UAAA;CAAW,CAAA;AAEtC;AAQA,SAAgB,EAAS,EAAE,SAAM,SAAM,WAAQ,UAAO,WAAQ,WAAQ,WAAQ,IAAM,cAAW,aAAU,gBAA4B;CACnI,IAAM,IAAI,EAAY,GAChB,IAAM,IAAO,EAAK,CAAI,IAAI,EAAK,MAE/B,IAAU,EAAQ,GADX,QAAkB,IAAS,CAAI,GAAG,CAAC,GAAQ,CAAI,CAC/B,CAAI,GAC3B,IAAO,EAAU,GAAG,EAAK,QAAQ,GAAO,CAAM,GAC9C,IAAQ,EAAK,SAAS,EAAK;CACjC,OACE,kBAAC,WAAD;EAAS,WAAW,EAAG,kDAAkD,CAAS;EAAG,aAAU;EAAY,WAAS,EAAK;EAAI,eAAa,IAAO,KAAK,KAAA;EAAW,MAAM,EAAK,YAAY,KAAA;EAAxL,UAAA;GACG,MAAW,KAAS,EAAK,SAAS,kBAAC,GAAD;IAAW,OAAO,EAAK;IAAO,MAAM;IAAW,WAAU;GAAW,CAAA;GACvG,kBAAC,KAAD;IAAG,MAAM;IAAc;IAAS,WAAU;IAA1C,UAAA,CACE,kBAAC,QAAD;KAAM,WAAU;KAA0C,aAAU;KACjE,UAAA;IACG,CAAA,GACL,EAAK,MAAM,SAAS,KACnB,kBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CACE,kBAAC,GAAD;MAAc,SAAS,EAAK;MAAO,KAAI;MAAG,KAAI;MAAQ,UAAA;MAAS,WAAW,EAAG,aAAa,KAAQ,SAAS;KAAI,CAAA,GAC9G,KACC,kBAAC,QAAD;MAAM,WAAU;MACd,UAAA,kBAAC,QAAD;OAAM,WAAU;OAAqG,aAAU;OAA/H,UAAA,CACE,kBAAC,GAAD;QAAe,MAAM;QAAU,aAAa;QAAG,WAAU;QAAW,eAAA;OAAa,CAAA,GAChF,CACG;;KACF,CAAA,CAEJ;IAEP,CAAA,CAAA;;GACH,kBAAC,KAAD;IAAG,WAAU;IAAb,UAAA;KACG,EAAK,gBAAgB,kBAAC,GAAD,EAAc,IAAI,EAAK,aAAe,CAAA;KAC3D,CAAC,EAAK,MAAM,UAAU,KAAQ,kBAAC,QAAD;MAAM,aAAU;MAAa,UAAA;KAAW,CAAA;KACvE,kBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA;OACE,kBAAC,GAAD;QAAe,MAAM;QAAe,aAAa;QAAG,WAAW,EAAG,YAAY,EAAK,QAAQ,aAAa,2BAA2B;QAAG,eAAA;OAAa,CAAA;OACnJ,kBAAC,QAAD;QAAM,WAAU;QAAW,UAAA,EAAE,EAAE,oBAAoB;OAAQ,CAAA;OAC1D,EAAQ,EAAK,OAAO,WAAW,EAAE,QAAQ;MACtC;;IACL;;GACF;EACM;;AAEb"}
|
|
@@ -20,7 +20,8 @@ export declare function versionLabel(v: Version, languageName: (l: string) => st
|
|
|
20
20
|
/**
|
|
21
21
|
* A content's versions: order, languages, traits, label, state and
|
|
22
22
|
* schedule, an access override and its own offer, segments (chapters) and
|
|
23
|
-
* the version's media folder; add and delete.
|
|
23
|
+
* the version's media folder; add and delete. A kind whose one version is
|
|
24
|
+
* hidden shows only that version's segments and media.
|
|
24
25
|
*/
|
|
25
26
|
export declare function VersionsEditor({ content, media, ...p }: Common & {
|
|
26
27
|
content: Content;
|