@openrails/contentkit-ui 0.104.0-rc.1 → 0.104.0-rc.3
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 +6 -6
- package/dist/client/beacons.js +4 -1
- package/dist/client/beacons.js.map +1 -1
- package/dist/client/contents.d.ts +9 -1
- package/dist/client/contents.js +73 -55
- package/dist/client/contents.js.map +1 -1
- package/dist/client/discovery.d.ts +6 -2
- package/dist/client/discovery.js +1 -1
- 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 +4 -0
- package/dist/client/generated/error-codes.js.map +1 -1
- package/dist/client/generated/routes.d.ts +43 -30
- package/dist/client/generated/routes.js +70 -63
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +36 -74
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/media/windows.d.ts +2 -0
- package/dist/client/media/windows.js +4 -1
- package/dist/client/media/windows.js.map +1 -1
- package/dist/client/stats.d.ts +4 -20
- package/dist/client/stats.js +0 -11
- package/dist/client/stats.js.map +1 -1
- package/dist/client/versions.d.ts +8 -6
- package/dist/client/versions.js +15 -10
- package/dist/client/versions.js.map +1 -1
- package/dist/components/admin/bulk-drafts.d.ts +17 -0
- package/dist/components/admin/bulk-drafts.js +41 -0
- package/dist/components/admin/bulk-drafts.js.map +1 -0
- package/dist/components/admin/content-admin.d.ts +1 -1
- package/dist/components/admin/content-admin.js.map +1 -1
- package/dist/components/admin/content-manager.d.ts +11 -3
- package/dist/components/admin/content-manager.js +739 -380
- package/dist/components/admin/content-manager.js.map +1 -1
- package/dist/components/admin/group-manager.d.ts +8 -3
- package/dist/components/admin/group-manager.js +218 -146
- package/dist/components/admin/group-manager.js.map +1 -1
- package/dist/components/admin/page-notices.d.ts +16 -0
- package/dist/components/admin/page-notices.js +113 -0
- package/dist/components/admin/page-notices.js.map +1 -0
- package/dist/components/admin/page-picker.d.ts +38 -0
- package/dist/components/admin/page-picker.js +159 -0
- package/dist/components/admin/page-picker.js.map +1 -0
- package/dist/components/admin/reader-content-editor.js +537 -500
- package/dist/components/admin/reader-content-editor.js.map +1 -1
- package/dist/components/admin/reader-manifest.js +181 -179
- package/dist/components/admin/reader-manifest.js.map +1 -1
- package/dist/components/admin/shell.d.ts +10 -2
- package/dist/components/admin/shell.js +114 -42
- package/dist/components/admin/shell.js.map +1 -1
- package/dist/components/admin/stats-dashboard.d.ts +4 -9
- package/dist/components/admin/stats-dashboard.js +300 -202
- package/dist/components/admin/stats-dashboard.js.map +1 -1
- package/dist/components/admin/upload-queue.d.ts +14 -0
- package/dist/components/admin/upload-queue.js +115 -98
- package/dist/components/admin/upload-queue.js.map +1 -1
- package/dist/components/content/card.d.ts +31 -3
- package/dist/components/content/card.js +324 -158
- package/dist/components/content/card.js.map +1 -1
- package/dist/components/content/daily-releases.js +14 -12
- package/dist/components/content/daily-releases.js.map +1 -1
- package/dist/components/content/editor-save.js +27 -25
- package/dist/components/content/editor-save.js.map +1 -1
- package/dist/components/content/editors.js +274 -253
- package/dist/components/content/editors.js.map +1 -1
- package/dist/components/content/favorites.d.ts +1 -1
- package/dist/components/content/favorites.js +36 -22
- package/dist/components/content/favorites.js.map +1 -1
- package/dist/components/content/grid.d.ts +11 -4
- package/dist/components/content/grid.js +52 -43
- package/dist/components/content/grid.js.map +1 -1
- package/dist/components/content/history.js +83 -63
- package/dist/components/content/history.js.map +1 -1
- package/dist/components/content/index.d.ts +5 -3
- package/dist/components/content/listing.d.ts +14 -3
- package/dist/components/content/listing.js +65 -56
- package/dist/components/content/listing.js.map +1 -1
- package/dist/components/content/offer-fields.js +6 -6
- package/dist/components/content/paged-grid.d.ts +10 -0
- package/dist/components/content/paged-grid.js +116 -0
- package/dist/components/content/paged-grid.js.map +1 -0
- package/dist/components/content/pagination.d.ts +19 -0
- package/dist/components/content/pagination.js +97 -0
- package/dist/components/content/pagination.js.map +1 -0
- package/dist/components/content/paywall.d.ts +9 -0
- package/dist/components/content/paywall.js +27 -3
- package/dist/components/content/paywall.js.map +1 -1
- package/dist/components/content/post-list.d.ts +37 -0
- package/dist/components/content/post-list.js +203 -0
- package/dist/components/content/post-list.js.map +1 -0
- package/dist/components/content/reader-settings.d.ts +2 -0
- package/dist/components/content/reader-settings.js +1 -1
- package/dist/components/content/reader-settings.js.map +1 -1
- package/dist/components/groups/banner.d.ts +6 -2
- package/dist/components/groups/banner.js +79 -61
- package/dist/components/groups/banner.js.map +1 -1
- package/dist/components/groups/directory.d.ts +12 -2
- package/dist/components/groups/directory.js +168 -105
- package/dist/components/groups/directory.js.map +1 -1
- package/dist/components/groups/editor.js +10 -10
- package/dist/components/groups/editor.js.map +1 -1
- package/dist/components/groups/entity-chips.d.ts +61 -0
- package/dist/components/groups/entity-chips.js +382 -0
- package/dist/components/groups/entity-chips.js.map +1 -0
- package/dist/components/groups/group-members.d.ts +29 -0
- package/dist/components/groups/group-members.js +474 -0
- package/dist/components/groups/group-members.js.map +1 -0
- package/dist/components/groups/header.js +53 -45
- package/dist/components/groups/header.js.map +1 -1
- package/dist/components/groups/index.d.ts +3 -1
- package/dist/components/groups/memberships.d.ts +3 -36
- package/dist/components/groups/memberships.js +105 -480
- package/dist/components/groups/memberships.js.map +1 -1
- package/dist/components/groups/scoped.d.ts +23 -0
- package/dist/components/groups/scoped.js +92 -0
- package/dist/components/groups/scoped.js.map +1 -0
- package/dist/components/media-folder-editor.d.ts +5 -0
- package/dist/components/media-folder-editor.js +418 -230
- package/dist/components/media-folder-editor.js.map +1 -1
- package/dist/components/social/poll.js +57 -48
- package/dist/components/social/poll.js.map +1 -1
- package/dist/components/sortable-list.d.ts +5 -1
- package/dist/components/sortable-list.js +97 -81
- package/dist/components/sortable-list.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +41 -37
- package/dist/locales/admin/de.js +78 -45
- package/dist/locales/admin/de.js.map +1 -1
- package/dist/locales/admin/en.d.ts +74 -41
- package/dist/locales/admin/en.js +78 -45
- package/dist/locales/admin/en.js.map +1 -1
- package/dist/locales/admin/es.js +78 -45
- package/dist/locales/admin/es.js.map +1 -1
- package/dist/locales/admin/ja.js +78 -45
- package/dist/locales/admin/ja.js.map +1 -1
- package/dist/locales/admin/ko.js +78 -45
- package/dist/locales/admin/ko.js.map +1 -1
- package/dist/locales/admin/zh.js +78 -45
- package/dist/locales/admin/zh.js.map +1 -1
- package/dist/locales/de.js +2 -0
- package/dist/locales/de.js.map +1 -1
- package/dist/locales/discovery/de.js +25 -1
- package/dist/locales/discovery/de.js.map +1 -1
- package/dist/locales/discovery/en.d.ts +24 -0
- package/dist/locales/discovery/en.js +25 -1
- package/dist/locales/discovery/en.js.map +1 -1
- package/dist/locales/discovery/es.js +25 -1
- package/dist/locales/discovery/es.js.map +1 -1
- package/dist/locales/discovery/ja.js +25 -1
- package/dist/locales/discovery/ja.js.map +1 -1
- package/dist/locales/discovery/ko.js +25 -1
- package/dist/locales/discovery/ko.js.map +1 -1
- package/dist/locales/discovery/zh.js +25 -1
- package/dist/locales/discovery/zh.js.map +1 -1
- package/dist/locales/en.d.ts +120 -43
- package/dist/locales/en.js +2 -0
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +2 -0
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/groups/de.js +22 -4
- package/dist/locales/groups/de.js.map +1 -1
- package/dist/locales/groups/en.d.ts +20 -2
- package/dist/locales/groups/en.js +22 -4
- package/dist/locales/groups/en.js.map +1 -1
- package/dist/locales/groups/es.js +22 -4
- package/dist/locales/groups/es.js.map +1 -1
- package/dist/locales/groups/ja.js +22 -4
- package/dist/locales/groups/ja.js.map +1 -1
- package/dist/locales/groups/ko.js +22 -4
- package/dist/locales/groups/ko.js.map +1 -1
- package/dist/locales/groups/zh.js +22 -4
- package/dist/locales/groups/zh.js.map +1 -1
- package/dist/locales/ja.js +2 -0
- package/dist/locales/ja.js.map +1 -1
- package/dist/locales/ko.js +2 -0
- package/dist/locales/ko.js.map +1 -1
- package/dist/locales/zh.js +2 -0
- package/dist/locales/zh.js.map +1 -1
- package/dist/react/contents.js +1 -1
- package/dist/react/contents.js.map +1 -1
- package/dist/react/discovery.d.ts +16 -0
- package/dist/react/discovery.js +69 -37
- package/dist/react/discovery.js.map +1 -1
- package/dist/react/groups.d.ts +19 -3
- package/dist/react/groups.js +49 -22
- package/dist/react/groups.js.map +1 -1
- package/dist/react/index.d.ts +6 -4
- package/dist/react/page-notices.d.ts +13 -0
- package/dist/react/page-notices.js +38 -0
- package/dist/react/page-notices.js.map +1 -0
- package/dist/react/post-reads.d.ts +23 -0
- package/dist/react/post-reads.js +90 -0
- package/dist/react/post-reads.js.map +1 -0
- package/dist/react/remembered-sort.d.ts +5 -0
- package/dist/react/remembered-sort.js +29 -0
- package/dist/react/remembered-sort.js.map +1 -0
- package/dist/react/resources.js +2 -2
- package/dist/react/resources.js.map +1 -1
- package/dist/react/stats.d.ts +3 -7
- package/dist/react/stats.js +2 -6
- package/dist/react/stats.js.map +1 -1
- package/dist/react/use-engagement.d.ts +2 -0
- package/dist/react/use-engagement.js +40 -34
- package/dist/react/use-engagement.js.map +1 -1
- package/dist/react.js +29 -27
- package/dist/styles.css +1 -1
- package/dist/urls/index.d.ts +1 -1
- package/dist/urls.js +2 -2
- package/dist/urls.js.map +1 -1
- package/package.json +1 -1
- package/dist/components/admin/page-review.d.ts +0 -13
- package/dist/components/admin/page-review.js +0 -225
- package/dist/components/admin/page-review.js.map +0 -1
- package/dist/react/page-review.d.ts +0 -14
- package/dist/react/page-review.js +0 -37
- package/dist/react/page-review.js.map +0 -1
|
@@ -8,12 +8,13 @@ import { useNearViewport as o } from "../../react/viewport.js";
|
|
|
8
8
|
import { Skeleton as s } from "../../ui/skeleton.js";
|
|
9
9
|
import { contentError as c } from "../social/parts.js";
|
|
10
10
|
import { useContents as l, useExposure as u, useHistory as d, useRecommendations as f, useSearch as p, useSimilar as m } from "../../react/discovery.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
11
|
+
import { ContentFilterDialog as h } from "./filter-dialog.js";
|
|
12
|
+
import { useReleaseReveal as g } from "./release-reveal.js";
|
|
13
|
+
import { ContentSummaryTile as _ } from "./summary-tile.js";
|
|
14
|
+
import { ContentCard as v } from "./card.js";
|
|
15
|
+
import { PagedContentGrid as y, PagedSearchResults as b } from "./paged-grid.js";
|
|
16
|
+
import { ContentHistory as x } from "./history.js";
|
|
17
|
+
import { useCallback as S, useContext as C, useEffect as w, useLayoutEffect as ee, useMemo as T, useRef as te, useState as E } from "react";
|
|
17
18
|
import { jsx as D, jsxs as O } from "react/jsx-runtime";
|
|
18
19
|
import { cn as k } from "cn";
|
|
19
20
|
//#region src/components/content/grid.tsx
|
|
@@ -30,7 +31,7 @@ function j(e) {
|
|
|
30
31
|
};
|
|
31
32
|
}
|
|
32
33
|
function M(e) {
|
|
33
|
-
let { client: t, viewer: i, language: a } = r(e.client), o =
|
|
34
|
+
let { client: t, viewer: i, language: a } = r(e.client), o = C(n), [s, c] = E({
|
|
34
35
|
client: t,
|
|
35
36
|
viewer: i,
|
|
36
37
|
language: a,
|
|
@@ -48,23 +49,23 @@ function M(e) {
|
|
|
48
49
|
}, c(l)), /* @__PURE__ */ D(N, { ...e }, l.key);
|
|
49
50
|
}
|
|
50
51
|
function N({ list: n, render: r, filterKinds: l, filterLanguage: d, horizontal: f, ...p }) {
|
|
51
|
-
let m = e(), { t: y } = m, { kinds:
|
|
52
|
-
|
|
53
|
-
if (!
|
|
52
|
+
let m = e(), { t: y } = m, { kinds: b } = i({ client: p.client }), [x, C] = E(!1), [A, M] = E(!1), N = te(null), [P, F] = E(null), [I, L] = E(0), [R, z] = E(() => globalThis.matchMedia?.("(max-width: 767px)").matches ?? !1);
|
|
53
|
+
ee(() => {
|
|
54
|
+
if (!P) return;
|
|
54
55
|
let e = () => {
|
|
55
|
-
let e = getComputedStyle(
|
|
56
|
-
|
|
56
|
+
let e = getComputedStyle(P).gridTemplateColumns.trim();
|
|
57
|
+
L(e && e !== "none" ? e.split(/\s+/).length : 0), z(globalThis.matchMedia?.("(max-width: 767px)").matches ?? !1);
|
|
57
58
|
};
|
|
58
59
|
e();
|
|
59
60
|
let t = typeof ResizeObserver == "function" ? new ResizeObserver(e) : void 0;
|
|
60
|
-
return t?.observe(
|
|
61
|
+
return t?.observe(P), addEventListener("resize", e), () => {
|
|
61
62
|
t?.disconnect(), removeEventListener("resize", e);
|
|
62
63
|
};
|
|
63
|
-
}, [
|
|
64
|
-
let B = n.summary?.locked_count ?? 0, V = p.showFilteredSummary === !1 ? 0 : n.summary?.filtered_count ?? 0, H = p.locked === "collapse" && !
|
|
64
|
+
}, [P]);
|
|
65
|
+
let B = n.summary?.locked_count ?? 0, V = p.showFilteredSummary === !1 ? 0 : n.summary?.filtered_count ?? 0, H = p.locked === "collapse" && !x && B > 0, U = H && B > 0 && I >= Math.max(0, p.lockedSummaryMinColumns ?? 0), W = T(() => {
|
|
65
66
|
let e = [], t = !1;
|
|
66
67
|
for (let [r, i] of n.items.entries()) {
|
|
67
|
-
if (
|
|
68
|
+
if (ne(i) && (H || p.locked === "hide")) {
|
|
68
69
|
U && !t && (e.push({
|
|
69
70
|
key: "premium-summary",
|
|
70
71
|
premium: !0,
|
|
@@ -82,17 +83,17 @@ function N({ list: n, render: r, filterKinds: l, filterLanguage: d, horizontal:
|
|
|
82
83
|
key: "premium-summary",
|
|
83
84
|
premium: !0
|
|
84
85
|
});
|
|
85
|
-
let r =
|
|
86
|
+
let r = R && p.mobileCardLimit !== void 0 ? p.mobileCardLimit : p.cardLimit;
|
|
86
87
|
return r !== void 0 && Number.isFinite(r) ? e.slice(0, Math.max(0, Math.floor(r))) : e;
|
|
87
88
|
}, [
|
|
88
89
|
n.items,
|
|
89
90
|
H,
|
|
90
91
|
p.locked,
|
|
91
92
|
U,
|
|
92
|
-
|
|
93
|
+
R,
|
|
93
94
|
p.mobileCardLimit,
|
|
94
95
|
p.cardLimit
|
|
95
|
-
]), re =
|
|
96
|
+
]), re = T(() => W.flatMap((e) => "premium" in e ? [] : [{
|
|
96
97
|
...e.card,
|
|
97
98
|
position: e.position
|
|
98
99
|
}]), [W]), G = u(re, {
|
|
@@ -103,7 +104,7 @@ function N({ list: n, render: r, filterKinds: l, filterLanguage: d, horizontal:
|
|
|
103
104
|
margin: "600px 0px",
|
|
104
105
|
leaveMargin: "1200px 0px"
|
|
105
106
|
}), { hasMore: q, loadingMore: J, loadMore: Y, error: X } = n;
|
|
106
|
-
|
|
107
|
+
w(() => {
|
|
107
108
|
p.infinite && K && q && !J && !X && Y();
|
|
108
109
|
}, [
|
|
109
110
|
p.infinite,
|
|
@@ -113,8 +114,8 @@ function N({ list: n, render: r, filterKinds: l, filterLanguage: d, horizontal:
|
|
|
113
114
|
Y,
|
|
114
115
|
X
|
|
115
116
|
]);
|
|
116
|
-
let { grid: Z, prepare: ae } =
|
|
117
|
-
Z.current = e,
|
|
117
|
+
let { grid: Z, prepare: ae } = g(W.map((e) => e.key).join("\0")), oe = S((e) => {
|
|
118
|
+
Z.current = e, F(e);
|
|
118
119
|
}, [Z]), Q = f ? { className: "relative flex snap-x gap-4 overflow-x-auto pb-2 [&>li]:w-36 [&>li]:shrink-0 [&>li]:snap-start sm:[&>li]:w-44" } : j(p.grid), $ = n.summary?.truncated ? "≥ " : "", se = $ + (p.summaryLabels?.premium?.(B) ?? m.plural("contents.lockedShow", B)), ce = $ + (p.summaryLabels?.filtered?.(V) ?? m.plural("releases.filteredMore", V)), le = W.length > 0 || V > 0 || H && B > 0;
|
|
119
120
|
return /* @__PURE__ */ O(t, {
|
|
120
121
|
appearance: p.appearance,
|
|
@@ -147,7 +148,7 @@ function N({ list: n, render: r, filterKinds: l, filterLanguage: d, horizontal:
|
|
|
147
148
|
tabIndex: -1,
|
|
148
149
|
className: Q.className,
|
|
149
150
|
style: Q.style,
|
|
150
|
-
children: [W.map((e) => "premium" in e ? /* @__PURE__ */ D(
|
|
151
|
+
children: [W.map((e) => "premium" in e ? /* @__PURE__ */ D(_, {
|
|
151
152
|
tileKey: e.key,
|
|
152
153
|
kind: "premium",
|
|
153
154
|
contentKind: l?.[0] ?? e.card?.kind,
|
|
@@ -156,12 +157,12 @@ function N({ list: n, render: r, filterKinds: l, filterLanguage: d, horizontal:
|
|
|
156
157
|
cardProps: p,
|
|
157
158
|
label: se,
|
|
158
159
|
onClick: (e) => {
|
|
159
|
-
ae(e.detail === 0),
|
|
160
|
+
ae(e.detail === 0), C(!0);
|
|
160
161
|
}
|
|
161
162
|
}, e.key) : /* @__PURE__ */ D("li", {
|
|
162
163
|
"data-release-key": e.key,
|
|
163
164
|
ref: G.track(e.card.id, e.position),
|
|
164
|
-
children: p.renderCard ? p.renderCard(e.card, e.position) : /* @__PURE__ */ D(
|
|
165
|
+
children: p.renderCard ? p.renderCard(e.card, e.position) : /* @__PURE__ */ D(v, {
|
|
165
166
|
card: e.card,
|
|
166
167
|
client: p.client,
|
|
167
168
|
href: p.href,
|
|
@@ -171,19 +172,21 @@ function N({ list: n, render: r, filterKinds: l, filterLanguage: d, horizontal:
|
|
|
171
172
|
loadMedia: p.loadMedia,
|
|
172
173
|
groupKinds: p.groupKinds,
|
|
173
174
|
chips: p.chips,
|
|
175
|
+
chipOverflow: p.chipOverflow,
|
|
176
|
+
chipFit: p.chipFit,
|
|
174
177
|
filterEntity: p.filterEntity,
|
|
175
178
|
entityStyle: p.entityStyle,
|
|
176
179
|
entityLayout: p.entityLayout,
|
|
177
180
|
metadata: p.metadata,
|
|
178
181
|
showCounts: p.showCounts,
|
|
179
|
-
tiers: p.tiers ??
|
|
182
|
+
tiers: p.tiers ?? b?.tiers,
|
|
180
183
|
labels: p.labels,
|
|
181
184
|
owner: p.owner,
|
|
182
185
|
ownerHref: p.ownerHref,
|
|
183
186
|
decorate: p.decorate,
|
|
184
187
|
onOpen: () => G.click(e.card.id, e.position)
|
|
185
188
|
})
|
|
186
|
-
}, e.key)), V > 0 && /* @__PURE__ */ D(
|
|
189
|
+
}, e.key)), V > 0 && /* @__PURE__ */ D(_, {
|
|
187
190
|
tileKey: "filtered-summary",
|
|
188
191
|
kind: "filtered",
|
|
189
192
|
contentKind: l?.[0] ?? n.items[0]?.kind,
|
|
@@ -191,7 +194,7 @@ function N({ list: n, render: r, filterKinds: l, filterLanguage: d, horizontal:
|
|
|
191
194
|
cardProps: p,
|
|
192
195
|
label: ce,
|
|
193
196
|
onClick: (e) => {
|
|
194
|
-
|
|
197
|
+
N.current = e.currentTarget, M(!0);
|
|
195
198
|
}
|
|
196
199
|
})]
|
|
197
200
|
}) : /* @__PURE__ */ D("div", {
|
|
@@ -214,10 +217,10 @@ function N({ list: n, render: r, filterKinds: l, filterLanguage: d, horizontal:
|
|
|
214
217
|
children: n.loadingMore ? y("contents.loading") : n.error ? y("common.retry") : y("contents.loadMore")
|
|
215
218
|
})]
|
|
216
219
|
}),
|
|
217
|
-
/* @__PURE__ */ D(
|
|
218
|
-
open:
|
|
219
|
-
onOpenChange:
|
|
220
|
-
returnFocus: () =>
|
|
220
|
+
/* @__PURE__ */ D(h, {
|
|
221
|
+
open: A,
|
|
222
|
+
onOpenChange: M,
|
|
223
|
+
returnFocus: () => N.current?.isConnected ? N.current : P,
|
|
221
224
|
client: p.client,
|
|
222
225
|
kinds: l,
|
|
223
226
|
language: d,
|
|
@@ -236,9 +239,12 @@ var F = [
|
|
|
236
239
|
"group",
|
|
237
240
|
"ppv",
|
|
238
241
|
"group_ppv"
|
|
239
|
-
],
|
|
240
|
-
function I(
|
|
241
|
-
|
|
242
|
+
], ne = (e) => !e.access.allowed && !e.access.unknown && F.includes(e.access.level);
|
|
243
|
+
function I(e) {
|
|
244
|
+
return e.pagination === "pages" ? /* @__PURE__ */ D(y, { ...e }) : /* @__PURE__ */ D(L, { ...e });
|
|
245
|
+
}
|
|
246
|
+
function L({ query: e, locked: t = "show", ...n }) {
|
|
247
|
+
let r = T(() => ({
|
|
242
248
|
...e,
|
|
243
249
|
summary: e.summary ?? !0,
|
|
244
250
|
limit: e.limit ?? n.pageSize,
|
|
@@ -257,8 +263,11 @@ function I({ query: e, locked: t = "show", ...n }) {
|
|
|
257
263
|
filterLanguage: e.display_language ?? e.language
|
|
258
264
|
});
|
|
259
265
|
}
|
|
260
|
-
function
|
|
261
|
-
|
|
266
|
+
function R(e) {
|
|
267
|
+
return e.pagination === "pages" ? /* @__PURE__ */ D(b, { ...e }) : /* @__PURE__ */ D(z, { ...e });
|
|
268
|
+
}
|
|
269
|
+
function z({ query: t, ...n }) {
|
|
270
|
+
let { t: r } = e(), i = T(() => ({
|
|
262
271
|
...t,
|
|
263
272
|
mode: P(n.locked, t.mode),
|
|
264
273
|
summary: t.summary ?? !0,
|
|
@@ -278,8 +287,8 @@ function L({ query: t, ...n }) {
|
|
|
278
287
|
filterLanguage: t.display_language ?? t.language
|
|
279
288
|
}) : null;
|
|
280
289
|
}
|
|
281
|
-
function
|
|
282
|
-
let p = s.limit ?? u.pageSize ?? 12, h =
|
|
290
|
+
function B({ title: e, similar: n, recommendations: r, history: i, group: a, list: o, query: s = {}, more: c, ...u }) {
|
|
291
|
+
let p = s.limit ?? u.pageSize ?? 12, h = T(() => ({
|
|
283
292
|
...s,
|
|
284
293
|
mode: P(u.locked, s.mode),
|
|
285
294
|
summary: s.summary ?? !0,
|
|
@@ -288,7 +297,7 @@ function R({ title: e, similar: n, recommendations: r, history: i, group: a, lis
|
|
|
288
297
|
s,
|
|
289
298
|
p,
|
|
290
299
|
u.locked
|
|
291
|
-
]), g =
|
|
300
|
+
]), g = T(() => o ? {
|
|
292
301
|
...o,
|
|
293
302
|
mode: P(u.locked, o.mode),
|
|
294
303
|
summary: o.summary ?? !0,
|
|
@@ -326,7 +335,7 @@ function R({ title: e, similar: n, recommendations: r, history: i, group: a, lis
|
|
|
326
335
|
loadingMore: !1,
|
|
327
336
|
hasMore: !1,
|
|
328
337
|
loadMore: async () => {}
|
|
329
|
-
},
|
|
338
|
+
}, w = o?.kind ?? i?.kind ?? h.kind;
|
|
330
339
|
return /* @__PURE__ */ O(t, {
|
|
331
340
|
appearance: u.appearance,
|
|
332
341
|
className: k("grid gap-3 text-sm", u.className),
|
|
@@ -352,12 +361,12 @@ function R({ title: e, similar: n, recommendations: r, history: i, group: a, lis
|
|
|
352
361
|
g,
|
|
353
362
|
h
|
|
354
363
|
]),
|
|
355
|
-
filterKinds:
|
|
364
|
+
filterKinds: w ? [w] : void 0,
|
|
356
365
|
filterLanguage: o?.display_language ?? i?.display_language ?? h.display_language ?? o?.language ?? i?.language ?? h.language
|
|
357
366
|
})]
|
|
358
367
|
});
|
|
359
368
|
}
|
|
360
369
|
//#endregion
|
|
361
|
-
export { M as CardGrid, I as ContentGrid,
|
|
370
|
+
export { M as CardGrid, I as ContentGrid, x as ContentHistory, B as ContentRail, R as SearchResults, j as cardGridLayout, P as cardListMode };
|
|
362
371
|
|
|
363
372
|
//# sourceMappingURL=grid.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid.js","names":[],"sources":["../../../src/components/content/grid.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport { useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode } from \"react\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { AccessMode, ContentQuery, HistoryQuery, RailQuery, SearchQuery } from \"../../client/discovery.js\";\nimport type { Card, ListingSummary } from \"../../client/generated/wire.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { useContents, useExposure, useHistory, useRecommendations, useSearch, useSimilar, type UseRail } from \"../../react/discovery.js\";\nimport { useKinds } from \"../../react/groups.js\";\nimport type { UseList } from \"../../react/use-resource.js\";\nimport { ContentKitContext } from \"../../react/context.js\";\nimport { useContentScope } from \"../../react/use-resource.js\";\nimport { useNearViewport } from \"../../react/viewport.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { contentError } from \"../social/parts.js\";\nimport { ContentFilterDialog } from \"./filter-dialog.js\";\nimport { useReleaseReveal } from \"./release-reveal.js\";\nimport { ContentSummaryTile } from \"./summary-tile.js\";\nimport { ContentCard, type ContentCardProps } from \"./card.js\";\n\nexport interface CardListProps extends Omit<ContentCardProps, \"card\" | \"onOpen\" | \"children\" | \"className\"> {\n /** Where the list is, for exposures and click attribution: \"home\", \"search\", \"similar\". */\n surface?: string;\n /** Loads the next page as the end nears, instead of a button. */\n infinite?: boolean;\n /** A card's entry instead of ContentCard. */\n renderCard?: (card: Card, position: number) => ReactNode;\n /** Shown when nothing matches. */\n empty?: ReactNode;\n pageSize?: number;\n client?: ContentKitClient;\n className?: string;\n appearance?: ContentKitUiAppearance;\n /** Collapse paid/locked cards into a counted tile, or hide them; default show. */\n locked?: LockedCards;\n /** Optional-filter summary tiles are on by default; hosts may suppress them in previews. */\n showFilteredSummary?: boolean;\n /** Show the collapsed locked tile only at this measured grid width. Default 0. */\n lockedSummaryMinColumns?: number;\n /** Limit rendered preview tiles without changing the matching selection or summary counts. */\n cardLimit?: number;\n /** Limit cards in mobile previews without mounting their images. */\n mobileCardLimit?: number;\n /** Host-specific nouns for summary controls. */\n summaryLabels?: { premium?: (count: number) => string; filtered?: (count: number) => string };\n /** Opt into a fluid grid, optionally with a desktop column ceiling. */\n grid?: CardGridLayout;\n}\n\nconst GRID = \"grid grid-cols-[repeat(auto-fill,minmax(min(100%,10rem),1fr))] gap-x-4 gap-y-6\";\n\nexport interface CardGridLayout {\n /** Minimum desktop card width: CSS pixels or a CSS length such as clamp(...). Cards fill the available space. */\n minCardWidth: number | string;\n /** Maximum desktop columns. Omit to use all available width without a ceiling. */\n maxColumns?: number;\n /** Equal-width columns below the desktop breakpoint. Default 2. */\n mobileColumns?: number;\n}\n\n/** Shared by complete lists, release-day sections and grid-style previews. */\nexport function cardGridLayout(layout?: CardGridLayout): { className: string; style?: CSSProperties } {\n if (!layout) return { className: GRID };\n const width =\n typeof layout.minCardWidth === \"string\" ? layout.minCardWidth.trim() || \"160px\" : `${Number.isFinite(layout.minCardWidth) ? Math.max(1, layout.minCardWidth) : 160}px`;\n const columns = layout.mobileColumns !== undefined && Number.isFinite(layout.mobileColumns) ? Math.max(1, Math.floor(layout.mobileColumns)) : 2;\n const maximum = layout.maxColumns !== undefined && Number.isFinite(layout.maxColumns) ? Math.max(1, Math.floor(layout.maxColumns)) : undefined;\n const trackWidth = maximum === undefined ? width : `max(${width}, calc((100% - ${maximum - 1}rem) / ${maximum}))`;\n return {\n className:\n \"grid grid-cols-[repeat(var(--ckui-card-mobile-columns),minmax(0,1fr))] gap-x-4 gap-y-6 md:grid-cols-[repeat(auto-fill,minmax(min(100%,var(--ckui-card-min-width)),1fr))]\",\n style: { \"--ckui-card-min-width\": trackWidth, \"--ckui-card-mobile-columns\": columns } as CSSProperties,\n };\n}\n\n/** A list carries exact selection-wide counts when the API was asked for them. */\ntype SummaryList = UseList<Card> & { summary?: ListingSummary };\ntype GridProps = CardListProps & { list: SummaryList; render: string; filterKinds?: readonly string[]; filterLanguage?: string; horizontal?: boolean };\n\n/** A list's cards and summary controls share one responsive, animated grid. */\nexport function CardGrid(p: GridProps) {\n const { client, viewer, language } = useContentScope(p.client);\n const context = useContext(ContentKitContext);\n const [boundary, setBoundary] = useState({ client, viewer, language, access: context?.accessRevision, render: p.render, key: 0 });\n let session = boundary;\n if (boundary.client !== client || boundary.viewer !== viewer || boundary.language !== language || boundary.access !== context?.accessRevision || boundary.render !== p.render) {\n session = { client, viewer, language, access: context?.accessRevision, render: p.render, key: boundary.key + 1 };\n setBoundary(session);\n }\n return <CardGridBody key={session.key} {...p} />;\n}\n\nfunction CardGridBody({ list, render, filterKinds, filterLanguage, horizontal, ...p }: GridProps) {\n const m = useMessages();\n const { t } = m;\n const { kinds } = useKinds({ client: p.client });\n const [expanded, setExpanded] = useState(false);\n const [filtersOpen, setFiltersOpen] = useState(false);\n const filterTrigger = useRef<HTMLElement | null>(null);\n const [element, setElement] = useState<HTMLOListElement | null>(null);\n const [columns, setColumns] = useState(0);\n const [mobile, setMobile] = useState(() => globalThis.matchMedia?.(\"(max-width: 767px)\").matches ?? false);\n useLayoutEffect(() => {\n if (!element) return;\n const measure = () => {\n const tracks = getComputedStyle(element).gridTemplateColumns.trim();\n setColumns(tracks && tracks !== \"none\" ? tracks.split(/\\s+/).length : 0);\n setMobile(globalThis.matchMedia?.(\"(max-width: 767px)\").matches ?? false);\n };\n measure();\n const observer = typeof ResizeObserver === \"function\" ? new ResizeObserver(measure) : undefined;\n observer?.observe(element);\n addEventListener(\"resize\", measure);\n return () => {\n observer?.disconnect();\n removeEventListener(\"resize\", measure);\n };\n }, [element]);\n const lockedCount = list.summary?.locked_count ?? 0;\n const filteredCount = p.showFilteredSummary === false ? 0 : (list.summary?.filtered_count ?? 0);\n const collapse = p.locked === \"collapse\" && !expanded && lockedCount > 0;\n const lockedTile = collapse && lockedCount > 0 && columns >= Math.max(0, p.lockedSummaryMinColumns ?? 0);\n const entries = useMemo(() => {\n const result: ({ key: string; card: Card; position: number } | { key: string; premium: true; card?: Card })[] = [];\n let inserted = false;\n for (const [i, card] of list.items.entries()) {\n if (isLockedCard(card) && (collapse || p.locked === \"hide\")) {\n if (lockedTile && !inserted) {\n result.push({ key: \"premium-summary\", premium: true, card });\n inserted = true;\n }\n continue;\n }\n result.push({ key: card.id, card, position: i + 1 });\n }\n if (lockedTile && !inserted) result.push({ key: \"premium-summary\", premium: true });\n const limit = mobile && p.mobileCardLimit !== undefined ? p.mobileCardLimit : p.cardLimit;\n return limit !== undefined && Number.isFinite(limit) ? result.slice(0, Math.max(0, Math.floor(limit))) : result;\n }, [list.items, collapse, p.locked, lockedTile, mobile, p.mobileCardLimit, p.cardLimit]);\n const shown = useMemo(() => entries.flatMap((entry) => (\"premium\" in entry ? [] : [{ ...entry.card, position: entry.position }])), [entries]);\n const exposure = useExposure(shown, { surface: p.surface ?? \"list\", render, client: p.client });\n const [sentinel, near] = useNearViewport({ margin: \"600px 0px\", leaveMargin: \"1200px 0px\" });\n const { hasMore, loadingMore, loadMore, error } = list;\n useEffect(() => {\n if (p.infinite && near && hasMore && !loadingMore && !error) void loadMore();\n }, [p.infinite, near, hasMore, loadingMore, loadMore, error]);\n const { grid: animationGrid, prepare } = useReleaseReveal(entries.map((entry) => entry.key).join(\"\\0\"));\n const grid = useCallback(\n (node: HTMLOListElement | null) => {\n animationGrid.current = node;\n setElement(node);\n },\n [animationGrid],\n );\n const layout: ReturnType<typeof cardGridLayout> = horizontal\n ? { className: \"relative flex snap-x gap-4 overflow-x-auto pb-2 [&>li]:w-36 [&>li]:shrink-0 [&>li]:snap-start sm:[&>li]:w-44\" }\n : cardGridLayout(p.grid);\n const lowerBound = list.summary?.truncated ? \"≥ \" : \"\";\n const premiumLabel = lowerBound + (p.summaryLabels?.premium?.(lockedCount) ?? m.plural(\"contents.lockedShow\", lockedCount));\n const filteredLabel = lowerBound + (p.summaryLabels?.filtered?.(filteredCount) ?? m.plural(\"releases.filteredMore\", filteredCount));\n const showGrid = entries.length > 0 || filteredCount > 0 || (collapse && lockedCount > 0);\n return (\n <ContentKitUiRoot appearance={p.appearance} className={cn(\"grid gap-4 text-sm\", p.className)} data-ckui=\"content-grid\" aria-busy={list.loading}>\n {list.loading && !list.items.length ? (\n <ol aria-hidden className={layout.className} style={layout.style}>\n {Array.from({ length: 8 }, (_, i) => (\n <li key={i}>\n <Skeleton\n className={p.aspectRatio === undefined ? (p.shape === \"landscape\" ? \"aspect-video w-full\" : \"aspect-[3/4] w-full\") : \"w-full\"}\n style={p.aspectRatio === undefined ? undefined : { aspectRatio: p.aspectRatio }}\n />\n </li>\n ))}\n </ol>\n ) : list.error && !list.items.length ? (\n <div role=\"alert\" className=\"grid justify-items-start gap-2\">\n <p className=\"text-destructive\">{contentError(m, list.error)}</p>\n <Button size=\"sm\" variant=\"outline\" onClick={list.reload}>\n {t(\"common.retry\")}\n </Button>\n </div>\n ) : !showGrid ? (\n <div className=\"text-muted-foreground\" role=\"status\">\n {p.empty ?? t(\"contents.empty\")}\n </div>\n ) : (\n <ol ref={grid} tabIndex={-1} className={layout.className} style={layout.style}>\n {entries.map((entry) =>\n \"premium\" in entry ? (\n <ContentSummaryTile\n key={entry.key}\n tileKey={entry.key}\n kind=\"premium\"\n contentKind={filterKinds?.[0] ?? entry.card?.kind}\n preview={entry.card}\n open\n cardProps={p}\n label={premiumLabel}\n onClick={(event) => {\n prepare(event.detail === 0);\n setExpanded(true);\n }}\n />\n ) : (\n <li key={entry.key} data-release-key={entry.key} ref={exposure.track(entry.card.id, entry.position)}>\n {p.renderCard ? (\n p.renderCard(entry.card, entry.position)\n ) : (\n <ContentCard\n card={entry.card}\n client={p.client}\n href={p.href}\n shape={p.shape}\n aspectRatio={p.aspectRatio}\n titlePosition={p.titlePosition}\n loadMedia={p.loadMedia}\n groupKinds={p.groupKinds}\n chips={p.chips}\n filterEntity={p.filterEntity}\n entityStyle={p.entityStyle}\n entityLayout={p.entityLayout}\n metadata={p.metadata}\n showCounts={p.showCounts}\n tiers={p.tiers ?? kinds?.tiers}\n labels={p.labels}\n owner={p.owner}\n ownerHref={p.ownerHref}\n decorate={p.decorate}\n onOpen={() => exposure.click(entry.card.id, entry.position)}\n />\n )}\n </li>\n ),\n )}\n {filteredCount > 0 && (\n <ContentSummaryTile\n tileKey=\"filtered-summary\"\n kind=\"filtered\"\n contentKind={filterKinds?.[0] ?? list.items[0]?.kind}\n open\n cardProps={p}\n label={filteredLabel}\n onClick={(event) => {\n filterTrigger.current = event.currentTarget;\n setFiltersOpen(true);\n }}\n />\n )}\n </ol>\n )}\n {list.hasMore && (\n <div ref={sentinel} className=\"grid justify-items-center gap-2\">\n {list.error && list.items.length > 0 && (\n <p role=\"alert\" className=\"text-destructive\">\n {contentError(m, list.error)}\n </p>\n )}\n <Button variant=\"outline\" size=\"sm\" disabled={list.loadingMore} onClick={() => void list.loadMore()}>\n {list.loadingMore ? t(\"contents.loading\") : list.error ? t(\"common.retry\") : t(\"contents.loadMore\")}\n </Button>\n </div>\n )}\n <ContentFilterDialog\n open={filtersOpen}\n onOpenChange={setFiltersOpen}\n returnFocus={() => (filterTrigger.current?.isConnected ? filterTrigger.current : element)}\n client={p.client}\n kinds={filterKinds}\n language={filterLanguage}\n counts={list.summary?.filtered_entities}\n countsLowerBound={list.summary?.truncated}\n appearance={p.appearance}\n />\n </ContentKitUiRoot>\n );\n}\n\n/**\n * What a list does with cards the reader doesn't open: shows them marked\n * (show), leaves them out (hide), or replaces them with a counted tile\n * that reveals the cached previews in place (collapse).\n */\nexport type LockedCards = \"show\" | \"hide\" | \"collapse\";\n\n/** Settle locked-card admission before pagination, retaining explicit reader modes otherwise. */\nexport function cardListMode(locked: LockedCards | undefined, mode?: AccessMode): AccessMode | undefined {\n return locked === \"hide\" ? \"hide\" : locked === \"collapse\" ? \"lock\" : mode;\n}\n\nconst LOCKED_LEVELS: readonly string[] = [\"tier\", \"group\", \"ppv\", \"group_ppv\"];\nconst isLockedCard = (card: Card) => !card.access.allowed && !card.access.unknown && LOCKED_LEVELS.includes(card.access.level);\n\n/** Contents as cards (GET /v1/contents): any sort and filter, paged. */\nexport function ContentGrid({ query, locked = \"show\", ...p }: CardListProps & { query: ContentQuery }) {\n const q = useMemo<ContentQuery>(\n () => ({\n ...query,\n summary: query.summary ?? true,\n limit: query.limit ?? p.pageSize,\n mode: cardListMode(locked, query.mode),\n }),\n [query, p.pageSize, locked],\n );\n const list = useContents(q, { client: p.client });\n return (\n <CardGrid\n {...p}\n locked={locked}\n list={list}\n render={JSON.stringify(q)}\n filterKinds={query.kind ? [query.kind] : undefined}\n filterLanguage={query.display_language ?? query.language}\n />\n );\n}\n\n/** Search results as cards; nothing until the query has text. */\nexport function SearchResults({ query, ...p }: CardListProps & { query: SearchQuery }) {\n const { t } = useMessages();\n const q = useMemo(\n () => ({ ...query, mode: cardListMode(p.locked, query.mode), summary: query.summary ?? true, limit: query.limit ?? p.pageSize }),\n [query, p.pageSize, p.locked],\n );\n const list = useSearch(q, { client: p.client });\n if (!query.q.trim()) return null;\n return (\n <CardGrid\n surface=\"search\"\n empty={t(\"contents.noResults\", { q: query.q.trim() })}\n {...p}\n list={list}\n render={JSON.stringify(q)}\n filterKinds={query.kind ? [query.kind] : undefined}\n filterLanguage={query.display_language ?? query.language}\n />\n );\n}\n\nexport { ContentHistory } from \"./history.js\";\n\nexport interface ContentRailProps extends Omit<CardListProps, \"infinite\" | \"empty\"> {\n /** The rail's heading. */\n title: ReactNode;\n /** Contents like this one. */\n similar?: string;\n /** For the signed-in reader. */\n recommendations?: boolean;\n /** The reader's history: { status: \"in_progress\" } is a continue-watching rail. */\n history?: HistoryQuery;\n /** An ordered group's members in its order: a featured rail (its windows apply). */\n group?: string;\n /** Any list: a sort and filters. */\n list?: ContentQuery;\n /** Filters and reader options of a similar or recommended rail. */\n query?: RailQuery;\n /** A link beside the heading, e.g. to the whole list. */\n more?: ReactNode;\n}\n\n/**\n * A horizontal row of contents: similar, recommended, the reader's history,\n * an ordered group's members or any list. It hides itself when it has none or\n * the site runs without what it needs.\n */\nexport function ContentRail({ title, similar, recommendations, history, group, list: listQuery, query = {}, more, ...p }: ContentRailProps) {\n const limit = query.limit ?? p.pageSize ?? 12;\n const q = useMemo(() => ({ ...query, mode: cardListMode(p.locked, query.mode), summary: query.summary ?? true, limit }), [query, limit, p.locked]);\n const listing = useMemo(\n () =>\n listQuery\n ? { ...listQuery, mode: cardListMode(p.locked, listQuery.mode), summary: listQuery.summary ?? true, limit: listQuery.limit ?? limit }\n : group\n ? { groups: [group], sort: \"position\" as const, mode: cardListMode(p.locked), summary: true, limit }\n : null,\n [listQuery, group, limit, p.locked],\n );\n const like = useSimilar(recommendations || history || listing ? null : similar, q, { client: p.client });\n const mine = useRecommendations(recommendations ? q : null, { client: p.client });\n const seen = useHistory(history ? { ...history, mode: cardListMode(p.locked, history.mode), summary: history.summary ?? true, limit: history.limit ?? limit } : null, {\n client: p.client,\n });\n const listed = useContents(listing, { client: p.client });\n const rail: UseRail = recommendations\n ? mine\n : history || listing\n ? (() => {\n const l = history ? seen : listed;\n return { items: l.items, summary: l.summary, loading: l.loading, error: l.error, unavailable: l.error?.code === \"not_configured\", reload: l.reload };\n })()\n : like;\n const surface = p.surface ?? (recommendations ? \"recommendations\" : history ? \"history\" : group ? \"featured\" : listing ? \"list\" : \"similar\");\n const source = similar || recommendations || history || group || listing;\n if (!source || rail.unavailable || (!rail.loading && !rail.items.length && !rail.summary?.filtered_count && !rail.summary?.locked_count)) return null;\n const list: SummaryList = { ...rail, loadingMore: false, hasMore: false, loadMore: async () => {} };\n const kind = listQuery?.kind ?? history?.kind ?? q.kind;\n return (\n <ContentKitUiRoot appearance={p.appearance} className={cn(\"grid gap-3 text-sm\", p.className)} data-ckui=\"content-rail\" data-surface={surface}>\n <div className=\"flex items-baseline justify-between gap-2\">\n <h2 className=\"text-base font-semibold\">{title}</h2>\n {more}\n </div>\n <CardGrid\n {...p}\n className={undefined}\n surface={surface}\n horizontal={!p.grid}\n list={list}\n render={JSON.stringify([similar, recommendations, history, group, listing, q])}\n filterKinds={kind ? [kind] : undefined}\n filterLanguage={listQuery?.display_language ?? history?.display_language ?? q.display_language ?? listQuery?.language ?? history?.language ?? q.language}\n />\n </ContentKitUiRoot>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"grid.js","names":[],"sources":["../../../src/components/content/grid.tsx"],"sourcesContent":["import { cn } from \"cn\";\nimport { useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode } from \"react\";\nimport type { ContentKitUiAppearance } from \"../../appearance.js\";\nimport type { ContentKitClient } from \"../../client/client.js\";\nimport type { AccessMode, ContentQuery, HistoryQuery, RailQuery, SearchQuery } from \"../../client/discovery.js\";\nimport type { Card, ListingSummary } from \"../../client/generated/wire.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { useContents, useExposure, useHistory, useRecommendations, useSearch, useSimilar, type UseRail } from \"../../react/discovery.js\";\nimport { useKinds } from \"../../react/groups.js\";\nimport type { UseList } from \"../../react/use-resource.js\";\nimport { ContentKitContext } from \"../../react/context.js\";\nimport { useContentScope } from \"../../react/use-resource.js\";\nimport { useNearViewport } from \"../../react/viewport.js\";\nimport { ContentKitUiRoot } from \"../../scope.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { Skeleton } from \"#ckui/ui/skeleton\";\nimport { contentError } from \"../social/parts.js\";\nimport { ContentFilterDialog } from \"./filter-dialog.js\";\nimport { useReleaseReveal } from \"./release-reveal.js\";\nimport { ContentSummaryTile } from \"./summary-tile.js\";\nimport { ContentCard, type ContentCardProps } from \"./card.js\";\nimport { PagedContentGrid, PagedSearchResults } from \"./paged-grid.js\";\n\nexport interface CardListProps extends Omit<ContentCardProps, \"card\" | \"onOpen\" | \"children\" | \"className\"> {\n /** Where the list is, for exposures and click attribution: \"home\", \"search\", \"similar\". */\n surface?: string;\n /** Loads the next page as the end nears, instead of a button. */\n infinite?: boolean;\n /** A card's entry instead of ContentCard. */\n renderCard?: (card: Card, position: number) => ReactNode;\n /** Shown when nothing matches. */\n empty?: ReactNode;\n pageSize?: number;\n client?: ContentKitClient;\n className?: string;\n appearance?: ContentKitUiAppearance;\n /** Collapse paid/locked cards into a counted tile, or hide them; default show. */\n locked?: LockedCards;\n /** Optional-filter summary tiles are on by default; hosts may suppress them in previews. */\n showFilteredSummary?: boolean;\n /** Show the collapsed locked tile only at this measured grid width. Default 0. */\n lockedSummaryMinColumns?: number;\n /** Limit rendered preview tiles without changing the matching selection or summary counts. */\n cardLimit?: number;\n /** Limit cards in mobile previews without mounting their images. */\n mobileCardLimit?: number;\n /** Host-specific nouns for summary controls. */\n summaryLabels?: { premium?: (count: number) => string; filtered?: (count: number) => string };\n /** Opt into a fluid grid, optionally with a desktop column ceiling. */\n grid?: CardGridLayout;\n /** Numbered pages with a shown range instead of load more or infinite scroll. */\n pagination?: \"pages\";\n /** The numbered page, from 1; with onPageChange the host keeps it (in its URL). */\n page?: number;\n onPageChange?: (page: number) => void;\n /** Each numbered page's link, for crawlers and opening in a new tab. */\n pageHref?: (page: number) => string;\n}\n\nconst GRID = \"grid grid-cols-[repeat(auto-fill,minmax(min(100%,10rem),1fr))] gap-x-4 gap-y-6\";\n\nexport interface CardGridLayout {\n /** Minimum desktop card width: CSS pixels or a CSS length such as clamp(...). Cards fill the available space. */\n minCardWidth: number | string;\n /** Maximum desktop columns. Omit to use all available width without a ceiling. */\n maxColumns?: number;\n /** Equal-width columns below the desktop breakpoint. Default 2. */\n mobileColumns?: number;\n}\n\n/** Shared by complete lists, release-day sections and grid-style previews. */\nexport function cardGridLayout(layout?: CardGridLayout): { className: string; style?: CSSProperties } {\n if (!layout) return { className: GRID };\n const width =\n typeof layout.minCardWidth === \"string\" ? layout.minCardWidth.trim() || \"160px\" : `${Number.isFinite(layout.minCardWidth) ? Math.max(1, layout.minCardWidth) : 160}px`;\n const columns = layout.mobileColumns !== undefined && Number.isFinite(layout.mobileColumns) ? Math.max(1, Math.floor(layout.mobileColumns)) : 2;\n const maximum = layout.maxColumns !== undefined && Number.isFinite(layout.maxColumns) ? Math.max(1, Math.floor(layout.maxColumns)) : undefined;\n const trackWidth = maximum === undefined ? width : `max(${width}, calc((100% - ${maximum - 1}rem) / ${maximum}))`;\n return {\n className:\n \"grid grid-cols-[repeat(var(--ckui-card-mobile-columns),minmax(0,1fr))] gap-x-4 gap-y-6 md:grid-cols-[repeat(auto-fill,minmax(min(100%,var(--ckui-card-min-width)),1fr))]\",\n style: { \"--ckui-card-min-width\": trackWidth, \"--ckui-card-mobile-columns\": columns } as CSSProperties,\n };\n}\n\n/** A list carries exact selection-wide counts when the API was asked for them. */\ntype SummaryList = UseList<Card> & { summary?: ListingSummary };\ntype GridProps = CardListProps & { list: SummaryList; render: string; filterKinds?: readonly string[]; filterLanguage?: string; horizontal?: boolean };\n\n/** A list's cards and summary controls share one responsive, animated grid. */\nexport function CardGrid(p: GridProps) {\n const { client, viewer, language } = useContentScope(p.client);\n const context = useContext(ContentKitContext);\n const [boundary, setBoundary] = useState({ client, viewer, language, access: context?.accessRevision, render: p.render, key: 0 });\n let session = boundary;\n if (boundary.client !== client || boundary.viewer !== viewer || boundary.language !== language || boundary.access !== context?.accessRevision || boundary.render !== p.render) {\n session = { client, viewer, language, access: context?.accessRevision, render: p.render, key: boundary.key + 1 };\n setBoundary(session);\n }\n return <CardGridBody key={session.key} {...p} />;\n}\n\nfunction CardGridBody({ list, render, filterKinds, filterLanguage, horizontal, ...p }: GridProps) {\n const m = useMessages();\n const { t } = m;\n const { kinds } = useKinds({ client: p.client });\n const [expanded, setExpanded] = useState(false);\n const [filtersOpen, setFiltersOpen] = useState(false);\n const filterTrigger = useRef<HTMLElement | null>(null);\n const [element, setElement] = useState<HTMLOListElement | null>(null);\n const [columns, setColumns] = useState(0);\n const [mobile, setMobile] = useState(() => globalThis.matchMedia?.(\"(max-width: 767px)\").matches ?? false);\n useLayoutEffect(() => {\n if (!element) return;\n const measure = () => {\n const tracks = getComputedStyle(element).gridTemplateColumns.trim();\n setColumns(tracks && tracks !== \"none\" ? tracks.split(/\\s+/).length : 0);\n setMobile(globalThis.matchMedia?.(\"(max-width: 767px)\").matches ?? false);\n };\n measure();\n const observer = typeof ResizeObserver === \"function\" ? new ResizeObserver(measure) : undefined;\n observer?.observe(element);\n addEventListener(\"resize\", measure);\n return () => {\n observer?.disconnect();\n removeEventListener(\"resize\", measure);\n };\n }, [element]);\n const lockedCount = list.summary?.locked_count ?? 0;\n const filteredCount = p.showFilteredSummary === false ? 0 : (list.summary?.filtered_count ?? 0);\n const collapse = p.locked === \"collapse\" && !expanded && lockedCount > 0;\n const lockedTile = collapse && lockedCount > 0 && columns >= Math.max(0, p.lockedSummaryMinColumns ?? 0);\n const entries = useMemo(() => {\n const result: ({ key: string; card: Card; position: number } | { key: string; premium: true; card?: Card })[] = [];\n let inserted = false;\n for (const [i, card] of list.items.entries()) {\n if (isLockedCard(card) && (collapse || p.locked === \"hide\")) {\n if (lockedTile && !inserted) {\n result.push({ key: \"premium-summary\", premium: true, card });\n inserted = true;\n }\n continue;\n }\n result.push({ key: card.id, card, position: i + 1 });\n }\n if (lockedTile && !inserted) result.push({ key: \"premium-summary\", premium: true });\n const limit = mobile && p.mobileCardLimit !== undefined ? p.mobileCardLimit : p.cardLimit;\n return limit !== undefined && Number.isFinite(limit) ? result.slice(0, Math.max(0, Math.floor(limit))) : result;\n }, [list.items, collapse, p.locked, lockedTile, mobile, p.mobileCardLimit, p.cardLimit]);\n const shown = useMemo(() => entries.flatMap((entry) => (\"premium\" in entry ? [] : [{ ...entry.card, position: entry.position }])), [entries]);\n const exposure = useExposure(shown, { surface: p.surface ?? \"list\", render, client: p.client });\n const [sentinel, near] = useNearViewport({ margin: \"600px 0px\", leaveMargin: \"1200px 0px\" });\n const { hasMore, loadingMore, loadMore, error } = list;\n useEffect(() => {\n if (p.infinite && near && hasMore && !loadingMore && !error) void loadMore();\n }, [p.infinite, near, hasMore, loadingMore, loadMore, error]);\n const { grid: animationGrid, prepare } = useReleaseReveal(entries.map((entry) => entry.key).join(\"\\0\"));\n const grid = useCallback(\n (node: HTMLOListElement | null) => {\n animationGrid.current = node;\n setElement(node);\n },\n [animationGrid],\n );\n const layout: ReturnType<typeof cardGridLayout> = horizontal\n ? { className: \"relative flex snap-x gap-4 overflow-x-auto pb-2 [&>li]:w-36 [&>li]:shrink-0 [&>li]:snap-start sm:[&>li]:w-44\" }\n : cardGridLayout(p.grid);\n const lowerBound = list.summary?.truncated ? \"≥ \" : \"\";\n const premiumLabel = lowerBound + (p.summaryLabels?.premium?.(lockedCount) ?? m.plural(\"contents.lockedShow\", lockedCount));\n const filteredLabel = lowerBound + (p.summaryLabels?.filtered?.(filteredCount) ?? m.plural(\"releases.filteredMore\", filteredCount));\n const showGrid = entries.length > 0 || filteredCount > 0 || (collapse && lockedCount > 0);\n return (\n <ContentKitUiRoot appearance={p.appearance} className={cn(\"grid gap-4 text-sm\", p.className)} data-ckui=\"content-grid\" aria-busy={list.loading}>\n {list.loading && !list.items.length ? (\n <ol aria-hidden className={layout.className} style={layout.style}>\n {Array.from({ length: 8 }, (_, i) => (\n <li key={i}>\n <Skeleton\n className={p.aspectRatio === undefined ? (p.shape === \"landscape\" ? \"aspect-video w-full\" : \"aspect-[3/4] w-full\") : \"w-full\"}\n style={p.aspectRatio === undefined ? undefined : { aspectRatio: p.aspectRatio }}\n />\n </li>\n ))}\n </ol>\n ) : list.error && !list.items.length ? (\n <div role=\"alert\" className=\"grid justify-items-start gap-2\">\n <p className=\"text-destructive\">{contentError(m, list.error)}</p>\n <Button size=\"sm\" variant=\"outline\" onClick={list.reload}>\n {t(\"common.retry\")}\n </Button>\n </div>\n ) : !showGrid ? (\n <div className=\"text-muted-foreground\" role=\"status\">\n {p.empty ?? t(\"contents.empty\")}\n </div>\n ) : (\n <ol ref={grid} tabIndex={-1} className={layout.className} style={layout.style}>\n {entries.map((entry) =>\n \"premium\" in entry ? (\n <ContentSummaryTile\n key={entry.key}\n tileKey={entry.key}\n kind=\"premium\"\n contentKind={filterKinds?.[0] ?? entry.card?.kind}\n preview={entry.card}\n open\n cardProps={p}\n label={premiumLabel}\n onClick={(event) => {\n prepare(event.detail === 0);\n setExpanded(true);\n }}\n />\n ) : (\n <li key={entry.key} data-release-key={entry.key} ref={exposure.track(entry.card.id, entry.position)}>\n {p.renderCard ? (\n p.renderCard(entry.card, entry.position)\n ) : (\n <ContentCard\n card={entry.card}\n client={p.client}\n href={p.href}\n shape={p.shape}\n aspectRatio={p.aspectRatio}\n titlePosition={p.titlePosition}\n loadMedia={p.loadMedia}\n groupKinds={p.groupKinds}\n chips={p.chips}\n chipOverflow={p.chipOverflow}\n chipFit={p.chipFit}\n filterEntity={p.filterEntity}\n entityStyle={p.entityStyle}\n entityLayout={p.entityLayout}\n metadata={p.metadata}\n showCounts={p.showCounts}\n tiers={p.tiers ?? kinds?.tiers}\n labels={p.labels}\n owner={p.owner}\n ownerHref={p.ownerHref}\n decorate={p.decorate}\n onOpen={() => exposure.click(entry.card.id, entry.position)}\n />\n )}\n </li>\n ),\n )}\n {filteredCount > 0 && (\n <ContentSummaryTile\n tileKey=\"filtered-summary\"\n kind=\"filtered\"\n contentKind={filterKinds?.[0] ?? list.items[0]?.kind}\n open\n cardProps={p}\n label={filteredLabel}\n onClick={(event) => {\n filterTrigger.current = event.currentTarget;\n setFiltersOpen(true);\n }}\n />\n )}\n </ol>\n )}\n {list.hasMore && (\n <div ref={sentinel} className=\"grid justify-items-center gap-2\">\n {list.error && list.items.length > 0 && (\n <p role=\"alert\" className=\"text-destructive\">\n {contentError(m, list.error)}\n </p>\n )}\n <Button variant=\"outline\" size=\"sm\" disabled={list.loadingMore} onClick={() => void list.loadMore()}>\n {list.loadingMore ? t(\"contents.loading\") : list.error ? t(\"common.retry\") : t(\"contents.loadMore\")}\n </Button>\n </div>\n )}\n <ContentFilterDialog\n open={filtersOpen}\n onOpenChange={setFiltersOpen}\n returnFocus={() => (filterTrigger.current?.isConnected ? filterTrigger.current : element)}\n client={p.client}\n kinds={filterKinds}\n language={filterLanguage}\n counts={list.summary?.filtered_entities}\n countsLowerBound={list.summary?.truncated}\n appearance={p.appearance}\n />\n </ContentKitUiRoot>\n );\n}\n\n/**\n * What a list does with cards the reader doesn't open: shows them marked\n * (show), leaves them out (hide), or replaces them with a counted tile\n * that reveals the cached previews in place (collapse).\n */\nexport type LockedCards = \"show\" | \"hide\" | \"collapse\";\n\n/** Settle locked-card admission before pagination, retaining explicit reader modes otherwise. */\nexport function cardListMode(locked: LockedCards | undefined, mode?: AccessMode): AccessMode | undefined {\n return locked === \"hide\" ? \"hide\" : locked === \"collapse\" ? \"lock\" : mode;\n}\n\nconst LOCKED_LEVELS: readonly string[] = [\"tier\", \"group\", \"ppv\", \"group_ppv\"];\nconst isLockedCard = (card: Card) => !card.access.allowed && !card.access.unknown && LOCKED_LEVELS.includes(card.access.level);\n\n/** Contents as cards (GET /v1/contents): any sort and filter, paged by load more, infinite scroll or numbered pages. */\nexport function ContentGrid(p: CardListProps & { query: ContentQuery }) {\n return p.pagination === \"pages\" ? <PagedContentGrid {...p} /> : <CursorContentGrid {...p} />;\n}\n\nfunction CursorContentGrid({ query, locked = \"show\", ...p }: CardListProps & { query: ContentQuery }) {\n const q = useMemo<ContentQuery>(\n () => ({\n ...query,\n summary: query.summary ?? true,\n limit: query.limit ?? p.pageSize,\n mode: cardListMode(locked, query.mode),\n }),\n [query, p.pageSize, locked],\n );\n const list = useContents(q, { client: p.client });\n return (\n <CardGrid\n {...p}\n locked={locked}\n list={list}\n render={JSON.stringify(q)}\n filterKinds={query.kind ? [query.kind] : undefined}\n filterLanguage={query.display_language ?? query.language}\n />\n );\n}\n\n/** Search results as cards; nothing until the query has text. */\nexport function SearchResults(p: CardListProps & { query: SearchQuery }) {\n return p.pagination === \"pages\" ? <PagedSearchResults {...p} /> : <CursorSearchResults {...p} />;\n}\n\nfunction CursorSearchResults({ query, ...p }: CardListProps & { query: SearchQuery }) {\n const { t } = useMessages();\n const q = useMemo(\n () => ({ ...query, mode: cardListMode(p.locked, query.mode), summary: query.summary ?? true, limit: query.limit ?? p.pageSize }),\n [query, p.pageSize, p.locked],\n );\n const list = useSearch(q, { client: p.client });\n if (!query.q.trim()) return null;\n return (\n <CardGrid\n surface=\"search\"\n empty={t(\"contents.noResults\", { q: query.q.trim() })}\n {...p}\n list={list}\n render={JSON.stringify(q)}\n filterKinds={query.kind ? [query.kind] : undefined}\n filterLanguage={query.display_language ?? query.language}\n />\n );\n}\n\nexport { ContentHistory } from \"./history.js\";\n\nexport interface ContentRailProps extends Omit<CardListProps, \"infinite\" | \"empty\"> {\n /** The rail's heading. */\n title: ReactNode;\n /** Contents like this one. */\n similar?: string;\n /** For the signed-in reader. */\n recommendations?: boolean;\n /** The reader's history: { status: \"in_progress\" } is a continue-watching rail. */\n history?: HistoryQuery;\n /** An ordered group's members in its order: a featured rail (its windows apply). */\n group?: string;\n /** Any list: a sort and filters. */\n list?: ContentQuery;\n /** Filters and reader options of a similar or recommended rail. */\n query?: RailQuery;\n /** A link beside the heading, e.g. to the whole list. */\n more?: ReactNode;\n}\n\n/**\n * A horizontal row of contents: similar, recommended, the reader's history,\n * an ordered group's members or any list. It hides itself when it has none or\n * the site runs without what it needs.\n */\nexport function ContentRail({ title, similar, recommendations, history, group, list: listQuery, query = {}, more, ...p }: ContentRailProps) {\n const limit = query.limit ?? p.pageSize ?? 12;\n const q = useMemo(() => ({ ...query, mode: cardListMode(p.locked, query.mode), summary: query.summary ?? true, limit }), [query, limit, p.locked]);\n const listing = useMemo(\n () =>\n listQuery\n ? { ...listQuery, mode: cardListMode(p.locked, listQuery.mode), summary: listQuery.summary ?? true, limit: listQuery.limit ?? limit }\n : group\n ? { groups: [group], sort: \"position\" as const, mode: cardListMode(p.locked), summary: true, limit }\n : null,\n [listQuery, group, limit, p.locked],\n );\n const like = useSimilar(recommendations || history || listing ? null : similar, q, { client: p.client });\n const mine = useRecommendations(recommendations ? q : null, { client: p.client });\n const seen = useHistory(history ? { ...history, mode: cardListMode(p.locked, history.mode), summary: history.summary ?? true, limit: history.limit ?? limit } : null, {\n client: p.client,\n });\n const listed = useContents(listing, { client: p.client });\n const rail: UseRail = recommendations\n ? mine\n : history || listing\n ? (() => {\n const l = history ? seen : listed;\n return { items: l.items, summary: l.summary, loading: l.loading, error: l.error, unavailable: l.error?.code === \"not_configured\", reload: l.reload };\n })()\n : like;\n const surface = p.surface ?? (recommendations ? \"recommendations\" : history ? \"history\" : group ? \"featured\" : listing ? \"list\" : \"similar\");\n const source = similar || recommendations || history || group || listing;\n if (!source || rail.unavailable || (!rail.loading && !rail.items.length && !rail.summary?.filtered_count && !rail.summary?.locked_count)) return null;\n const list: SummaryList = { ...rail, loadingMore: false, hasMore: false, loadMore: async () => {} };\n const kind = listQuery?.kind ?? history?.kind ?? q.kind;\n return (\n <ContentKitUiRoot appearance={p.appearance} className={cn(\"grid gap-3 text-sm\", p.className)} data-ckui=\"content-rail\" data-surface={surface}>\n <div className=\"flex items-baseline justify-between gap-2\">\n <h2 className=\"text-base font-semibold\">{title}</h2>\n {more}\n </div>\n <CardGrid\n {...p}\n className={undefined}\n surface={surface}\n horizontal={!p.grid}\n list={list}\n render={JSON.stringify([similar, recommendations, history, group, listing, q])}\n filterKinds={kind ? [kind] : undefined}\n filterLanguage={listQuery?.display_language ?? history?.display_language ?? q.display_language ?? listQuery?.language ?? history?.language ?? q.language}\n />\n </ContentKitUiRoot>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,91 +1,111 @@
|
|
|
1
1
|
import { useMessages as e } from "../../i18n/context.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { ContentFilterDialog as
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
2
|
+
import { useKinds as t } from "../../react/groups.js";
|
|
3
|
+
import { Button as n } from "../../ui/button.js";
|
|
4
|
+
import { formatDate as r, relativeTime as i, useAction as a } from "../social/parts.js";
|
|
5
|
+
import { useHistory as o } from "../../react/discovery.js";
|
|
6
|
+
import { ContentFilterDialog as s } from "./filter-dialog.js";
|
|
7
|
+
import { ContentCard as c } from "./card.js";
|
|
8
|
+
import { CardGrid as l } from "./grid.js";
|
|
9
|
+
import { useMemo as u, useRef as d, useState as f } from "react";
|
|
10
|
+
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
10
11
|
//#region src/components/content/history.tsx
|
|
11
|
-
function
|
|
12
|
-
let { t:
|
|
13
|
-
...
|
|
12
|
+
function h({ query: r = {}, ...i }) {
|
|
13
|
+
let { t: h } = e(), _ = u(() => ({
|
|
14
|
+
...r,
|
|
14
15
|
summary: !0,
|
|
15
|
-
mode:
|
|
16
|
-
limit:
|
|
16
|
+
mode: i.locked === "collapse" ? "lock" : i.locked === "hide" ? "hide" : r.mode,
|
|
17
|
+
limit: r.limit ?? i.pageSize
|
|
17
18
|
}), [
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
]),
|
|
22
|
-
return /* @__PURE__ */
|
|
19
|
+
r,
|
|
20
|
+
i.pageSize,
|
|
21
|
+
i.locked
|
|
22
|
+
]), v = o(_, { client: i.client }), y = a("history.forget"), { kinds: b } = t({ client: i.client }), [x, S] = f(!1), C = d(null);
|
|
23
|
+
return /* @__PURE__ */ m("div", {
|
|
23
24
|
className: "grid gap-3",
|
|
24
25
|
"data-ckui": "content-history",
|
|
25
26
|
children: [
|
|
26
|
-
|
|
27
|
+
v.items.length > 0 && /* @__PURE__ */ p(n, {
|
|
27
28
|
size: "sm",
|
|
28
29
|
variant: "outline",
|
|
29
30
|
className: "justify-self-end",
|
|
30
|
-
disabled:
|
|
31
|
-
onClick: () => void
|
|
32
|
-
children:
|
|
31
|
+
disabled: y.pending,
|
|
32
|
+
onClick: () => void y.run(() => v.forget(r.kind ? { kind: r.kind } : {})),
|
|
33
|
+
children: h("contents.clearHistory")
|
|
33
34
|
}),
|
|
34
|
-
|
|
35
|
-
ref:
|
|
35
|
+
v.filterSummaryUnknown && i.showFilteredSummary !== !1 && /* @__PURE__ */ p(n, {
|
|
36
|
+
ref: C,
|
|
36
37
|
variant: "outline",
|
|
37
38
|
className: "justify-self-start",
|
|
38
|
-
onClick: () =>
|
|
39
|
-
children:
|
|
39
|
+
onClick: () => S(!0),
|
|
40
|
+
children: h("releases.manageFilters")
|
|
40
41
|
}),
|
|
41
|
-
/* @__PURE__ */
|
|
42
|
-
client:
|
|
43
|
-
language:
|
|
44
|
-
open:
|
|
45
|
-
onOpenChange:
|
|
46
|
-
returnFocus: () =>
|
|
42
|
+
/* @__PURE__ */ p(s, {
|
|
43
|
+
client: i.client,
|
|
44
|
+
language: _.language,
|
|
45
|
+
open: x,
|
|
46
|
+
onOpenChange: S,
|
|
47
|
+
returnFocus: () => C.current
|
|
47
48
|
}),
|
|
48
|
-
/* @__PURE__ */
|
|
49
|
+
/* @__PURE__ */ p(l, {
|
|
49
50
|
surface: "history",
|
|
50
|
-
empty:
|
|
51
|
-
...
|
|
52
|
-
list:
|
|
53
|
-
render: JSON.stringify(
|
|
54
|
-
filterLanguage:
|
|
55
|
-
renderCard:
|
|
51
|
+
empty: h("contents.historyEmpty"),
|
|
52
|
+
...i,
|
|
53
|
+
list: v,
|
|
54
|
+
render: JSON.stringify(_),
|
|
55
|
+
filterLanguage: _.language,
|
|
56
|
+
renderCard: i.renderCard ?? ((e) => /* @__PURE__ */ m(c, {
|
|
56
57
|
card: e,
|
|
57
|
-
client:
|
|
58
|
-
href:
|
|
59
|
-
shape:
|
|
60
|
-
aspectRatio:
|
|
61
|
-
titlePosition:
|
|
62
|
-
loadMedia:
|
|
63
|
-
groupKinds:
|
|
64
|
-
chips:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
58
|
+
client: i.client,
|
|
59
|
+
href: i.href,
|
|
60
|
+
shape: i.shape,
|
|
61
|
+
aspectRatio: i.aspectRatio,
|
|
62
|
+
titlePosition: i.titlePosition,
|
|
63
|
+
loadMedia: i.loadMedia,
|
|
64
|
+
groupKinds: i.groupKinds,
|
|
65
|
+
chips: i.chips,
|
|
66
|
+
chipOverflow: i.chipOverflow,
|
|
67
|
+
chipFit: i.chipFit,
|
|
68
|
+
filterEntity: i.filterEntity,
|
|
69
|
+
entityStyle: i.entityStyle,
|
|
70
|
+
entityLayout: i.entityLayout,
|
|
71
|
+
metadata: i.metadata,
|
|
72
|
+
showCounts: i.showCounts,
|
|
73
|
+
tiers: i.tiers,
|
|
74
|
+
labels: i.labels,
|
|
75
|
+
owner: i.owner,
|
|
76
|
+
ownerHref: i.ownerHref,
|
|
77
|
+
decorate: i.decorate,
|
|
78
|
+
children: [/* @__PURE__ */ p(g, {
|
|
79
|
+
card: e,
|
|
80
|
+
presentation: b?.kinds[e.kind]?.presentation
|
|
81
|
+
}), /* @__PURE__ */ p(n, {
|
|
76
82
|
size: "xs",
|
|
77
83
|
variant: "ghost",
|
|
78
84
|
className: "justify-self-start",
|
|
79
|
-
disabled:
|
|
80
|
-
onClick: () => void
|
|
81
|
-
children:
|
|
82
|
-
})
|
|
85
|
+
disabled: y.pending,
|
|
86
|
+
onClick: () => void y.run(() => v.forget({ content_id: e.id })),
|
|
87
|
+
children: h("contents.removeFromHistory")
|
|
88
|
+
})]
|
|
83
89
|
}))
|
|
84
90
|
})
|
|
85
91
|
]
|
|
86
92
|
});
|
|
87
93
|
}
|
|
94
|
+
function g({ card: t, presentation: n }) {
|
|
95
|
+
let a = e(), o = t.viewer;
|
|
96
|
+
if (!o) return null;
|
|
97
|
+
let s = o.completed ? o.progress_max : Math.min(o.progress, o.progress_max), c = o.progress_max > 0 && n === "reader" ? a.plural("contents.pageProgress", o.progress_max, { progress: s }) : o.progress_max > 0 && n === "player" ? a.plural("contents.minuteProgress", Math.max(1, Math.round(o.progress_max / 60)), { progress: Math.round(s / 60) }) : null;
|
|
98
|
+
return !o.last_read_at && !c ? null : /* @__PURE__ */ m("p", {
|
|
99
|
+
className: "flex flex-wrap gap-x-2 text-xs tabular-nums text-muted-foreground",
|
|
100
|
+
"data-ckui": "history-progress",
|
|
101
|
+
children: [o.last_read_at && /* @__PURE__ */ p("time", {
|
|
102
|
+
dateTime: o.last_read_at,
|
|
103
|
+
title: r(a, o.last_read_at),
|
|
104
|
+
children: a.t(n === "player" ? "contents.watchedAgo" : "contents.readAgo", { time: i(a, o.last_read_at) })
|
|
105
|
+
}), c && /* @__PURE__ */ p("span", { children: c })]
|
|
106
|
+
});
|
|
107
|
+
}
|
|
88
108
|
//#endregion
|
|
89
|
-
export {
|
|
109
|
+
export { h as ContentHistory };
|
|
90
110
|
|
|
91
111
|
//# sourceMappingURL=history.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"history.js","names":[],"sources":["../../../src/components/content/history.tsx"],"sourcesContent":["import { useMemo, useRef, useState } from \"react\";\nimport type { HistoryQuery } from \"../../client/discovery.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { useHistory } from \"../../react/discovery.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { useAction } from \"../social/parts.js\";\nimport { ContentFilterDialog } from \"./filter-dialog.js\";\nimport { ContentCard } from \"./card.js\";\nimport { CardGrid, type CardListProps } from \"./grid.js\";\n\n/** Account history or this browser's guest history, each removable, with a clear-all. */\nexport function ContentHistory({ query = {}, ...p }: CardListProps & { query?: HistoryQuery }) {\n const { t } = useMessages();\n const q = useMemo(() => ({ ...query, summary: true, mode: p.locked === \"collapse\" ? \"lock\" as const : p.locked === \"hide\" ? \"hide\" as const : query.mode, limit: query.limit ?? p.pageSize }), [query, p.pageSize, p.locked]);\n const list = useHistory(q, { client: p.client });\n const forget = useAction(\"history.forget\");\n const [filtersOpen, setFiltersOpen] = useState(false);\n const filterTrigger = useRef<HTMLButtonElement | null>(null);\n return (\n <div className=\"grid gap-3\" data-ckui=\"content-history\">\n {list.items.length > 0 && (\n <Button size=\"sm\" variant=\"outline\" className=\"justify-self-end\" disabled={forget.pending} onClick={() => void forget.run(() => list.forget(query.kind ? { kind: query.kind } : {}))}>\n {t(\"contents.clearHistory\")}\n </Button>\n )}\n {list.filterSummaryUnknown && p.showFilteredSummary !== false && (\n <Button ref={filterTrigger} variant=\"outline\" className=\"justify-self-start\" onClick={() => setFiltersOpen(true)}>{t(\"releases.manageFilters\")}</Button>\n )}\n <ContentFilterDialog client={p.client} language={q.language} open={filtersOpen} onOpenChange={setFiltersOpen} returnFocus={() => filterTrigger.current} />\n <CardGrid\n surface=\"history\"\n empty={t(\"contents.historyEmpty\")}\n {...p}\n list={list}\n render={JSON.stringify(q)}\n filterLanguage={q.language}\n renderCard={\n p.renderCard ??\n ((card) => (\n <ContentCard\n card={card}\n client={p.client}\n href={p.href}\n shape={p.shape}\n aspectRatio={p.aspectRatio}\n titlePosition={p.titlePosition}\n loadMedia={p.loadMedia}\n groupKinds={p.groupKinds}\n chips={p.chips}\n filterEntity={p.filterEntity}\n entityStyle={p.entityStyle}\n entityLayout={p.entityLayout}\n metadata={p.metadata}\n showCounts={p.showCounts}\n tiers={p.tiers}\n labels={p.labels}\n owner={p.owner}\n ownerHref={p.ownerHref}\n decorate={p.decorate}\n >\n <Button size=\"xs\" variant=\"ghost\" className=\"justify-self-start\" disabled={forget.pending} onClick={() => void forget.run(() => list.forget({ content_id: card.id }))}>\n {t(\"contents.removeFromHistory\")}\n </Button>\n </ContentCard>\n ))\n }\n />\n </div>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"history.js","names":[],"sources":["../../../src/components/content/history.tsx"],"sourcesContent":["import { useMemo, useRef, useState } from \"react\";\nimport type { Card } from \"../../client/generated/wire.js\";\nimport type { HistoryQuery } from \"../../client/discovery.js\";\nimport { useMessages } from \"../../i18n/context.js\";\nimport { useHistory } from \"../../react/discovery.js\";\nimport { useKinds } from \"../../react/groups.js\";\nimport { Button } from \"#ckui/ui/button\";\nimport { formatDate, relativeTime, useAction } from \"../social/parts.js\";\nimport { ContentFilterDialog } from \"./filter-dialog.js\";\nimport { ContentCard } from \"./card.js\";\nimport { CardGrid, type CardListProps } from \"./grid.js\";\n\n/** Account history or this browser's guest history, each removable, with a clear-all. */\nexport function ContentHistory({ query = {}, ...p }: CardListProps & { query?: HistoryQuery }) {\n const { t } = useMessages();\n const q = useMemo(() => ({ ...query, summary: true, mode: p.locked === \"collapse\" ? \"lock\" as const : p.locked === \"hide\" ? \"hide\" as const : query.mode, limit: query.limit ?? p.pageSize }), [query, p.pageSize, p.locked]);\n const list = useHistory(q, { client: p.client });\n const forget = useAction(\"history.forget\");\n const { kinds } = useKinds({ client: p.client });\n const [filtersOpen, setFiltersOpen] = useState(false);\n const filterTrigger = useRef<HTMLButtonElement | null>(null);\n return (\n <div className=\"grid gap-3\" data-ckui=\"content-history\">\n {list.items.length > 0 && (\n <Button size=\"sm\" variant=\"outline\" className=\"justify-self-end\" disabled={forget.pending} onClick={() => void forget.run(() => list.forget(query.kind ? { kind: query.kind } : {}))}>\n {t(\"contents.clearHistory\")}\n </Button>\n )}\n {list.filterSummaryUnknown && p.showFilteredSummary !== false && (\n <Button ref={filterTrigger} variant=\"outline\" className=\"justify-self-start\" onClick={() => setFiltersOpen(true)}>{t(\"releases.manageFilters\")}</Button>\n )}\n <ContentFilterDialog client={p.client} language={q.language} open={filtersOpen} onOpenChange={setFiltersOpen} returnFocus={() => filterTrigger.current} />\n <CardGrid\n surface=\"history\"\n empty={t(\"contents.historyEmpty\")}\n {...p}\n list={list}\n render={JSON.stringify(q)}\n filterLanguage={q.language}\n renderCard={\n p.renderCard ??\n ((card) => (\n <ContentCard\n card={card}\n client={p.client}\n href={p.href}\n shape={p.shape}\n aspectRatio={p.aspectRatio}\n titlePosition={p.titlePosition}\n loadMedia={p.loadMedia}\n groupKinds={p.groupKinds}\n chips={p.chips}\n chipOverflow={p.chipOverflow}\n chipFit={p.chipFit}\n filterEntity={p.filterEntity}\n entityStyle={p.entityStyle}\n entityLayout={p.entityLayout}\n metadata={p.metadata}\n showCounts={p.showCounts}\n tiers={p.tiers}\n labels={p.labels}\n owner={p.owner}\n ownerHref={p.ownerHref}\n decorate={p.decorate}\n >\n <HistoryProgress card={card} presentation={kinds?.kinds[card.kind]?.presentation} />\n <Button size=\"xs\" variant=\"ghost\" className=\"justify-self-start\" disabled={forget.pending} onClick={() => void forget.run(() => list.forget({ content_id: card.id }))}>\n {t(\"contents.removeFromHistory\")}\n </Button>\n </ContentCard>\n ))\n }\n />\n </div>\n );\n}\n\n/** When the reader last read or watched it, and how far: pages for a reader, minutes for a player. */\nfunction HistoryProgress({ card, presentation }: { card: Card; presentation?: string }) {\n const m = useMessages();\n const v = card.viewer;\n if (!v) return null;\n const done = v.completed ? v.progress_max : Math.min(v.progress, v.progress_max);\n const amount =\n v.progress_max > 0 && presentation === \"reader\"\n ? m.plural(\"contents.pageProgress\", v.progress_max, { progress: done })\n : v.progress_max > 0 && presentation === \"player\"\n ? m.plural(\"contents.minuteProgress\", Math.max(1, Math.round(v.progress_max / 60)), { progress: Math.round(done / 60) })\n : null;\n if (!v.last_read_at && !amount) return null;\n return (\n <p className=\"flex flex-wrap gap-x-2 text-xs tabular-nums text-muted-foreground\" data-ckui=\"history-progress\">\n {v.last_read_at && (\n <time dateTime={v.last_read_at} title={formatDate(m, v.last_read_at)}>\n {m.t(presentation === \"player\" ? \"contents.watchedAgo\" : \"contents.readAgo\", { time: relativeTime(m, v.last_read_at) })}\n </time>\n )}\n {amount && <span>{amount}</span>}\n </p>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ContentCard, OwnerChip, PostCard, lockLabel, type CardMetadata, type ContentCardProps, type PostCardProps } from './card.js';
|
|
1
|
+
export { CardStatusBadges, ContentCard, OwnerChip, PostCard, cardStatus, lockLabel, type CardMetadata, type CardStatus, type ContentCardProps, type PostCardProps } from './card.js';
|
|
2
2
|
export { cardGridLayout, CardGrid, ContentGrid, ContentHistory, ContentRail, SearchResults, type CardGridLayout, type CardListProps, type ContentRailProps, type LockedCards } from './grid.js';
|
|
3
3
|
export { DailyReleases, type DailyReleasesProps } from './daily-releases.js';
|
|
4
4
|
export { ReleaseDatePicker, isReleaseDate, localReleaseDate, type ReleaseDatePickerProps } from './release-date-picker.js';
|
|
@@ -7,10 +7,12 @@ export { SearchBox, type SearchBoxProps } from './search.js';
|
|
|
7
7
|
export { ReaderSettings, type ReaderSettingsProps } from './reader-settings.js';
|
|
8
8
|
export { ContentFilterDialog, type ContentFilterDialogProps } from './filter-dialog.js';
|
|
9
9
|
export { ContentFilterSettings, ReleaseDateIndex, type ContentFilterSettingsProps, type ContentFilterCount, type ReleaseDateIndexProps } from './filters.js';
|
|
10
|
-
export { ContentListing, sortLabel, type ContentListingProps } from './listing.js';
|
|
11
|
-
export {
|
|
10
|
+
export { ContentListing, SortMenu, sortLabel, type ContentListingProps, type SortMenuProps } from './listing.js';
|
|
11
|
+
export { Pagination, pageWindow, type PaginationProps } from './pagination.js';
|
|
12
|
+
export { LanguageFallbackNotice, Paywall, VersionPicker, priceLabel, useVersionMenuItems, type LanguageFallbackNoticeProps, type PaywallProps, type VersionMenuOptions, type VersionPickerProps } from './paywall.js';
|
|
12
13
|
export { AccessEditor, ContentDetailsEditor, ContentSections, SegmentsEditor, VersionCover, VersionsEditor, versionLabel } from './editors.js';
|
|
13
14
|
export { OfferFields } from './offer-fields.js';
|
|
14
15
|
export { ReaderStats, type ReaderStatsProps } from './reader-stats.js';
|
|
15
16
|
export { VersionDownloadButton, type VersionDownloadButtonProps } from './download-button.js';
|
|
16
17
|
export { ContentFavorites } from './favorites.js';
|
|
18
|
+
export { PostList, excerpt, type PostListProps } from './post-list.js';
|