@canopy-iiif/app 0.12.4 → 0.12.6
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/lib/build/iiif.js +15 -1
- package/lib/build/mdx.js +101 -0
- package/lib/build/pages.js +7 -1
- package/lib/build/runtimes.js +1 -0
- package/lib/components/timeline-runtime.js +80 -0
- package/lib/search/search-form-runtime.js +1 -1
- package/package.json +1 -1
- package/ui/dist/index.mjs +732 -67
- package/ui/dist/index.mjs.map +4 -4
- package/ui/dist/server.mjs +904 -61
- package/ui/dist/server.mjs.map +4 -4
- package/ui/styles/components/_timeline.scss +294 -0
- package/ui/styles/components/index.scss +1 -0
- package/ui/styles/index.css +269 -0
package/ui/dist/server.mjs
CHANGED
|
@@ -2062,8 +2062,51 @@ function CanopyFooter({ className = "", children }) {
|
|
|
2062
2062
|
return /* @__PURE__ */ React20.createElement("footer", { className: footerClassName }, /* @__PURE__ */ React20.createElement("div", { className: "canopy-footer__inner" }, children));
|
|
2063
2063
|
}
|
|
2064
2064
|
|
|
2065
|
-
// ui/src/layout/
|
|
2065
|
+
// ui/src/layout/TeaserCard.jsx
|
|
2066
2066
|
import React21 from "react";
|
|
2067
|
+
function TeaserCard({
|
|
2068
|
+
href = "",
|
|
2069
|
+
title = "",
|
|
2070
|
+
metadata = [],
|
|
2071
|
+
summary = "",
|
|
2072
|
+
thumbnail = null,
|
|
2073
|
+
type = "work",
|
|
2074
|
+
className = "",
|
|
2075
|
+
...rest
|
|
2076
|
+
}) {
|
|
2077
|
+
const Tag = href ? "a" : "div";
|
|
2078
|
+
const classes = [
|
|
2079
|
+
"canopy-card",
|
|
2080
|
+
"canopy-card--teaser",
|
|
2081
|
+
"canopy-search-teaser__item",
|
|
2082
|
+
"canopy-teaser-card",
|
|
2083
|
+
className
|
|
2084
|
+
].filter(Boolean).join(" ");
|
|
2085
|
+
const showThumb = type === "work" && thumbnail;
|
|
2086
|
+
const metaLine = (Array.isArray(metadata) && metadata.length ? metadata.filter(Boolean) : summary ? [summary] : []).filter(Boolean).slice(0, 2).join(" \u2022 ");
|
|
2087
|
+
return /* @__PURE__ */ React21.createElement(
|
|
2088
|
+
Tag,
|
|
2089
|
+
{
|
|
2090
|
+
className: classes,
|
|
2091
|
+
href: href || void 0,
|
|
2092
|
+
"data-canopy-item": href ? "" : void 0,
|
|
2093
|
+
...rest
|
|
2094
|
+
},
|
|
2095
|
+
showThumb ? /* @__PURE__ */ React21.createElement("div", { className: "canopy-search-teaser__thumb" }, /* @__PURE__ */ React21.createElement(
|
|
2096
|
+
"img",
|
|
2097
|
+
{
|
|
2098
|
+
src: thumbnail,
|
|
2099
|
+
alt: "",
|
|
2100
|
+
loading: "lazy",
|
|
2101
|
+
className: "canopy-search-teaser__thumb-img"
|
|
2102
|
+
}
|
|
2103
|
+
)) : null,
|
|
2104
|
+
/* @__PURE__ */ React21.createElement("div", { className: "canopy-search-teaser__text" }, /* @__PURE__ */ React21.createElement("span", { className: "canopy-search-teaser__title" }, title || href || "Untitled"), metaLine ? /* @__PURE__ */ React21.createElement("span", { className: "canopy-search-teaser__meta" }, metaLine) : null)
|
|
2105
|
+
);
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2108
|
+
// ui/src/layout/Container.jsx
|
|
2109
|
+
import React22 from "react";
|
|
2067
2110
|
function Container({
|
|
2068
2111
|
className = "",
|
|
2069
2112
|
variant = "content",
|
|
@@ -2072,7 +2115,7 @@ function Container({
|
|
|
2072
2115
|
}) {
|
|
2073
2116
|
const variantClass = variant === "wide" ? "max-w-wide" : "max-w-content";
|
|
2074
2117
|
const classes = ["mx-auto", variantClass, "w-full", className].filter(Boolean).join(" ");
|
|
2075
|
-
return /* @__PURE__ */
|
|
2118
|
+
return /* @__PURE__ */ React22.createElement(
|
|
2076
2119
|
"div",
|
|
2077
2120
|
{
|
|
2078
2121
|
className: classes,
|
|
@@ -2084,11 +2127,11 @@ function Container({
|
|
|
2084
2127
|
}
|
|
2085
2128
|
|
|
2086
2129
|
// ui/src/content/ReferencedItems.jsx
|
|
2087
|
-
import
|
|
2130
|
+
import React24 from "react";
|
|
2088
2131
|
import navigationHelpers4 from "@canopy-iiif/app/lib/components/navigation.js";
|
|
2089
2132
|
|
|
2090
2133
|
// ui/src/layout/Card.jsx
|
|
2091
|
-
import
|
|
2134
|
+
import React23, { useEffect as useEffect5, useRef, useState as useState5 } from "react";
|
|
2092
2135
|
function Card({
|
|
2093
2136
|
href,
|
|
2094
2137
|
src,
|
|
@@ -2146,8 +2189,8 @@ function Card({
|
|
|
2146
2189
|
const h = Number(imgHeight);
|
|
2147
2190
|
const ratio = Number.isFinite(Number(aspectRatio)) && Number(aspectRatio) > 0 ? Number(aspectRatio) : Number.isFinite(w) && w > 0 && Number.isFinite(h) && h > 0 ? w / h : void 0;
|
|
2148
2191
|
const paddingPercent = ratio ? 100 / ratio : 100;
|
|
2149
|
-
const caption = /* @__PURE__ */
|
|
2150
|
-
return /* @__PURE__ */
|
|
2192
|
+
const caption = /* @__PURE__ */ React23.createElement("figcaption", null, title && /* @__PURE__ */ React23.createElement("span", null, title), subtitle && /* @__PURE__ */ React23.createElement("span", null, subtitle), children);
|
|
2193
|
+
return /* @__PURE__ */ React23.createElement(
|
|
2151
2194
|
"a",
|
|
2152
2195
|
{
|
|
2153
2196
|
href,
|
|
@@ -2159,13 +2202,13 @@ function Card({
|
|
|
2159
2202
|
"data-image-loaded": imageLoaded ? "true" : "false",
|
|
2160
2203
|
...rest
|
|
2161
2204
|
},
|
|
2162
|
-
/* @__PURE__ */
|
|
2205
|
+
/* @__PURE__ */ React23.createElement("figure", null, src ? ratio ? /* @__PURE__ */ React23.createElement(
|
|
2163
2206
|
"div",
|
|
2164
2207
|
{
|
|
2165
2208
|
className: "canopy-card-media",
|
|
2166
2209
|
style: { "--canopy-card-padding": `${paddingPercent}%` }
|
|
2167
2210
|
},
|
|
2168
|
-
inView ? /* @__PURE__ */
|
|
2211
|
+
inView ? /* @__PURE__ */ React23.createElement(
|
|
2169
2212
|
"img",
|
|
2170
2213
|
{
|
|
2171
2214
|
src,
|
|
@@ -2175,7 +2218,7 @@ function Card({
|
|
|
2175
2218
|
onError: () => setImageLoaded(true)
|
|
2176
2219
|
}
|
|
2177
2220
|
) : null
|
|
2178
|
-
) : /* @__PURE__ */
|
|
2221
|
+
) : /* @__PURE__ */ React23.createElement(
|
|
2179
2222
|
"img",
|
|
2180
2223
|
{
|
|
2181
2224
|
src,
|
|
@@ -2194,7 +2237,7 @@ function useReferencedItems(itemsProp) {
|
|
|
2194
2237
|
if (Array.isArray(itemsProp)) return itemsProp;
|
|
2195
2238
|
const PageContext = navigationHelpers4 && typeof navigationHelpers4.getPageContext === "function" ? navigationHelpers4.getPageContext() : null;
|
|
2196
2239
|
if (!PageContext) return [];
|
|
2197
|
-
const context =
|
|
2240
|
+
const context = React24.useContext(PageContext);
|
|
2198
2241
|
const items = context && context.page ? context.page.referencedItems : null;
|
|
2199
2242
|
return Array.isArray(items) ? items : [];
|
|
2200
2243
|
}
|
|
@@ -2214,13 +2257,13 @@ function ReferencedItems({
|
|
|
2214
2257
|
"referenced-items--empty",
|
|
2215
2258
|
className
|
|
2216
2259
|
].filter(Boolean).join(" ");
|
|
2217
|
-
return /* @__PURE__ */
|
|
2260
|
+
return /* @__PURE__ */ React24.createElement("div", { className: emptyClass, ...rest }, typeof emptyLabel === "function" ? emptyLabel() : emptyLabel);
|
|
2218
2261
|
}
|
|
2219
2262
|
const containerClassName = ["referenced-items", className].filter(Boolean).join(" ");
|
|
2220
|
-
return /* @__PURE__ */
|
|
2263
|
+
return /* @__PURE__ */ React24.createElement("section", { className: containerClassName, ...rest }, children, /* @__PURE__ */ React24.createElement("div", { className: "referenced-items__grid", role: "list" }, items.map((item) => {
|
|
2221
2264
|
if (!item) return null;
|
|
2222
2265
|
const key = item.href || item.slug || item.id;
|
|
2223
|
-
return /* @__PURE__ */
|
|
2266
|
+
return /* @__PURE__ */ React24.createElement("div", { className: "referenced-items__item", role: "listitem", key }, /* @__PURE__ */ React24.createElement(
|
|
2224
2267
|
Card,
|
|
2225
2268
|
{
|
|
2226
2269
|
href: item.href,
|
|
@@ -2237,7 +2280,7 @@ function ReferencedItems({
|
|
|
2237
2280
|
}
|
|
2238
2281
|
|
|
2239
2282
|
// ui/src/content/References.jsx
|
|
2240
|
-
import
|
|
2283
|
+
import React25 from "react";
|
|
2241
2284
|
import navigationHelpers5 from "@canopy-iiif/app/lib/components/navigation.js";
|
|
2242
2285
|
function getPageContext() {
|
|
2243
2286
|
if (!navigationHelpers5 || typeof navigationHelpers5.getPageContext !== "function") {
|
|
@@ -2267,7 +2310,7 @@ function References({
|
|
|
2267
2310
|
...rest
|
|
2268
2311
|
}) {
|
|
2269
2312
|
const PageContext = getPageContext();
|
|
2270
|
-
const context = PageContext ?
|
|
2313
|
+
const context = PageContext ? React25.useContext(PageContext) : null;
|
|
2271
2314
|
const contextPage = context && context.page ? context.page : null;
|
|
2272
2315
|
const manifestId = id || contextPage && contextPage.manifestId || "";
|
|
2273
2316
|
const contextReferences = !id && contextPage && Array.isArray(contextPage.referencedBy) ? contextPage.referencedBy : null;
|
|
@@ -2276,11 +2319,808 @@ function References({
|
|
|
2276
2319
|
const entries = references && references.length ? references : null;
|
|
2277
2320
|
if (!entries || !entries.length) return null;
|
|
2278
2321
|
const containerClass = ["references", className].filter(Boolean).join(" ");
|
|
2279
|
-
return /* @__PURE__ */
|
|
2322
|
+
return /* @__PURE__ */ React25.createElement("dl", { className: containerClass, ...rest }, /* @__PURE__ */ React25.createElement("div", { className: "references__group" }, /* @__PURE__ */ React25.createElement("dt", null, title), entries.map((entry) => /* @__PURE__ */ React25.createElement("dd", { key: entry.href, className: "references__item" }, /* @__PURE__ */ React25.createElement("a", { href: entry.href }, entry.title || entry.href)))));
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
// ui/src/content/timeline/MdxTimeline.jsx
|
|
2326
|
+
import React27 from "react";
|
|
2327
|
+
import ReactDOMServer from "react-dom/server";
|
|
2328
|
+
|
|
2329
|
+
// ui/src/content/timeline/Timeline.jsx
|
|
2330
|
+
import React26 from "react";
|
|
2331
|
+
|
|
2332
|
+
// ui/src/content/timeline/date-utils.js
|
|
2333
|
+
var FALLBACK_LOCALE = (() => {
|
|
2334
|
+
try {
|
|
2335
|
+
return new Intl.Locale("en-US");
|
|
2336
|
+
} catch (_) {
|
|
2337
|
+
return "en-US";
|
|
2338
|
+
}
|
|
2339
|
+
})();
|
|
2340
|
+
function createLocale(localeValue) {
|
|
2341
|
+
if (!localeValue) return FALLBACK_LOCALE;
|
|
2342
|
+
if (typeof Intl !== "undefined" && localeValue instanceof Intl.Locale)
|
|
2343
|
+
return localeValue;
|
|
2344
|
+
try {
|
|
2345
|
+
return new Intl.Locale(localeValue);
|
|
2346
|
+
} catch (_) {
|
|
2347
|
+
return FALLBACK_LOCALE;
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
function parseMonthIndex(name = "", locale = FALLBACK_LOCALE) {
|
|
2351
|
+
const localeId = typeof locale === "string" ? locale : locale && locale.baseName ? locale.baseName : "en-US";
|
|
2352
|
+
const normalized = String(name || "").trim().toLocaleLowerCase(localeId);
|
|
2353
|
+
if (!normalized) return 0;
|
|
2354
|
+
const months = [
|
|
2355
|
+
"january",
|
|
2356
|
+
"february",
|
|
2357
|
+
"march",
|
|
2358
|
+
"april",
|
|
2359
|
+
"may",
|
|
2360
|
+
"june",
|
|
2361
|
+
"july",
|
|
2362
|
+
"august",
|
|
2363
|
+
"september",
|
|
2364
|
+
"october",
|
|
2365
|
+
"november",
|
|
2366
|
+
"december"
|
|
2367
|
+
];
|
|
2368
|
+
const idx = months.indexOf(normalized);
|
|
2369
|
+
return idx === -1 ? 0 : idx;
|
|
2370
|
+
}
|
|
2371
|
+
function parseStructuredInput(value) {
|
|
2372
|
+
if (!value || typeof value !== "object") return null;
|
|
2373
|
+
const { year, month, day } = value;
|
|
2374
|
+
if (!Number.isFinite(Number(year))) return null;
|
|
2375
|
+
const y = Number(year);
|
|
2376
|
+
const m = Number.isFinite(Number(month)) ? Number(month) - 1 : 0;
|
|
2377
|
+
const d = Number.isFinite(Number(day)) ? Number(day) : 1;
|
|
2378
|
+
return new Date(Date.UTC(y, Math.max(0, Math.min(11, m)), Math.max(1, Math.min(31, d))));
|
|
2379
|
+
}
|
|
2380
|
+
function createDateFromInput(value, { locale } = {}) {
|
|
2381
|
+
const loc = createLocale(locale);
|
|
2382
|
+
if (value instanceof Date) return new Date(value.getTime());
|
|
2383
|
+
if (Number.isFinite(Number(value))) {
|
|
2384
|
+
const year = Number(value);
|
|
2385
|
+
return new Date(Date.UTC(year, 0, 1));
|
|
2386
|
+
}
|
|
2387
|
+
if (value && typeof value === "object") {
|
|
2388
|
+
const structured = parseStructuredInput(value);
|
|
2389
|
+
if (structured) return structured;
|
|
2390
|
+
}
|
|
2391
|
+
const text = typeof value === "string" ? value.trim() : "";
|
|
2392
|
+
if (!text) return null;
|
|
2393
|
+
const isoYear = text.match(/^(\d{4})$/);
|
|
2394
|
+
if (isoYear) {
|
|
2395
|
+
return new Date(Date.UTC(Number(isoYear[1]), 0, 1));
|
|
2396
|
+
}
|
|
2397
|
+
const isoYearMonth = text.match(/^(\d{4})-(\d{2})$/);
|
|
2398
|
+
if (isoYearMonth) {
|
|
2399
|
+
return new Date(
|
|
2400
|
+
Date.UTC(Number(isoYearMonth[1]), Number(isoYearMonth[2]) - 1, 1)
|
|
2401
|
+
);
|
|
2402
|
+
}
|
|
2403
|
+
const isoDate = text.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
2404
|
+
if (isoDate) {
|
|
2405
|
+
return new Date(
|
|
2406
|
+
Date.UTC(
|
|
2407
|
+
Number(isoDate[1]),
|
|
2408
|
+
Number(isoDate[2]) - 1,
|
|
2409
|
+
Number(isoDate[3])
|
|
2410
|
+
)
|
|
2411
|
+
);
|
|
2412
|
+
}
|
|
2413
|
+
const monthDayYear = text.match(/^([A-Za-z]+)\s+(\d{1,2})(?:,)?\s*(\d{4})$/);
|
|
2414
|
+
if (monthDayYear) {
|
|
2415
|
+
const month = parseMonthIndex(monthDayYear[1], loc);
|
|
2416
|
+
const day = Number(monthDayYear[2]);
|
|
2417
|
+
const year = Number(monthDayYear[3]);
|
|
2418
|
+
return new Date(Date.UTC(year, month, day));
|
|
2419
|
+
}
|
|
2420
|
+
const monthYear = text.match(/^([A-Za-z]+)\s+(\d{4})$/);
|
|
2421
|
+
if (monthYear) {
|
|
2422
|
+
const month = parseMonthIndex(monthYear[1], loc);
|
|
2423
|
+
const year = Number(monthYear[2]);
|
|
2424
|
+
return new Date(Date.UTC(year, month, 1));
|
|
2425
|
+
}
|
|
2426
|
+
const fallback = new Date(text);
|
|
2427
|
+
if (!Number.isNaN(fallback.getTime())) return fallback;
|
|
2428
|
+
const alt = new Date(Date.parse(text));
|
|
2429
|
+
if (!Number.isNaN(alt.getTime())) return alt;
|
|
2430
|
+
return null;
|
|
2431
|
+
}
|
|
2432
|
+
function formatDateLabel(date, { granularity = "day", locale } = {}) {
|
|
2433
|
+
if (!(date instanceof Date) || Number.isNaN(date.getTime())) return "";
|
|
2434
|
+
const loc = createLocale(locale);
|
|
2435
|
+
const baseName = typeof loc === "string" ? loc : loc.baseName || "en-US";
|
|
2436
|
+
const options = { year: "numeric" };
|
|
2437
|
+
if (granularity === "month" || granularity === "day") {
|
|
2438
|
+
options.month = "long";
|
|
2439
|
+
}
|
|
2440
|
+
if (granularity === "day") {
|
|
2441
|
+
options.day = "numeric";
|
|
2442
|
+
}
|
|
2443
|
+
options.timeZone = "UTC";
|
|
2444
|
+
try {
|
|
2445
|
+
const formatter = new Intl.DateTimeFormat(baseName, options);
|
|
2446
|
+
return formatter.format(date);
|
|
2447
|
+
} catch (_) {
|
|
2448
|
+
return date.toISOString().slice(0, 10);
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
function normalizeRange(range = {}) {
|
|
2452
|
+
const { start, end, granularity = "year", locale } = range || {};
|
|
2453
|
+
const loc = createLocale(locale);
|
|
2454
|
+
const startDate = createDateFromInput(start || /* @__PURE__ */ new Date(), { locale: loc }) || new Date(Date.UTC(0, 0, 1));
|
|
2455
|
+
let endDate = createDateFromInput(end, { locale: loc });
|
|
2456
|
+
if (!endDate) {
|
|
2457
|
+
const copy = new Date(startDate.getTime());
|
|
2458
|
+
copy.setUTCFullYear(copy.getUTCFullYear() + 1);
|
|
2459
|
+
endDate = copy;
|
|
2460
|
+
}
|
|
2461
|
+
if (endDate <= startDate) {
|
|
2462
|
+
const nextDay = new Date(startDate.getTime());
|
|
2463
|
+
nextDay.setUTCDate(nextDay.getUTCDate() + 1);
|
|
2464
|
+
endDate = nextDay;
|
|
2465
|
+
}
|
|
2466
|
+
const span = Math.max(1, endDate - startDate);
|
|
2467
|
+
return {
|
|
2468
|
+
startDate,
|
|
2469
|
+
endDate,
|
|
2470
|
+
span,
|
|
2471
|
+
granularity: granularity === "month" || granularity === "day" ? granularity : "year",
|
|
2472
|
+
locale: loc
|
|
2473
|
+
};
|
|
2474
|
+
}
|
|
2475
|
+
function buildPointMetadata({ value, granularity, locale }) {
|
|
2476
|
+
const date = createDateFromInput(value, { locale });
|
|
2477
|
+
return {
|
|
2478
|
+
date,
|
|
2479
|
+
label: formatDateLabel(date, { granularity, locale }),
|
|
2480
|
+
timestamp: date ? date.getTime() : null
|
|
2481
|
+
};
|
|
2482
|
+
}
|
|
2483
|
+
function clampProgress(value) {
|
|
2484
|
+
if (!Number.isFinite(value)) return 0;
|
|
2485
|
+
if (value < 0) return 0;
|
|
2486
|
+
if (value > 1) return 1;
|
|
2487
|
+
return value;
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2490
|
+
// ui/src/content/timeline/Timeline.jsx
|
|
2491
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
2492
|
+
var DEFAULT_TRACK_HEIGHT = 640;
|
|
2493
|
+
var MIN_HEIGHT_PER_POINT = 220;
|
|
2494
|
+
function getThresholdMs(threshold, granularity) {
|
|
2495
|
+
const value = Number(threshold);
|
|
2496
|
+
if (!Number.isFinite(value) || value <= 0) return 0;
|
|
2497
|
+
if (granularity === "day") return value * DAY_MS;
|
|
2498
|
+
if (granularity === "month") return value * 30 * DAY_MS;
|
|
2499
|
+
return value * 365 * DAY_MS;
|
|
2500
|
+
}
|
|
2501
|
+
function buildGroupedEntries(points, thresholdMs, options) {
|
|
2502
|
+
if (!Array.isArray(points) || !points.length) return [];
|
|
2503
|
+
if (!thresholdMs) return points.map((point) => ({ type: "point", point }));
|
|
2504
|
+
const entries = [];
|
|
2505
|
+
let currentGroup = null;
|
|
2506
|
+
let groupCounter = 0;
|
|
2507
|
+
function flush() {
|
|
2508
|
+
if (!currentGroup) return;
|
|
2509
|
+
if (currentGroup.points.length > 1) {
|
|
2510
|
+
const firstPoint = currentGroup.points[0];
|
|
2511
|
+
entries.push({
|
|
2512
|
+
type: "group",
|
|
2513
|
+
id: `canopy-timeline-group-${groupCounter}-${currentGroup.start}`,
|
|
2514
|
+
points: currentGroup.points,
|
|
2515
|
+
progress: firstPoint.progress,
|
|
2516
|
+
side: firstPoint.side,
|
|
2517
|
+
label: formatGroupLabel(currentGroup.start, currentGroup.end, options),
|
|
2518
|
+
count: currentGroup.points.length
|
|
2519
|
+
});
|
|
2520
|
+
groupCounter += 1;
|
|
2521
|
+
} else {
|
|
2522
|
+
entries.push({ type: "point", point: currentGroup.points[0] });
|
|
2523
|
+
}
|
|
2524
|
+
currentGroup = null;
|
|
2525
|
+
}
|
|
2526
|
+
points.forEach((point) => {
|
|
2527
|
+
const timestamp = point && point.meta ? point.meta.timestamp : null;
|
|
2528
|
+
if (!Number.isFinite(timestamp)) {
|
|
2529
|
+
flush();
|
|
2530
|
+
if (point) entries.push({ type: "point", point });
|
|
2531
|
+
return;
|
|
2532
|
+
}
|
|
2533
|
+
if (!currentGroup) {
|
|
2534
|
+
currentGroup = {
|
|
2535
|
+
points: [point],
|
|
2536
|
+
start: timestamp,
|
|
2537
|
+
end: timestamp,
|
|
2538
|
+
last: timestamp
|
|
2539
|
+
};
|
|
2540
|
+
return;
|
|
2541
|
+
}
|
|
2542
|
+
const diff = Math.abs(timestamp - currentGroup.last);
|
|
2543
|
+
if (diff <= thresholdMs) {
|
|
2544
|
+
currentGroup.points.push(point);
|
|
2545
|
+
currentGroup.last = timestamp;
|
|
2546
|
+
if (timestamp < currentGroup.start) currentGroup.start = timestamp;
|
|
2547
|
+
if (timestamp > currentGroup.end) currentGroup.end = timestamp;
|
|
2548
|
+
} else {
|
|
2549
|
+
flush();
|
|
2550
|
+
currentGroup = {
|
|
2551
|
+
points: [point],
|
|
2552
|
+
start: timestamp,
|
|
2553
|
+
end: timestamp,
|
|
2554
|
+
last: timestamp
|
|
2555
|
+
};
|
|
2556
|
+
}
|
|
2557
|
+
});
|
|
2558
|
+
flush();
|
|
2559
|
+
return entries;
|
|
2560
|
+
}
|
|
2561
|
+
function formatGroupLabel(startTs, endTs, options) {
|
|
2562
|
+
if (!Number.isFinite(startTs) || !Number.isFinite(endTs)) return "";
|
|
2563
|
+
const startLabel = formatDateLabel(new Date(startTs), options);
|
|
2564
|
+
const endLabel = formatDateLabel(new Date(endTs), options);
|
|
2565
|
+
if (!startLabel || !endLabel) return "";
|
|
2566
|
+
return startLabel === endLabel ? startLabel : `${startLabel} \u2013 ${endLabel}`;
|
|
2567
|
+
}
|
|
2568
|
+
function deriveRangeOverrides(points, range) {
|
|
2569
|
+
const timestamps = points.map((point) => point && point.meta ? point.meta.timestamp : null).filter((timestamp) => Number.isFinite(timestamp));
|
|
2570
|
+
if (!timestamps.length) return range || {};
|
|
2571
|
+
const earliest = Math.min(...timestamps);
|
|
2572
|
+
const latest = Math.max(...timestamps);
|
|
2573
|
+
return {
|
|
2574
|
+
...range,
|
|
2575
|
+
start: range && range.start ? range.start : new Date(earliest),
|
|
2576
|
+
end: range && range.end ? range.end : new Date(latest)
|
|
2577
|
+
};
|
|
2578
|
+
}
|
|
2579
|
+
function getActivePointId(points) {
|
|
2580
|
+
const highlighted = points.find((point) => point && point.highlight);
|
|
2581
|
+
if (highlighted) return highlighted.id;
|
|
2582
|
+
return points.length ? points[0].id : null;
|
|
2583
|
+
}
|
|
2584
|
+
function formatRangeLabel(rangeInfo) {
|
|
2585
|
+
if (!rangeInfo) return "";
|
|
2586
|
+
const startLabel = formatDateLabel(rangeInfo.startDate, {
|
|
2587
|
+
granularity: rangeInfo.granularity,
|
|
2588
|
+
locale: rangeInfo.locale
|
|
2589
|
+
});
|
|
2590
|
+
const endLabel = formatDateLabel(rangeInfo.endDate, {
|
|
2591
|
+
granularity: rangeInfo.granularity,
|
|
2592
|
+
locale: rangeInfo.locale
|
|
2593
|
+
});
|
|
2594
|
+
if (!startLabel || !endLabel) return "";
|
|
2595
|
+
if (startLabel === endLabel) return startLabel;
|
|
2596
|
+
return `${startLabel} \u2013 ${endLabel}`;
|
|
2597
|
+
}
|
|
2598
|
+
function sanitizePoints(points) {
|
|
2599
|
+
if (!Array.isArray(points)) return [];
|
|
2600
|
+
return points.map((point, index) => {
|
|
2601
|
+
if (!point) return null;
|
|
2602
|
+
const meta = point.meta || {};
|
|
2603
|
+
const timestamp = Number(meta.timestamp);
|
|
2604
|
+
const manifests = Array.isArray(point.manifests) ? point.manifests.map((manifest) => manifest ? { ...manifest } : null).filter(Boolean) : [];
|
|
2605
|
+
const resources = Array.isArray(point.resources) ? point.resources.filter(Boolean) : [];
|
|
2606
|
+
return {
|
|
2607
|
+
...point,
|
|
2608
|
+
id: point.id || `timeline-point-${index}`,
|
|
2609
|
+
title: point.title || point.label || `Point ${index + 1}`,
|
|
2610
|
+
summary: point.summary || point.description || "",
|
|
2611
|
+
detailsHtml: point.detailsHtml || "",
|
|
2612
|
+
highlight: !!point.highlight,
|
|
2613
|
+
side: point.side === "left" || point.side === "right" ? point.side : null,
|
|
2614
|
+
meta: {
|
|
2615
|
+
label: meta.label || "",
|
|
2616
|
+
timestamp: Number.isFinite(timestamp) ? timestamp : null
|
|
2617
|
+
},
|
|
2618
|
+
manifests,
|
|
2619
|
+
resources
|
|
2620
|
+
};
|
|
2621
|
+
}).filter(Boolean);
|
|
2622
|
+
}
|
|
2623
|
+
function resolveTrackHeight(height, pointCount) {
|
|
2624
|
+
const minimumPx = Math.max(
|
|
2625
|
+
DEFAULT_TRACK_HEIGHT,
|
|
2626
|
+
pointCount * MIN_HEIGHT_PER_POINT
|
|
2627
|
+
);
|
|
2628
|
+
const fallback = `${minimumPx}px`;
|
|
2629
|
+
if (height == null) return fallback;
|
|
2630
|
+
if (typeof height === "number") {
|
|
2631
|
+
const numeric = Number(height);
|
|
2632
|
+
if (Number.isFinite(numeric)) {
|
|
2633
|
+
return `${Math.max(numeric, pointCount * MIN_HEIGHT_PER_POINT)}px`;
|
|
2634
|
+
}
|
|
2635
|
+
return fallback;
|
|
2636
|
+
}
|
|
2637
|
+
if (typeof height === "string") {
|
|
2638
|
+
const trimmed = height.trim();
|
|
2639
|
+
if (!trimmed) return fallback;
|
|
2640
|
+
const numeric = Number(trimmed);
|
|
2641
|
+
if (Number.isFinite(numeric)) {
|
|
2642
|
+
return `${Math.max(numeric, pointCount * MIN_HEIGHT_PER_POINT)}px`;
|
|
2643
|
+
}
|
|
2644
|
+
return trimmed;
|
|
2645
|
+
}
|
|
2646
|
+
return fallback;
|
|
2647
|
+
}
|
|
2648
|
+
function TimelineConnector({ side, isActive, highlight }) {
|
|
2649
|
+
const connectorClasses = [
|
|
2650
|
+
"canopy-timeline__connector",
|
|
2651
|
+
side === "left" ? "canopy-timeline__connector--left" : "canopy-timeline__connector--right"
|
|
2652
|
+
].filter(Boolean).join(" ");
|
|
2653
|
+
const dotClasses = [
|
|
2654
|
+
"canopy-timeline__connector-dot",
|
|
2655
|
+
highlight || isActive ? "is-active" : ""
|
|
2656
|
+
].filter(Boolean).join(" ");
|
|
2657
|
+
return /* @__PURE__ */ React26.createElement("span", { className: connectorClasses, "aria-hidden": "true" }, side === "left" ? /* @__PURE__ */ React26.createElement(React26.Fragment, null, /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__connector-line" }), /* @__PURE__ */ React26.createElement("span", { className: dotClasses })) : /* @__PURE__ */ React26.createElement(React26.Fragment, null, /* @__PURE__ */ React26.createElement("span", { className: dotClasses }), /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__connector-line" })));
|
|
2658
|
+
}
|
|
2659
|
+
function renderResourceSection(point) {
|
|
2660
|
+
if (!point) return null;
|
|
2661
|
+
const manifestCards = Array.isArray(point.manifests) ? point.manifests.filter(Boolean) : [];
|
|
2662
|
+
const legacyResources = Array.isArray(point.resources) ? point.resources.filter(Boolean) : [];
|
|
2663
|
+
if (!manifestCards.length && !legacyResources.length) return null;
|
|
2664
|
+
return /* @__PURE__ */ React26.createElement("div", { className: "canopy-timeline__resources" }, /* @__PURE__ */ React26.createElement("div", { className: "canopy-timeline__resources-list" }, manifestCards.map((manifest) => /* @__PURE__ */ React26.createElement("div", { key: manifest.id || manifest.href }, /* @__PURE__ */ React26.createElement(
|
|
2665
|
+
TeaserCard,
|
|
2666
|
+
{
|
|
2667
|
+
href: manifest.href,
|
|
2668
|
+
title: manifest.title || manifest.href,
|
|
2669
|
+
summary: manifest.summary,
|
|
2670
|
+
metadata: Array.isArray(manifest.metadata) && manifest.metadata.length ? manifest.metadata : manifest.summary ? [manifest.summary] : [],
|
|
2671
|
+
thumbnail: manifest.thumbnail,
|
|
2672
|
+
type: manifest.type || "work"
|
|
2673
|
+
}
|
|
2674
|
+
))), legacyResources.map((resource, idx) => /* @__PURE__ */ React26.createElement("div", { key: resource.id || resource.href || `legacy-${idx}` }, /* @__PURE__ */ React26.createElement(
|
|
2675
|
+
TeaserCard,
|
|
2676
|
+
{
|
|
2677
|
+
href: resource.href,
|
|
2678
|
+
title: resource.label || resource.title || resource.href,
|
|
2679
|
+
summary: resource.summary,
|
|
2680
|
+
thumbnail: resource.thumbnail,
|
|
2681
|
+
type: resource.type || "resource"
|
|
2682
|
+
}
|
|
2683
|
+
)))));
|
|
2684
|
+
}
|
|
2685
|
+
function Timeline({
|
|
2686
|
+
className = "",
|
|
2687
|
+
title,
|
|
2688
|
+
description,
|
|
2689
|
+
range: rangeProp,
|
|
2690
|
+
locale: localeProp = "en-US",
|
|
2691
|
+
height = DEFAULT_TRACK_HEIGHT,
|
|
2692
|
+
threshold: thresholdProp = null,
|
|
2693
|
+
steps = null,
|
|
2694
|
+
points: pointsProp,
|
|
2695
|
+
__canopyTimeline: payload = null,
|
|
2696
|
+
...rest
|
|
2697
|
+
}) {
|
|
2698
|
+
const payloadPoints = payload && Array.isArray(payload.points) ? payload.points : null;
|
|
2699
|
+
const rawPoints = React26.useMemo(() => {
|
|
2700
|
+
if (Array.isArray(pointsProp) && pointsProp.length) return pointsProp;
|
|
2701
|
+
if (payloadPoints && payloadPoints.length) return payloadPoints;
|
|
2702
|
+
return [];
|
|
2703
|
+
}, [pointsProp, payloadPoints]);
|
|
2704
|
+
const sanitizedPoints = React26.useMemo(
|
|
2705
|
+
() => sanitizePoints(rawPoints),
|
|
2706
|
+
[rawPoints]
|
|
2707
|
+
);
|
|
2708
|
+
const localeValue = payload && payload.locale ? payload.locale : localeProp;
|
|
2709
|
+
const baseLocale = React26.useMemo(
|
|
2710
|
+
() => createLocale(localeValue),
|
|
2711
|
+
[localeValue]
|
|
2712
|
+
);
|
|
2713
|
+
const rangeInput = payload && payload.range ? payload.range : rangeProp || {};
|
|
2714
|
+
const rangeOverrides = React26.useMemo(
|
|
2715
|
+
() => deriveRangeOverrides(sanitizedPoints, rangeInput),
|
|
2716
|
+
[sanitizedPoints, rangeInput]
|
|
2717
|
+
);
|
|
2718
|
+
const effectiveRange = React26.useMemo(
|
|
2719
|
+
() => normalizeRange({
|
|
2720
|
+
...rangeOverrides,
|
|
2721
|
+
locale: baseLocale
|
|
2722
|
+
}),
|
|
2723
|
+
[rangeOverrides, baseLocale]
|
|
2724
|
+
);
|
|
2725
|
+
const spanStart = effectiveRange.startDate.getTime();
|
|
2726
|
+
const span = effectiveRange.span;
|
|
2727
|
+
const pointsWithPosition = React26.useMemo(() => {
|
|
2728
|
+
if (!sanitizedPoints.length) return [];
|
|
2729
|
+
return sanitizedPoints.map((point, index) => {
|
|
2730
|
+
const timestamp = point.meta.timestamp;
|
|
2731
|
+
const fallbackProgress = sanitizedPoints.length > 1 ? index / (sanitizedPoints.length - 1) : 0;
|
|
2732
|
+
const progress = Number.isFinite(timestamp) ? clampProgress((timestamp - spanStart) / span) : fallbackProgress;
|
|
2733
|
+
const side = point.side || (index % 2 === 0 ? "left" : "right");
|
|
2734
|
+
return {
|
|
2735
|
+
...point,
|
|
2736
|
+
progress,
|
|
2737
|
+
side
|
|
2738
|
+
};
|
|
2739
|
+
});
|
|
2740
|
+
}, [sanitizedPoints, spanStart, span]);
|
|
2741
|
+
const [activeId, setActiveId] = React26.useState(
|
|
2742
|
+
() => getActivePointId(pointsWithPosition)
|
|
2743
|
+
);
|
|
2744
|
+
React26.useEffect(() => {
|
|
2745
|
+
setActiveId(getActivePointId(pointsWithPosition));
|
|
2746
|
+
}, [pointsWithPosition]);
|
|
2747
|
+
const thresholdValue = typeof thresholdProp === "number" ? thresholdProp : payload && payload.threshold != null ? payload.threshold : null;
|
|
2748
|
+
const stepsValue = typeof steps === "number" ? Number(steps) : payload && typeof payload.steps === "number" ? Number(payload.steps) : null;
|
|
2749
|
+
const thresholdMs = React26.useMemo(
|
|
2750
|
+
() => getThresholdMs(thresholdValue, effectiveRange.granularity),
|
|
2751
|
+
[thresholdValue, effectiveRange.granularity]
|
|
2752
|
+
);
|
|
2753
|
+
const groupedEntries = React26.useMemo(
|
|
2754
|
+
() => buildGroupedEntries(pointsWithPosition, thresholdMs, {
|
|
2755
|
+
granularity: effectiveRange.granularity,
|
|
2756
|
+
locale: baseLocale
|
|
2757
|
+
}),
|
|
2758
|
+
[pointsWithPosition, thresholdMs, effectiveRange.granularity, baseLocale]
|
|
2759
|
+
);
|
|
2760
|
+
const [expandedGroupIds, setExpandedGroupIds] = React26.useState(
|
|
2761
|
+
() => /* @__PURE__ */ new Set()
|
|
2762
|
+
);
|
|
2763
|
+
React26.useEffect(() => {
|
|
2764
|
+
setExpandedGroupIds((prev) => {
|
|
2765
|
+
if (!prev || prev.size === 0) return prev;
|
|
2766
|
+
const validIds = new Set(
|
|
2767
|
+
groupedEntries.filter((entry) => entry.type === "group").map((entry) => entry.id)
|
|
2768
|
+
);
|
|
2769
|
+
const next = /* @__PURE__ */ new Set();
|
|
2770
|
+
let changed = false;
|
|
2771
|
+
prev.forEach((id) => {
|
|
2772
|
+
if (validIds.has(id)) next.add(id);
|
|
2773
|
+
else changed = true;
|
|
2774
|
+
});
|
|
2775
|
+
return changed ? next : prev;
|
|
2776
|
+
});
|
|
2777
|
+
}, [groupedEntries]);
|
|
2778
|
+
const toggleGroup = React26.useCallback((groupId) => {
|
|
2779
|
+
setExpandedGroupIds((prev) => {
|
|
2780
|
+
const next = new Set(prev || []);
|
|
2781
|
+
if (next.has(groupId)) next.delete(groupId);
|
|
2782
|
+
else next.add(groupId);
|
|
2783
|
+
return next;
|
|
2784
|
+
});
|
|
2785
|
+
}, []);
|
|
2786
|
+
const trackHeight = resolveTrackHeight(height, pointsWithPosition.length);
|
|
2787
|
+
const containerClasses = ["canopy-timeline", className].filter(Boolean).join(" ");
|
|
2788
|
+
const rangeLabel = formatRangeLabel(effectiveRange);
|
|
2789
|
+
function renderPointEntry(point) {
|
|
2790
|
+
if (!point) return null;
|
|
2791
|
+
const wrapperClasses = [
|
|
2792
|
+
"canopy-timeline__point-wrapper",
|
|
2793
|
+
point.side === "left" ? "canopy-timeline__point-wrapper--left" : "canopy-timeline__point-wrapper--right"
|
|
2794
|
+
].filter(Boolean).join(" ");
|
|
2795
|
+
const wrapperStyle = { top: `${point.progress * 100}%` };
|
|
2796
|
+
const cardClasses = [
|
|
2797
|
+
"canopy-timeline__point",
|
|
2798
|
+
point.id === activeId ? "is-active" : "",
|
|
2799
|
+
point.highlight ? "is-highlighted" : ""
|
|
2800
|
+
].filter(Boolean).join(" ");
|
|
2801
|
+
const connector = /* @__PURE__ */ React26.createElement(
|
|
2802
|
+
TimelineConnector,
|
|
2803
|
+
{
|
|
2804
|
+
side: point.side,
|
|
2805
|
+
isActive: point.id === activeId,
|
|
2806
|
+
highlight: point.highlight
|
|
2807
|
+
}
|
|
2808
|
+
);
|
|
2809
|
+
const body = /* @__PURE__ */ React26.createElement("div", { className: "canopy-timeline__point-body" }, /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label), /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__point-title" }, point.title), point.summary ? /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__point-summary" }, point.summary) : null);
|
|
2810
|
+
const resourceSection = renderResourceSection(point);
|
|
2811
|
+
return /* @__PURE__ */ React26.createElement(
|
|
2812
|
+
"div",
|
|
2813
|
+
{
|
|
2814
|
+
key: point.id,
|
|
2815
|
+
className: wrapperClasses,
|
|
2816
|
+
style: wrapperStyle,
|
|
2817
|
+
role: "listitem"
|
|
2818
|
+
},
|
|
2819
|
+
point.side === "left" ? /* @__PURE__ */ React26.createElement(React26.Fragment, null, /* @__PURE__ */ React26.createElement("div", { className: cardClasses }, body, resourceSection), connector) : /* @__PURE__ */ React26.createElement(React26.Fragment, null, connector, /* @__PURE__ */ React26.createElement("div", { className: cardClasses }, body, resourceSection))
|
|
2820
|
+
);
|
|
2821
|
+
}
|
|
2822
|
+
function renderGroupEntry(entry) {
|
|
2823
|
+
const wrapperClasses = [
|
|
2824
|
+
"canopy-timeline__point-wrapper",
|
|
2825
|
+
entry.side === "left" ? "canopy-timeline__point-wrapper--left" : "canopy-timeline__point-wrapper--right"
|
|
2826
|
+
].filter(Boolean).join(" ");
|
|
2827
|
+
const wrapperStyle = { top: `${entry.progress * 100}%` };
|
|
2828
|
+
const isExpanded = expandedGroupIds.has(entry.id);
|
|
2829
|
+
const hasActivePoint = entry.points.some((point) => point.id === activeId);
|
|
2830
|
+
const connector = /* @__PURE__ */ React26.createElement(
|
|
2831
|
+
TimelineConnector,
|
|
2832
|
+
{
|
|
2833
|
+
side: entry.side,
|
|
2834
|
+
isActive: hasActivePoint,
|
|
2835
|
+
highlight: hasActivePoint
|
|
2836
|
+
}
|
|
2837
|
+
);
|
|
2838
|
+
const groupClasses = [
|
|
2839
|
+
"canopy-timeline__group",
|
|
2840
|
+
isExpanded ? "is-expanded" : "",
|
|
2841
|
+
hasActivePoint ? "is-active" : ""
|
|
2842
|
+
].filter(Boolean).join(" ");
|
|
2843
|
+
const countLabel = `${entry.count} event${entry.count > 1 ? "s" : ""}`;
|
|
2844
|
+
const header = /* @__PURE__ */ React26.createElement("div", { className: "canopy-timeline__group-header" }, /* @__PURE__ */ React26.createElement("div", { className: "canopy-timeline__group-summary" }, /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__point-date" }, entry.label), /* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__group-count" }, countLabel)), /* @__PURE__ */ React26.createElement(
|
|
2845
|
+
"button",
|
|
2846
|
+
{
|
|
2847
|
+
type: "button",
|
|
2848
|
+
className: "canopy-timeline__group-toggle",
|
|
2849
|
+
"aria-expanded": isExpanded ? "true" : "false",
|
|
2850
|
+
onClick: () => toggleGroup(entry.id)
|
|
2851
|
+
},
|
|
2852
|
+
isExpanded ? "Hide details" : "Show details"
|
|
2853
|
+
));
|
|
2854
|
+
const groupPoints = isExpanded ? /* @__PURE__ */ React26.createElement("div", { className: "canopy-timeline__group-points" }, entry.points.map((point) => /* @__PURE__ */ React26.createElement(
|
|
2855
|
+
"button",
|
|
2856
|
+
{
|
|
2857
|
+
key: point.id,
|
|
2858
|
+
type: "button",
|
|
2859
|
+
className: [
|
|
2860
|
+
"canopy-timeline__group-point",
|
|
2861
|
+
point.id === activeId ? "is-active" : ""
|
|
2862
|
+
].filter(Boolean).join(" "),
|
|
2863
|
+
onClick: () => setActiveId(point.id)
|
|
2864
|
+
},
|
|
2865
|
+
/* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__point-date" }, point.meta.label),
|
|
2866
|
+
/* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__group-point-title" }, point.title)
|
|
2867
|
+
))) : null;
|
|
2868
|
+
const groupCard = /* @__PURE__ */ React26.createElement("div", { className: groupClasses }, header, groupPoints);
|
|
2869
|
+
return /* @__PURE__ */ React26.createElement(
|
|
2870
|
+
"div",
|
|
2871
|
+
{
|
|
2872
|
+
key: entry.id,
|
|
2873
|
+
className: wrapperClasses,
|
|
2874
|
+
style: wrapperStyle,
|
|
2875
|
+
role: "listitem"
|
|
2876
|
+
},
|
|
2877
|
+
entry.side === "left" ? /* @__PURE__ */ React26.createElement(React26.Fragment, null, groupCard, connector) : /* @__PURE__ */ React26.createElement(React26.Fragment, null, connector, groupCard)
|
|
2878
|
+
);
|
|
2879
|
+
}
|
|
2880
|
+
return /* @__PURE__ */ React26.createElement("section", { className: containerClasses, ...rest }, title ? /* @__PURE__ */ React26.createElement("h2", { className: "canopy-timeline__title" }, title) : null, description ? /* @__PURE__ */ React26.createElement("p", { className: "canopy-timeline__description" }, description) : null, rangeLabel ? /* @__PURE__ */ React26.createElement("p", { className: "canopy-timeline__range", "aria-live": "polite" }, rangeLabel) : null, /* @__PURE__ */ React26.createElement("div", { className: "canopy-timeline__body" }, /* @__PURE__ */ React26.createElement(
|
|
2881
|
+
"div",
|
|
2882
|
+
{
|
|
2883
|
+
className: "canopy-timeline__list",
|
|
2884
|
+
role: "list",
|
|
2885
|
+
style: { minHeight: trackHeight }
|
|
2886
|
+
},
|
|
2887
|
+
/* @__PURE__ */ React26.createElement("div", { className: "canopy-timeline__spine", "aria-hidden": "true" }),
|
|
2888
|
+
renderSteps(stepsValue, effectiveRange),
|
|
2889
|
+
groupedEntries.map((entry) => {
|
|
2890
|
+
if (entry.type === "group") return renderGroupEntry(entry);
|
|
2891
|
+
return renderPointEntry(entry.point);
|
|
2892
|
+
})
|
|
2893
|
+
)));
|
|
2894
|
+
}
|
|
2895
|
+
function renderSteps(stepSize, range) {
|
|
2896
|
+
if (!Number.isFinite(stepSize) || stepSize <= 0 || !range) return null;
|
|
2897
|
+
const startYear = range.startDate.getUTCFullYear();
|
|
2898
|
+
const endYear = range.endDate.getUTCFullYear();
|
|
2899
|
+
const markers = [];
|
|
2900
|
+
if (startYear < endYear) {
|
|
2901
|
+
markers.push(
|
|
2902
|
+
/* @__PURE__ */ React26.createElement(
|
|
2903
|
+
"span",
|
|
2904
|
+
{
|
|
2905
|
+
key: "timeline-step-start",
|
|
2906
|
+
className: "canopy-timeline__step canopy-timeline__step--start",
|
|
2907
|
+
style: { top: "0%" },
|
|
2908
|
+
"aria-hidden": "true"
|
|
2909
|
+
},
|
|
2910
|
+
/* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__step-line" }),
|
|
2911
|
+
/* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__step-label" }, startYear)
|
|
2912
|
+
)
|
|
2913
|
+
);
|
|
2914
|
+
markers.push(
|
|
2915
|
+
/* @__PURE__ */ React26.createElement(
|
|
2916
|
+
"span",
|
|
2917
|
+
{
|
|
2918
|
+
key: "timeline-step-end",
|
|
2919
|
+
className: "canopy-timeline__step canopy-timeline__step--end",
|
|
2920
|
+
style: { top: "100%" },
|
|
2921
|
+
"aria-hidden": "true"
|
|
2922
|
+
},
|
|
2923
|
+
/* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__step-line" }),
|
|
2924
|
+
/* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__step-label" }, endYear)
|
|
2925
|
+
)
|
|
2926
|
+
);
|
|
2927
|
+
}
|
|
2928
|
+
const baseYear = Math.ceil(startYear / stepSize) * stepSize;
|
|
2929
|
+
for (let year = baseYear; year <= endYear; year += stepSize) {
|
|
2930
|
+
const timestamp = Date.UTC(year, 0, 1);
|
|
2931
|
+
const progress = (timestamp - range.startDate.getTime()) / range.span;
|
|
2932
|
+
if (progress <= 0 || progress >= 1) continue;
|
|
2933
|
+
markers.push(
|
|
2934
|
+
/* @__PURE__ */ React26.createElement(
|
|
2935
|
+
"span",
|
|
2936
|
+
{
|
|
2937
|
+
key: `timeline-step-${year}`,
|
|
2938
|
+
className: "canopy-timeline__step",
|
|
2939
|
+
style: { top: `calc(${progress * 100}% - 0.5px)` },
|
|
2940
|
+
"aria-hidden": "true"
|
|
2941
|
+
},
|
|
2942
|
+
/* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__step-line" }),
|
|
2943
|
+
/* @__PURE__ */ React26.createElement("span", { className: "canopy-timeline__step-label" }, year)
|
|
2944
|
+
)
|
|
2945
|
+
);
|
|
2946
|
+
}
|
|
2947
|
+
return markers.length ? markers : null;
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
// ui/src/content/timeline/TimelinePoint.jsx
|
|
2951
|
+
function TimelinePoint() {
|
|
2952
|
+
return null;
|
|
2953
|
+
}
|
|
2954
|
+
TimelinePoint.displayName = "TimelinePoint";
|
|
2955
|
+
|
|
2956
|
+
// ui/src/content/timeline/MdxTimeline.jsx
|
|
2957
|
+
import navigationHelpers6 from "@canopy-iiif/app/lib/components/navigation.js";
|
|
2958
|
+
function normalizeManifestId(raw) {
|
|
2959
|
+
if (!raw) return "";
|
|
2960
|
+
try {
|
|
2961
|
+
const url = new URL(String(raw));
|
|
2962
|
+
url.hash = "";
|
|
2963
|
+
const params = Array.from(url.searchParams.entries()).sort(
|
|
2964
|
+
(a, b) => a[0].localeCompare(b[0]) || a[1].localeCompare(b[1])
|
|
2965
|
+
);
|
|
2966
|
+
url.search = "";
|
|
2967
|
+
params.forEach(([key, value]) => url.searchParams.append(key, value));
|
|
2968
|
+
return url.toString();
|
|
2969
|
+
} catch (_) {
|
|
2970
|
+
return String(raw || "").trim();
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
var PageContextFallback = React27.createContext(null);
|
|
2974
|
+
function useReferencedManifestMap() {
|
|
2975
|
+
var _a, _b;
|
|
2976
|
+
const PageContext = ((_b = (_a = navigationHelpers6) == null ? void 0 : _a.getPageContext) == null ? void 0 : _b.call(_a)) || PageContextFallback;
|
|
2977
|
+
const pageContext = React27.useContext(PageContext);
|
|
2978
|
+
const referencedItems = pageContext && pageContext.page && Array.isArray(pageContext.page.referencedItems) ? pageContext.page.referencedItems : [];
|
|
2979
|
+
return React27.useMemo(() => {
|
|
2980
|
+
const map = /* @__PURE__ */ new Map();
|
|
2981
|
+
referencedItems.forEach((item) => {
|
|
2982
|
+
if (!item) return;
|
|
2983
|
+
const id = item.id || item.href;
|
|
2984
|
+
if (!id) return;
|
|
2985
|
+
const normalized = normalizeManifestId(id);
|
|
2986
|
+
map.set(normalized, item);
|
|
2987
|
+
map.set(String(id), item);
|
|
2988
|
+
});
|
|
2989
|
+
return map;
|
|
2990
|
+
}, [referencedItems]);
|
|
2991
|
+
}
|
|
2992
|
+
function normalizeResource(resource, index) {
|
|
2993
|
+
if (!resource) return null;
|
|
2994
|
+
const href = resource.href || resource.id || "";
|
|
2995
|
+
const label = resource.label || resource.title || href || `Resource ${index + 1}`;
|
|
2996
|
+
return {
|
|
2997
|
+
id: resource.id || href || `timeline-resource-${index}`,
|
|
2998
|
+
href,
|
|
2999
|
+
label,
|
|
3000
|
+
type: resource.type || "IIIF",
|
|
3001
|
+
thumbnail: resource.thumbnail || null,
|
|
3002
|
+
summary: resource.summary || null
|
|
3003
|
+
};
|
|
3004
|
+
}
|
|
3005
|
+
function normalizePoint(child, index, options) {
|
|
3006
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3007
|
+
if (!React27.isValidElement(child)) return null;
|
|
3008
|
+
if (child.type !== TimelinePoint && ((_a = child.type) == null ? void 0 : _a.displayName) !== "TimelinePoint")
|
|
3009
|
+
return null;
|
|
3010
|
+
const props = child.props || {};
|
|
3011
|
+
const id = props.id || `timeline-point-${index}`;
|
|
3012
|
+
const granularity = props.precision || props.granularity || options && options.range && options.range.granularity || "year";
|
|
3013
|
+
const value = (_f = (_e = (_d = (_c = (_b = props.date) != null ? _b : props.value) != null ? _c : props.timestamp) != null ? _d : props.year) != null ? _e : props.label) != null ? _f : props.title;
|
|
3014
|
+
const meta = buildPointMetadata({
|
|
3015
|
+
value,
|
|
3016
|
+
granularity,
|
|
3017
|
+
locale: options.locale
|
|
3018
|
+
});
|
|
3019
|
+
let detailsHtml = "";
|
|
3020
|
+
try {
|
|
3021
|
+
if (props.children) {
|
|
3022
|
+
detailsHtml = ReactDOMServer.renderToStaticMarkup(
|
|
3023
|
+
React27.createElement(React27.Fragment, null, props.children)
|
|
3024
|
+
);
|
|
3025
|
+
}
|
|
3026
|
+
} catch (_) {
|
|
3027
|
+
detailsHtml = "";
|
|
3028
|
+
}
|
|
3029
|
+
const resources = Array.isArray(props.iiifResources) ? props.iiifResources.map(normalizeResource).filter(Boolean) : [];
|
|
3030
|
+
const manifestValues = Array.isArray(props.referencedManifests) ? props.referencedManifests : props.manifest ? [props.manifest] : Array.isArray(props.manifests) ? props.manifests : [];
|
|
3031
|
+
const manifests = resolveManifestReferences(manifestValues, options.manifestMap);
|
|
3032
|
+
return {
|
|
3033
|
+
id,
|
|
3034
|
+
title: props.title || props.label || `Point ${index + 1}`,
|
|
3035
|
+
summary: props.summary || props.description || "",
|
|
3036
|
+
description: props.description || "",
|
|
3037
|
+
highlight: props.highlight === true || props.highlight === "true",
|
|
3038
|
+
side: props.side || props.align || props.alignment || null,
|
|
3039
|
+
meta: {
|
|
3040
|
+
label: meta.label,
|
|
3041
|
+
timestamp: meta.timestamp
|
|
3042
|
+
},
|
|
3043
|
+
detailsHtml,
|
|
3044
|
+
resources,
|
|
3045
|
+
manifests
|
|
3046
|
+
};
|
|
3047
|
+
}
|
|
3048
|
+
function resolveManifestReferences(ids, manifestMap) {
|
|
3049
|
+
if (!Array.isArray(ids) || !ids.length || !manifestMap) return [];
|
|
3050
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3051
|
+
const out = [];
|
|
3052
|
+
ids.forEach((value) => {
|
|
3053
|
+
if (!value) return;
|
|
3054
|
+
const normalized = normalizeManifestId(value);
|
|
3055
|
+
if (!normalized || seen.has(normalized)) return;
|
|
3056
|
+
seen.add(normalized);
|
|
3057
|
+
const record = manifestMap.get(normalized);
|
|
3058
|
+
if (!record) return;
|
|
3059
|
+
out.push({
|
|
3060
|
+
id: record.id || value,
|
|
3061
|
+
href: record.href || null,
|
|
3062
|
+
title: record.title || record.href || value,
|
|
3063
|
+
summary: record.summary || "",
|
|
3064
|
+
thumbnail: record.thumbnail || null,
|
|
3065
|
+
thumbnailWidth: record.thumbnailWidth,
|
|
3066
|
+
thumbnailHeight: record.thumbnailHeight,
|
|
3067
|
+
type: record.type || "work",
|
|
3068
|
+
metadata: Array.isArray(record.metadata) && record.metadata.length ? record.metadata : record.summary ? [record.summary] : []
|
|
3069
|
+
});
|
|
3070
|
+
});
|
|
3071
|
+
return out;
|
|
3072
|
+
}
|
|
3073
|
+
function serializeProps(props, payload, locale) {
|
|
3074
|
+
const clone = {};
|
|
3075
|
+
Object.keys(props || {}).forEach((key) => {
|
|
3076
|
+
if (key === "children") return;
|
|
3077
|
+
const value = props[key];
|
|
3078
|
+
if (typeof value === "function" || typeof value === "symbol") return;
|
|
3079
|
+
clone[key] = value;
|
|
3080
|
+
});
|
|
3081
|
+
clone.locale = locale;
|
|
3082
|
+
clone.__canopyTimeline = payload;
|
|
3083
|
+
return clone;
|
|
3084
|
+
}
|
|
3085
|
+
function serializeForScript(data) {
|
|
3086
|
+
try {
|
|
3087
|
+
return JSON.stringify(data).replace(/</g, "\\u003c");
|
|
3088
|
+
} catch (_) {
|
|
3089
|
+
return "{}";
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
function MdxTimeline({ children, ...rest }) {
|
|
3093
|
+
const localeValue = rest.locale || "en-US";
|
|
3094
|
+
const localeObj = createLocale(localeValue);
|
|
3095
|
+
const localeBase = typeof localeObj === "string" ? localeObj : localeObj.baseName || "en-US";
|
|
3096
|
+
const manifestMap = useReferencedManifestMap();
|
|
3097
|
+
const childArray = React27.Children.toArray(children);
|
|
3098
|
+
const points = childArray.map(
|
|
3099
|
+
(child, index) => normalizePoint(child, index, {
|
|
3100
|
+
range: rest.range || {},
|
|
3101
|
+
locale: localeObj,
|
|
3102
|
+
manifestMap
|
|
3103
|
+
})
|
|
3104
|
+
).filter(Boolean);
|
|
3105
|
+
const payload = {
|
|
3106
|
+
points,
|
|
3107
|
+
locale: localeBase,
|
|
3108
|
+
range: rest.range || null,
|
|
3109
|
+
threshold: rest.threshold != null ? rest.threshold : null,
|
|
3110
|
+
steps: rest.steps != null ? rest.steps : null
|
|
3111
|
+
};
|
|
3112
|
+
const json = serializeForScript(serializeProps(rest, payload, localeBase));
|
|
3113
|
+
return /* @__PURE__ */ React27.createElement("div", { "data-canopy-timeline": "1" }, /* @__PURE__ */ React27.createElement(Timeline, { ...rest, __canopyTimeline: payload }), /* @__PURE__ */ React27.createElement(
|
|
3114
|
+
"script",
|
|
3115
|
+
{
|
|
3116
|
+
type: "application/json",
|
|
3117
|
+
dangerouslySetInnerHTML: { __html: json }
|
|
3118
|
+
}
|
|
3119
|
+
));
|
|
2280
3120
|
}
|
|
2281
3121
|
|
|
2282
3122
|
// ui/src/search/MdxSearchResults.jsx
|
|
2283
|
-
import
|
|
3123
|
+
import React28 from "react";
|
|
2284
3124
|
function MdxSearchResults(props) {
|
|
2285
3125
|
let json = "{}";
|
|
2286
3126
|
try {
|
|
@@ -2288,11 +3128,11 @@ function MdxSearchResults(props) {
|
|
|
2288
3128
|
} catch (_) {
|
|
2289
3129
|
json = "{}";
|
|
2290
3130
|
}
|
|
2291
|
-
return /* @__PURE__ */
|
|
3131
|
+
return /* @__PURE__ */ React28.createElement("div", { "data-canopy-search-results": "1" }, /* @__PURE__ */ React28.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
|
|
2292
3132
|
}
|
|
2293
3133
|
|
|
2294
3134
|
// ui/src/search/SearchSummary.jsx
|
|
2295
|
-
import
|
|
3135
|
+
import React29 from "react";
|
|
2296
3136
|
function SearchSummary(props) {
|
|
2297
3137
|
let json = "{}";
|
|
2298
3138
|
try {
|
|
@@ -2300,11 +3140,11 @@ function SearchSummary(props) {
|
|
|
2300
3140
|
} catch (_) {
|
|
2301
3141
|
json = "{}";
|
|
2302
3142
|
}
|
|
2303
|
-
return /* @__PURE__ */
|
|
3143
|
+
return /* @__PURE__ */ React29.createElement("div", { "data-canopy-search-summary": "1" }, /* @__PURE__ */ React29.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
|
|
2304
3144
|
}
|
|
2305
3145
|
|
|
2306
3146
|
// ui/src/search/MdxSearchTabs.jsx
|
|
2307
|
-
import
|
|
3147
|
+
import React30 from "react";
|
|
2308
3148
|
function MdxSearchTabs(props) {
|
|
2309
3149
|
let json = "{}";
|
|
2310
3150
|
try {
|
|
@@ -2312,11 +3152,11 @@ function MdxSearchTabs(props) {
|
|
|
2312
3152
|
} catch (_) {
|
|
2313
3153
|
json = "{}";
|
|
2314
3154
|
}
|
|
2315
|
-
return /* @__PURE__ */
|
|
3155
|
+
return /* @__PURE__ */ React30.createElement("div", { "data-canopy-search-tabs": "1" }, /* @__PURE__ */ React30.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: json } }));
|
|
2316
3156
|
}
|
|
2317
3157
|
|
|
2318
3158
|
// ui/src/search-form/MdxSearchFormModal.jsx
|
|
2319
|
-
import
|
|
3159
|
+
import React31 from "react";
|
|
2320
3160
|
function MdxSearchFormModal(props = {}) {
|
|
2321
3161
|
const {
|
|
2322
3162
|
placeholder = "Search\u2026",
|
|
@@ -2332,11 +3172,11 @@ function MdxSearchFormModal(props = {}) {
|
|
|
2332
3172
|
const text = typeof label === "string" && label.trim() ? label.trim() : buttonLabel;
|
|
2333
3173
|
const resolvedSearchPath = resolveSearchPath(searchPath);
|
|
2334
3174
|
const data = { placeholder, hotkey, maxResults, groupOrder, label: text, searchPath: resolvedSearchPath };
|
|
2335
|
-
return /* @__PURE__ */
|
|
3175
|
+
return /* @__PURE__ */ React31.createElement("div", { "data-canopy-search-form": true, className: "flex-1 min-w-0" }, /* @__PURE__ */ React31.createElement("div", { className: "relative w-full" }, /* @__PURE__ */ React31.createElement(SearchPanelForm, { placeholder, buttonLabel, label, searchPath: resolvedSearchPath }), /* @__PURE__ */ React31.createElement(SearchPanelTeaserResults, null)), /* @__PURE__ */ React31.createElement("script", { type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(data) } }));
|
|
2336
3176
|
}
|
|
2337
3177
|
|
|
2338
3178
|
// ui/src/iiif/ManifestPrimitives.jsx
|
|
2339
|
-
import
|
|
3179
|
+
import React32 from "react";
|
|
2340
3180
|
import {
|
|
2341
3181
|
Label as CloverLabel,
|
|
2342
3182
|
Metadata as CloverMetadata,
|
|
@@ -2361,28 +3201,28 @@ function ensureMetadata(items) {
|
|
|
2361
3201
|
function Label({ manifest, label, ...rest }) {
|
|
2362
3202
|
const intl = label || manifest && manifest.label;
|
|
2363
3203
|
if (!hasInternationalValue(intl)) return null;
|
|
2364
|
-
return /* @__PURE__ */
|
|
3204
|
+
return /* @__PURE__ */ React32.createElement(CloverLabel, { label: intl, ...rest });
|
|
2365
3205
|
}
|
|
2366
3206
|
function Summary({ manifest, summary, ...rest }) {
|
|
2367
3207
|
const intl = summary || manifest && manifest.summary;
|
|
2368
3208
|
if (!hasInternationalValue(intl)) return null;
|
|
2369
|
-
return /* @__PURE__ */
|
|
3209
|
+
return /* @__PURE__ */ React32.createElement(CloverSummary, { summary: intl, ...rest });
|
|
2370
3210
|
}
|
|
2371
3211
|
function Metadata({ manifest, metadata, ...rest }) {
|
|
2372
3212
|
const items = ensureMetadata(metadata || manifest && manifest.metadata);
|
|
2373
3213
|
if (!items.length) return null;
|
|
2374
|
-
return /* @__PURE__ */
|
|
3214
|
+
return /* @__PURE__ */ React32.createElement(CloverMetadata, { metadata: items, ...rest });
|
|
2375
3215
|
}
|
|
2376
3216
|
function RequiredStatement({ manifest, requiredStatement, ...rest }) {
|
|
2377
3217
|
const stmt = requiredStatement || manifest && manifest.requiredStatement;
|
|
2378
3218
|
if (!stmt || !hasInternationalValue(stmt.label) || !hasInternationalValue(stmt.value)) {
|
|
2379
3219
|
return null;
|
|
2380
3220
|
}
|
|
2381
|
-
return /* @__PURE__ */
|
|
3221
|
+
return /* @__PURE__ */ React32.createElement(CloverRequiredStatement, { requiredStatement: stmt, ...rest });
|
|
2382
3222
|
}
|
|
2383
3223
|
|
|
2384
3224
|
// ui/src/docs/CodeBlock.jsx
|
|
2385
|
-
import
|
|
3225
|
+
import React33 from "react";
|
|
2386
3226
|
function parseHighlightAttr(attr) {
|
|
2387
3227
|
if (!attr) return /* @__PURE__ */ new Set();
|
|
2388
3228
|
const cleaned = String(attr || "").trim();
|
|
@@ -2428,10 +3268,10 @@ var highlightBaseStyle = {
|
|
|
2428
3268
|
};
|
|
2429
3269
|
function DocsCodeBlock(props = {}) {
|
|
2430
3270
|
const { children, ...rest } = props;
|
|
2431
|
-
const childArray =
|
|
2432
|
-
const codeElement = childArray.find((el) =>
|
|
3271
|
+
const childArray = React33.Children.toArray(children);
|
|
3272
|
+
const codeElement = childArray.find((el) => React33.isValidElement(el));
|
|
2433
3273
|
if (!codeElement || !codeElement.props) {
|
|
2434
|
-
return
|
|
3274
|
+
return React33.createElement("pre", props);
|
|
2435
3275
|
}
|
|
2436
3276
|
const {
|
|
2437
3277
|
className = "",
|
|
@@ -2446,8 +3286,8 @@ function DocsCodeBlock(props = {}) {
|
|
|
2446
3286
|
const highlightSet = parseHighlightAttr(highlightAttr);
|
|
2447
3287
|
const copyAttr = codeProps["data-copy"];
|
|
2448
3288
|
const enableCopy = copyAttr !== void 0 ? copyAttr === true || copyAttr === "true" || copyAttr === "" : false;
|
|
2449
|
-
const [copied, setCopied] =
|
|
2450
|
-
const handleCopy =
|
|
3289
|
+
const [copied, setCopied] = React33.useState(false);
|
|
3290
|
+
const handleCopy = React33.useCallback(async () => {
|
|
2451
3291
|
const text = rawCode;
|
|
2452
3292
|
try {
|
|
2453
3293
|
if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.writeText) {
|
|
@@ -2512,20 +3352,20 @@ function DocsCodeBlock(props = {}) {
|
|
|
2512
3352
|
const highlight = highlightSet.has(lineNumber);
|
|
2513
3353
|
const style = highlight ? { ...baseLineStyle, ...highlightBaseStyle } : baseLineStyle;
|
|
2514
3354
|
const displayLine = line === "" ? " " : line;
|
|
2515
|
-
return
|
|
3355
|
+
return React33.createElement(
|
|
2516
3356
|
"span",
|
|
2517
3357
|
{ key: lineNumber, style },
|
|
2518
|
-
|
|
3358
|
+
React33.createElement("span", { style: lineContentStyle }, displayLine)
|
|
2519
3359
|
);
|
|
2520
3360
|
});
|
|
2521
|
-
return
|
|
3361
|
+
return React33.createElement(
|
|
2522
3362
|
"div",
|
|
2523
3363
|
{ style: containerStyle },
|
|
2524
|
-
showHeader ?
|
|
3364
|
+
showHeader ? React33.createElement(
|
|
2525
3365
|
"div",
|
|
2526
3366
|
{ style: headerStyle },
|
|
2527
|
-
|
|
2528
|
-
enableCopy ?
|
|
3367
|
+
React33.createElement("span", null, showFilename ? filename : null),
|
|
3368
|
+
enableCopy ? React33.createElement(
|
|
2529
3369
|
"button",
|
|
2530
3370
|
{
|
|
2531
3371
|
type: "button",
|
|
@@ -2544,29 +3384,29 @@ function DocsCodeBlock(props = {}) {
|
|
|
2544
3384
|
copied ? "Copied" : "Copy"
|
|
2545
3385
|
) : null
|
|
2546
3386
|
) : null,
|
|
2547
|
-
|
|
3387
|
+
React33.createElement(
|
|
2548
3388
|
"pre",
|
|
2549
3389
|
{ ...preRest, className: preClassName, style: mergedPreStyle },
|
|
2550
|
-
|
|
3390
|
+
React33.createElement("code", { style: codeStyle }, lineElements)
|
|
2551
3391
|
)
|
|
2552
3392
|
);
|
|
2553
3393
|
}
|
|
2554
3394
|
|
|
2555
3395
|
// ui/src/docs/MarkdownTable.jsx
|
|
2556
|
-
import
|
|
3396
|
+
import React34 from "react";
|
|
2557
3397
|
function MarkdownTable({ className = "", ...rest }) {
|
|
2558
3398
|
const merged = ["markdown-table", className].filter(Boolean).join(" ");
|
|
2559
|
-
return /* @__PURE__ */
|
|
3399
|
+
return /* @__PURE__ */ React34.createElement("div", { className: "markdown-table__frame" }, /* @__PURE__ */ React34.createElement("table", { className: merged, ...rest }));
|
|
2560
3400
|
}
|
|
2561
3401
|
|
|
2562
3402
|
// ui/src/docs/Diagram.jsx
|
|
2563
|
-
import
|
|
3403
|
+
import React35 from "react";
|
|
2564
3404
|
function CanopyDiagram() {
|
|
2565
|
-
return /* @__PURE__ */
|
|
3405
|
+
return /* @__PURE__ */ React35.createElement("div", { className: "canopy-diagram" }, /* @__PURE__ */ React35.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--collections" }, /* @__PURE__ */ React35.createElement("h3", null, "IIIF Collection(s)"), /* @__PURE__ */ React35.createElement("span", { className: "canopy-diagram__section-summary" }, "Source collections contribute 105 total manifests that Canopy retrieves as-is via IIIF endpoints."), /* @__PURE__ */ React35.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Collection A"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "70 Manifests"), /* @__PURE__ */ React35.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React35.createElement("li", null, "Textual Annotations"))), /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Collection B"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "35 Manifests"), /* @__PURE__ */ React35.createElement("li", null, "IIIF Images + A/V"), /* @__PURE__ */ React35.createElement("li", null, "Textual Annotations"))))), /* @__PURE__ */ React35.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React35.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React35.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React35.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--build" }, /* @__PURE__ */ React35.createElement("h3", null, "Canopy Build Process"), /* @__PURE__ */ React35.createElement("span", { className: "canopy-diagram__section-summary" }, "Canopy syncs manifests, page content, and annotations before bundling the site."), /* @__PURE__ */ React35.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Automated content"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "105 manifests \u2192 105 work pages"), /* @__PURE__ */ React35.createElement("li", null, "One page per manifest"), /* @__PURE__ */ React35.createElement("li", null, "Customize page layout"))), /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Contextual content"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "Markdown & MDX pages"), /* @__PURE__ */ React35.createElement("li", null, "Author narratives & tours"), /* @__PURE__ */ React35.createElement("li", null, "Reference manifests inline"))), /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Search index"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "Combines works + pages"), /* @__PURE__ */ React35.createElement("li", null, "Customize result layout"), /* @__PURE__ */ React35.createElement("li", null, "Optional annotations"))))), /* @__PURE__ */ React35.createElement("div", { className: "canopy-diagram__arrow", "aria-hidden": "true" }, /* @__PURE__ */ React35.createElement("span", { className: "canopy-diagram__arrow-line" }), /* @__PURE__ */ React35.createElement("span", { className: "canopy-diagram__arrow-head" })), /* @__PURE__ */ React35.createElement("section", { className: "canopy-diagram__section canopy-diagram__section--output" }, /* @__PURE__ */ React35.createElement("h3", null, "Static Digital Project"), /* @__PURE__ */ React35.createElement("span", { className: "canopy-diagram__section-summary" }, "The output is a lightweight bundle of HTML, CSS, JS, and JSON assets that can deploy anywhere."), /* @__PURE__ */ React35.createElement("div", { className: "canopy-diagram__grid" }, /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Work pages"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "105 generated HTML pages"), /* @__PURE__ */ React35.createElement("li", null, "Each links back to source manifests"), /* @__PURE__ */ React35.createElement("li", null, "Styled with Canopy components"))), /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Custom pages"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "Markdown & MDX-authored content"), /* @__PURE__ */ React35.createElement("li", null, "Reusable layouts for narratives"), /* @__PURE__ */ React35.createElement("li", null, "Embed IIIF media & interstitials"))), /* @__PURE__ */ React35.createElement("article", null, /* @__PURE__ */ React35.createElement("h4", null, "Search bundle"), /* @__PURE__ */ React35.createElement("ul", null, /* @__PURE__ */ React35.createElement("li", null, "Static FlexSearch index"), /* @__PURE__ */ React35.createElement("li", null, "Works + pages share records"), /* @__PURE__ */ React35.createElement("li", null, "Optional annotation dataset"))))));
|
|
2566
3406
|
}
|
|
2567
3407
|
|
|
2568
3408
|
// ui/src/docs/ThemeShowcase.jsx
|
|
2569
|
-
import
|
|
3409
|
+
import React36 from "react";
|
|
2570
3410
|
|
|
2571
3411
|
// ../../node_modules/@radix-ui/colors/index.mjs
|
|
2572
3412
|
var colors_exports = {};
|
|
@@ -6399,21 +7239,21 @@ var ACCENT_COLOR_NAMES = [
|
|
|
6399
7239
|
"sky"
|
|
6400
7240
|
];
|
|
6401
7241
|
var GRAY_COLOR_NAMES = ["gray", "mauve", "slate", "sage", "olive", "sand"];
|
|
6402
|
-
var Section = ({ title, description, children }) => /* @__PURE__ */
|
|
6403
|
-
var ColorScaleRow = ({ label, prefix }) => /* @__PURE__ */
|
|
7242
|
+
var Section = ({ title, description, children }) => /* @__PURE__ */ React36.createElement("div", { className: "canopy-theme-showcase__section" }, /* @__PURE__ */ React36.createElement("h3", { className: "canopy-theme-showcase__section-title" }, title), description ? /* @__PURE__ */ React36.createElement("p", { className: "canopy-theme-showcase__section-description" }, description) : null, children);
|
|
7243
|
+
var ColorScaleRow = ({ label, prefix }) => /* @__PURE__ */ React36.createElement("div", { className: "canopy-theme-showcase__scale-row" }, /* @__PURE__ */ React36.createElement("div", { className: "canopy-theme-showcase__scale-label" }, /* @__PURE__ */ React36.createElement("strong", null, label)), /* @__PURE__ */ React36.createElement("div", { className: "canopy-theme-showcase__scale-track" }, COLOR_STOPS.map((stop) => /* @__PURE__ */ React36.createElement(
|
|
6404
7244
|
"div",
|
|
6405
7245
|
{
|
|
6406
7246
|
key: `${label}-${stop}`,
|
|
6407
7247
|
className: "canopy-theme-showcase__scale-stop"
|
|
6408
7248
|
},
|
|
6409
|
-
/* @__PURE__ */
|
|
7249
|
+
/* @__PURE__ */ React36.createElement(
|
|
6410
7250
|
"span",
|
|
6411
7251
|
{
|
|
6412
7252
|
className: "canopy-theme-showcase__scale-chip",
|
|
6413
7253
|
style: { backgroundColor: `var(${prefix}-${stop})` }
|
|
6414
7254
|
}
|
|
6415
7255
|
),
|
|
6416
|
-
/* @__PURE__ */
|
|
7256
|
+
/* @__PURE__ */ React36.createElement("span", { className: "canopy-theme-showcase__scale-token" }, stop)
|
|
6417
7257
|
))));
|
|
6418
7258
|
function ThemeShowcase() {
|
|
6419
7259
|
const accentColors = ACCENT_COLOR_NAMES;
|
|
@@ -6424,15 +7264,15 @@ function ThemeShowcase() {
|
|
|
6424
7264
|
if (!scale) return null;
|
|
6425
7265
|
return scale[`${name}9`] || Object.values(scale)[8];
|
|
6426
7266
|
};
|
|
6427
|
-
const ColorsLabeled = ({ colors }) => /* @__PURE__ */
|
|
7267
|
+
const ColorsLabeled = ({ colors }) => /* @__PURE__ */ React36.createElement("div", { className: "canopy-theme-showcase__swatch-grid" }, colors.map((name) => {
|
|
6428
7268
|
const colorValue = getRadixSwatch(name);
|
|
6429
|
-
return /* @__PURE__ */
|
|
7269
|
+
return /* @__PURE__ */ React36.createElement("div", { key: name, className: "canopy-theme-showcase__swatch" }, /* @__PURE__ */ React36.createElement(
|
|
6430
7270
|
"div",
|
|
6431
7271
|
{
|
|
6432
7272
|
className: "canopy-theme-showcase__swatch-chip",
|
|
6433
7273
|
style: { background: colorValue || "var(--color-gray-200)" }
|
|
6434
7274
|
}
|
|
6435
|
-
), /* @__PURE__ */
|
|
7275
|
+
), /* @__PURE__ */ React36.createElement("div", { className: "canopy-theme-showcase__swatch-label" }, name));
|
|
6436
7276
|
}));
|
|
6437
7277
|
const styles = `
|
|
6438
7278
|
.canopy-theme-showcase__section {
|
|
@@ -6516,13 +7356,13 @@ function ThemeShowcase() {
|
|
|
6516
7356
|
font-weight: 300;
|
|
6517
7357
|
}
|
|
6518
7358
|
`;
|
|
6519
|
-
return /* @__PURE__ */
|
|
7359
|
+
return /* @__PURE__ */ React36.createElement("div", { className: "canopy-theme-showcase" }, /* @__PURE__ */ React36.createElement("style", { dangerouslySetInnerHTML: { __html: styles } }), /* @__PURE__ */ React36.createElement(
|
|
6520
7360
|
Section,
|
|
6521
7361
|
{
|
|
6522
7362
|
title: "Color scales",
|
|
6523
7363
|
description: "Accent and gray ramps from the active theme."
|
|
6524
7364
|
},
|
|
6525
|
-
/* @__PURE__ */
|
|
7365
|
+
/* @__PURE__ */ React36.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "1.5rem" } }, COLOR_SCALES.map((scale) => /* @__PURE__ */ React36.createElement(
|
|
6526
7366
|
ColorScaleRow,
|
|
6527
7367
|
{
|
|
6528
7368
|
key: scale.label,
|
|
@@ -6530,20 +7370,20 @@ function ThemeShowcase() {
|
|
|
6530
7370
|
prefix: scale.prefix
|
|
6531
7371
|
}
|
|
6532
7372
|
)))
|
|
6533
|
-
), /* @__PURE__ */
|
|
7373
|
+
), /* @__PURE__ */ React36.createElement(
|
|
6534
7374
|
Section,
|
|
6535
7375
|
{
|
|
6536
7376
|
title: "Accent palette options",
|
|
6537
7377
|
description: "All accent color families available via Radix Themes."
|
|
6538
7378
|
},
|
|
6539
|
-
/* @__PURE__ */
|
|
6540
|
-
), /* @__PURE__ */
|
|
7379
|
+
/* @__PURE__ */ React36.createElement(ColorsLabeled, { colors: accentColors })
|
|
7380
|
+
), /* @__PURE__ */ React36.createElement(
|
|
6541
7381
|
Section,
|
|
6542
7382
|
{
|
|
6543
7383
|
title: "Gray palette options",
|
|
6544
7384
|
description: "Neutral ramps you can assign via the theme block."
|
|
6545
7385
|
},
|
|
6546
|
-
/* @__PURE__ */
|
|
7386
|
+
/* @__PURE__ */ React36.createElement(ColorsLabeled, { colors: grayColors })
|
|
6547
7387
|
));
|
|
6548
7388
|
}
|
|
6549
7389
|
export {
|
|
@@ -6578,7 +7418,10 @@ export {
|
|
|
6578
7418
|
Slider,
|
|
6579
7419
|
SubNavigation,
|
|
6580
7420
|
Summary,
|
|
7421
|
+
TeaserCard,
|
|
6581
7422
|
ThemeShowcase,
|
|
7423
|
+
MdxTimeline as Timeline,
|
|
7424
|
+
TimelinePoint,
|
|
6582
7425
|
Viewer
|
|
6583
7426
|
};
|
|
6584
7427
|
//# sourceMappingURL=server.mjs.map
|