@quartz-community/bases-page 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,929 @@
1
+ import { createRequire } from 'module';
2
+ import { viewRegistry, registerCustomViews } from './chunk-2AUMER56.js';
3
+ import { u, evaluate, evaluateFilter, resolvePropertyValue, S, transformLink, slugifyPath } from './chunk-X2AZ5GOJ.js';
4
+
5
+ createRequire(import.meta.url);
6
+
7
+ // src/components/ViewSelector.tsx
8
+ function ViewSelector({ views, activeIndex }) {
9
+ if (views.length <= 1) return null;
10
+ return /* @__PURE__ */ u("div", { class: "bases-view-tabs", role: "tablist", children: views.map((view, index) => /* @__PURE__ */ u(
11
+ "button",
12
+ {
13
+ type: "button",
14
+ class: index === activeIndex ? "is-active" : "",
15
+ "data-view-index": index,
16
+ children: view.name ?? view.type
17
+ }
18
+ )) });
19
+ }
20
+
21
+ // src/resolver.ts
22
+ function normalizeStringArray(values) {
23
+ if (!Array.isArray(values)) return [];
24
+ return values.filter((value) => typeof value === "string");
25
+ }
26
+ function getFilePath(fileData, slug) {
27
+ if (typeof fileData.relativePath === "string") return fileData.relativePath;
28
+ if (typeof fileData.filePath === "string") return fileData.filePath;
29
+ return slug ? `${slug}.md` : "";
30
+ }
31
+ function getFileName(path) {
32
+ const lastSlash = path.lastIndexOf("/");
33
+ return lastSlash >= 0 ? path.slice(lastSlash + 1) : path;
34
+ }
35
+ function getBaseName(path) {
36
+ const fileName = getFileName(path);
37
+ const dot = fileName.lastIndexOf(".");
38
+ return dot > 0 ? fileName.slice(0, dot) : fileName;
39
+ }
40
+ function toDate(value) {
41
+ if (value instanceof Date && !Number.isNaN(value.getTime())) return value;
42
+ if (typeof value === "string") {
43
+ const parsed = Date.parse(value);
44
+ if (!Number.isNaN(parsed)) return new Date(parsed);
45
+ }
46
+ return void 0;
47
+ }
48
+ function buildFileProperties(fileData, slug, frontmatter) {
49
+ const filePath = getFilePath(fileData, slug);
50
+ const baseName = filePath ? getBaseName(filePath) : getBaseName(slug);
51
+ const name = baseName || slug.split("/").pop() || "Untitled";
52
+ const basename = baseName || slug.split("/").pop() || "Untitled";
53
+ const lastSlash = filePath.lastIndexOf("/");
54
+ const folder = lastSlash >= 0 ? filePath.slice(0, lastSlash) : "";
55
+ const lastDot = filePath.lastIndexOf(".");
56
+ const ext = lastDot >= 0 ? filePath.slice(lastDot + 1) : "";
57
+ const tags = normalizeStringArray(frontmatter.tags);
58
+ const links = normalizeStringArray(fileData.links ?? fileData.outgoingLinks);
59
+ const embeds = normalizeStringArray(fileData.embeds);
60
+ const dates = fileData.dates;
61
+ const ctime = toDate(dates?.created);
62
+ const mtime = toDate(dates?.modified);
63
+ return {
64
+ name,
65
+ basename,
66
+ path: filePath,
67
+ folder,
68
+ ext,
69
+ tags,
70
+ links,
71
+ embeds,
72
+ created: ctime?.toISOString(),
73
+ modified: mtime?.toISOString(),
74
+ ctime,
75
+ mtime
76
+ };
77
+ }
78
+ function compareSort(a, b) {
79
+ if (a === b) return 0;
80
+ if (a === void 0 || a === null) return 1;
81
+ if (b === void 0 || b === null) return -1;
82
+ if (typeof a === "number" && typeof b === "number") return a - b;
83
+ const dateA = typeof a === "string" ? Date.parse(a) : NaN;
84
+ const dateB = typeof b === "string" ? Date.parse(b) : NaN;
85
+ if (!Number.isNaN(dateA) && !Number.isNaN(dateB)) return dateA - dateB;
86
+ return String(a).localeCompare(String(b));
87
+ }
88
+ function buildSortKeys(view) {
89
+ if (view?.sort && view.sort.length > 0) return view.sort;
90
+ if (view?.groupBy?.property) {
91
+ return [{ property: view.groupBy.property, direction: view.groupBy.direction ?? "ASC" }];
92
+ }
93
+ if (view?.order && view.order.length > 0) {
94
+ return view.order.map((property) => ({ property, direction: "ASC" }));
95
+ }
96
+ return [];
97
+ }
98
+ function sortEntries(entries, view) {
99
+ const sortKeys = buildSortKeys(view);
100
+ if (sortKeys.length === 0) return entries;
101
+ return [...entries].sort((left, right) => {
102
+ for (const key of sortKeys) {
103
+ const sign = key.direction === "DESC" ? -1 : 1;
104
+ const leftValue = resolvePropertyValue(key.property, {
105
+ note: left.properties,
106
+ file: left.fileProperties,
107
+ formula: left.formulaValues
108
+ });
109
+ const rightValue = resolvePropertyValue(key.property, {
110
+ note: right.properties,
111
+ file: right.fileProperties,
112
+ formula: right.formulaValues
113
+ });
114
+ const cmp = compareSort(leftValue, rightValue);
115
+ if (cmp !== 0) return sign * cmp;
116
+ }
117
+ return 0;
118
+ });
119
+ }
120
+ function resolveBasesEntries(basesData, allFiles, view, selfContext) {
121
+ const entries = [];
122
+ const formulas = basesData.formulas ?? {};
123
+ const fileLookup = /* @__PURE__ */ new Map();
124
+ for (const fd of allFiles) {
125
+ if (fd.unlisted === true) continue;
126
+ const fdSlug = typeof fd.slug === "string" ? fd.slug : "";
127
+ if (!fdSlug) continue;
128
+ const fdPath = getFilePath(fd, fdSlug);
129
+ const fm = fd.frontmatter ?? {};
130
+ const fp = buildFileProperties(fd, fdSlug, fm);
131
+ const fileValue = { ...fp, properties: fm };
132
+ fileLookup.set(fdPath, fileValue);
133
+ const withoutExt = fdPath.replace(/\.md$/, "");
134
+ if (withoutExt !== fdPath) fileLookup.set(withoutExt, fileValue);
135
+ if (fdSlug && !fileLookup.has(fdSlug)) {
136
+ fileLookup.set(fdSlug, fileValue);
137
+ }
138
+ const base = getBaseName(fdPath);
139
+ if (base && !fileLookup.has(base)) {
140
+ fileLookup.set(base, fileValue);
141
+ }
142
+ }
143
+ for (const fileData of allFiles) {
144
+ if (fileData.unlisted === true) continue;
145
+ const slug = typeof fileData.slug === "string" ? fileData.slug : "";
146
+ if (!slug) continue;
147
+ const filePath = typeof fileData.filePath === "string" ? fileData.filePath : "";
148
+ if (filePath.endsWith(".base") || slug.endsWith(".base")) continue;
149
+ const frontmatter = fileData.frontmatter ?? {};
150
+ const fileProperties = buildFileProperties(fileData, slug, frontmatter);
151
+ const context = {
152
+ note: frontmatter,
153
+ file: { ...fileProperties, properties: frontmatter },
154
+ formula: {},
155
+ self: selfContext,
156
+ _fileLookup: fileLookup
157
+ };
158
+ for (const [name, expr] of Object.entries(formulas)) {
159
+ context.formula[name] = evaluate(expr, context);
160
+ }
161
+ if (!evaluateFilter(basesData.filters, context)) continue;
162
+ if (view?.filters && !evaluateFilter(view.filters, context)) continue;
163
+ const title = typeof frontmatter.title === "string" ? frontmatter.title : fileProperties.basename || slug.split("/").pop() || "Untitled";
164
+ entries.push({
165
+ slug,
166
+ title,
167
+ properties: frontmatter,
168
+ fileProperties,
169
+ formulaValues: context.formula
170
+ });
171
+ }
172
+ const total = entries.length;
173
+ const sorted = sortEntries(entries, view);
174
+ const limited = view?.limit ? sorted.slice(0, view.limit) : sorted;
175
+ return { entries: limited, total };
176
+ }
177
+
178
+ // src/i18n/locales/en-US.ts
179
+ var en_US_default = {
180
+ components: {
181
+ bases: {
182
+ title: "Base",
183
+ noData: "No data found.",
184
+ noViews: "No views defined.",
185
+ mapPlaceholder: "Map view is not available in static builds.",
186
+ allNotes: "All notes",
187
+ allEntries: "All entries",
188
+ galleryView: "Gallery",
189
+ boardView: "Board",
190
+ noImage: "No image available",
191
+ uncategorized: "Uncategorized",
192
+ showingCount: "Showing {count} of {total} entries"
193
+ }
194
+ }
195
+ };
196
+
197
+ // src/i18n/index.ts
198
+ var locales = {
199
+ "en-US": en_US_default
200
+ };
201
+ function i18n(locale) {
202
+ return locales[locale] || en_US_default;
203
+ }
204
+
205
+ // src/components/shared/links.tsx
206
+ var WIKILINK_RE = /\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g;
207
+ var MDLINK_RE = /\[([^\]]*)\]\(([^)]+)\)/g;
208
+ var URL_RE = /https?:\/\/[^\s<>]+/g;
209
+ function renderTextWithLinks(text, ctx) {
210
+ const segments = [];
211
+ const transformOpts = {
212
+ strategy: ctx.linkResolution,
213
+ allSlugs: ctx.allSlugs
214
+ };
215
+ for (const match of text.matchAll(WIKILINK_RE)) {
216
+ const target = match[1] ?? "";
217
+ const display = match[2] ?? target;
218
+ const href = transformLink(ctx.slug, target, transformOpts);
219
+ segments.push({
220
+ start: match.index ?? 0,
221
+ end: (match.index ?? 0) + match[0].length,
222
+ node: /* @__PURE__ */ u("a", { href, class: "internal internal-link", children: display })
223
+ });
224
+ }
225
+ for (const match of text.matchAll(MDLINK_RE)) {
226
+ const start = match.index ?? 0;
227
+ const end = start + match[0].length;
228
+ const overlaps = segments.some((segment) => start < segment.end && end > segment.start);
229
+ if (overlaps) continue;
230
+ const display = match[1] ?? "";
231
+ const href = match[2] ?? "";
232
+ const isExternal = href.startsWith("http://") || href.startsWith("https://");
233
+ const resolvedHref = isExternal ? href : String(transformLink(ctx.slug, href, transformOpts));
234
+ segments.push({
235
+ start,
236
+ end,
237
+ node: /* @__PURE__ */ u(
238
+ "a",
239
+ {
240
+ href: resolvedHref,
241
+ class: isExternal ? "external external-link" : "internal internal-link",
242
+ ...isExternal ? { target: "_blank", rel: "noopener noreferrer" } : {},
243
+ children: display || href
244
+ }
245
+ )
246
+ });
247
+ }
248
+ for (const match of text.matchAll(URL_RE)) {
249
+ const start = match.index ?? 0;
250
+ const end = start + match[0].length;
251
+ const overlaps = segments.some((segment) => start < segment.end && end > segment.start);
252
+ if (overlaps) continue;
253
+ segments.push({
254
+ start,
255
+ end,
256
+ node: /* @__PURE__ */ u("a", { href: match[0], class: "external external-link", target: "_blank", rel: "noopener noreferrer", children: match[0] })
257
+ });
258
+ }
259
+ if (segments.length === 0) return [text];
260
+ segments.sort((a, b) => a.start - b.start);
261
+ const result = [];
262
+ let cursor = 0;
263
+ for (const segment of segments) {
264
+ if (segment.start > cursor) {
265
+ result.push(text.slice(cursor, segment.start));
266
+ }
267
+ result.push(segment.node);
268
+ cursor = segment.end;
269
+ }
270
+ if (cursor < text.length) {
271
+ result.push(text.slice(cursor));
272
+ }
273
+ return result;
274
+ }
275
+
276
+ // src/components/shared/cell.tsx
277
+ function isFileValue(value) {
278
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
279
+ const record = value;
280
+ return typeof record.name === "string" && typeof record.basename === "string" && typeof record.path === "string" && typeof record.folder === "string" && typeof record.ext === "string";
281
+ }
282
+ function formatValue(value) {
283
+ if (value === void 0 || value === null) return "";
284
+ if (Array.isArray(value)) return value.map((item) => String(item)).join(", ");
285
+ if (typeof value === "object") return JSON.stringify(value);
286
+ return String(value);
287
+ }
288
+ function renderCellValue(value, ctx) {
289
+ if (value === null || value === void 0) {
290
+ return /* @__PURE__ */ u("span", { class: "bases-empty", children: "\u2014" });
291
+ }
292
+ if (typeof value === "boolean") {
293
+ return /* @__PURE__ */ u("input", { type: "checkbox", checked: value, disabled: true });
294
+ }
295
+ if (typeof value === "number") {
296
+ return /* @__PURE__ */ u("span", { class: "bases-number", children: value });
297
+ }
298
+ if (typeof value === "string") {
299
+ const parts = renderTextWithLinks(value, ctx);
300
+ return /* @__PURE__ */ u("span", { class: "bases-text", children: parts });
301
+ }
302
+ if (Array.isArray(value)) {
303
+ const items = value.map((item, index) => /* @__PURE__ */ u(S, { children: [
304
+ index > 0 && /* @__PURE__ */ u("span", { class: "bases-separator", children: ", " }),
305
+ renderCellValue(item, ctx)
306
+ ] }));
307
+ return /* @__PURE__ */ u("span", { class: "bases-list", children: items });
308
+ }
309
+ if (typeof value === "object") {
310
+ if (isFileValue(value)) {
311
+ const href = transformLink(
312
+ ctx.slug,
313
+ slugifyPath(value.path.replace(/\.md$/, "")),
314
+ {
315
+ strategy: ctx.linkResolution,
316
+ allSlugs: ctx.allSlugs
317
+ }
318
+ );
319
+ return /* @__PURE__ */ u("a", { href, class: "internal internal-link", children: value.basename });
320
+ }
321
+ return /* @__PURE__ */ u("code", { children: JSON.stringify(value) });
322
+ }
323
+ return String(value);
324
+ }
325
+ function isEmptyValue(value) {
326
+ if (value === void 0 || value === null || value === "") return true;
327
+ if (Array.isArray(value)) return value.length === 0;
328
+ return false;
329
+ }
330
+ function getColumnLabel(column, basesData) {
331
+ const config = basesData.properties?.[column];
332
+ if (config?.displayName) return config.displayName;
333
+ const segment = column.split(".").pop() ?? column;
334
+ return segment.split("_").map((part) => part ? part.charAt(0).toUpperCase() + part.slice(1) : part).join(" ");
335
+ }
336
+ function getColumns(view, basesData, entries) {
337
+ if (view.order && view.order.length > 0) return view.order;
338
+ const columns = /* @__PURE__ */ new Set();
339
+ columns.add("file.name");
340
+ const propertyKeys = basesData.properties ? Object.keys(basesData.properties) : [];
341
+ if (propertyKeys.length > 0) {
342
+ propertyKeys.forEach((key) => {
343
+ columns.add(key);
344
+ });
345
+ } else if (entries.length > 0) {
346
+ const firstEntry = entries[0];
347
+ if (firstEntry) {
348
+ Object.keys(firstEntry.properties).forEach((key) => {
349
+ columns.add(key);
350
+ });
351
+ }
352
+ }
353
+ return Array.from(columns);
354
+ }
355
+ function getNestedValue(value, path) {
356
+ let current = value;
357
+ for (const segment of path) {
358
+ if (segment === "") continue;
359
+ if (Array.isArray(current)) {
360
+ const index = Number(segment);
361
+ if (Number.isNaN(index)) return void 0;
362
+ current = current[index];
363
+ continue;
364
+ }
365
+ if (current && typeof current === "object") {
366
+ const record = current;
367
+ current = record[segment];
368
+ continue;
369
+ }
370
+ return void 0;
371
+ }
372
+ return current;
373
+ }
374
+ function resolveEntryPropertyValue(column, entry) {
375
+ if (column.startsWith("note.")) {
376
+ return getNestedValue(entry.properties, column.slice(5).split("."));
377
+ }
378
+ if (column.startsWith("file.")) {
379
+ return getNestedValue(entry.fileProperties, column.slice(5).split("."));
380
+ }
381
+ if (column.startsWith("formula.")) {
382
+ return getNestedValue(entry.formulaValues, column.slice(8).split("."));
383
+ }
384
+ return getNestedValue(entry.properties, column.split("."));
385
+ }
386
+
387
+ // src/components/views/board.tsx
388
+ function formatMessage(template, values) {
389
+ return Object.entries(values).reduce(
390
+ (text, [key, value]) => text.replace(`{${key}}`, String(value)),
391
+ template
392
+ );
393
+ }
394
+ var BoardView = ({
395
+ entries,
396
+ view,
397
+ basesData,
398
+ total,
399
+ locale,
400
+ slug,
401
+ allSlugs,
402
+ linkResolution
403
+ }) => {
404
+ const localeStrings = i18n(locale).components.bases;
405
+ const groupProperty = view.groupBy?.property ?? view.boardProperty;
406
+ const columns = getColumns(view, basesData, entries).filter((column) => column !== groupProperty);
407
+ const groups = /* @__PURE__ */ new Map();
408
+ const emptyLabel = groupProperty ? localeStrings.uncategorized : localeStrings.allEntries;
409
+ const transformOpts = { strategy: linkResolution, allSlugs };
410
+ for (const entry of entries) {
411
+ const rawValue = groupProperty ? resolveEntryPropertyValue(groupProperty, entry) : void 0;
412
+ const label = isEmptyValue(rawValue) ? emptyLabel : formatValue(rawValue);
413
+ const key = label || emptyLabel;
414
+ const existing = groups.get(key);
415
+ if (existing) {
416
+ existing.entries.push(entry);
417
+ } else {
418
+ groups.set(key, { label: key, entries: [entry] });
419
+ }
420
+ }
421
+ if (groups.size === 0) {
422
+ groups.set(localeStrings.allEntries, { label: localeStrings.allEntries, entries });
423
+ }
424
+ return /* @__PURE__ */ u("div", { class: "bases-board-wrapper", children: [
425
+ /* @__PURE__ */ u("div", { class: "bases-view-meta", children: formatMessage(localeStrings.showingCount, {
426
+ count: entries.length,
427
+ total
428
+ }) }),
429
+ /* @__PURE__ */ u("div", { class: "bases-board", children: Array.from(groups.values()).map((group) => /* @__PURE__ */ u("div", { class: "bases-board-column", children: [
430
+ /* @__PURE__ */ u("div", { class: "bases-board-column-header", children: [
431
+ /* @__PURE__ */ u("span", { children: group.label }),
432
+ /* @__PURE__ */ u("span", { class: "bases-board-count", children: group.entries.length })
433
+ ] }),
434
+ /* @__PURE__ */ u("div", { class: "bases-board-column-body", children: group.entries.map((entry) => {
435
+ const ctx = { slug, allSlugs, linkResolution };
436
+ return /* @__PURE__ */ u("div", { class: "bases-board-card", children: [
437
+ /* @__PURE__ */ u(
438
+ "a",
439
+ {
440
+ href: transformLink(slug, entry.slug, transformOpts),
441
+ class: "internal internal-link",
442
+ "data-slug": entry.slug,
443
+ children: entry.title
444
+ }
445
+ ),
446
+ columns.length > 0 && /* @__PURE__ */ u("div", { class: "bases-board-card-meta", children: columns.map((column) => {
447
+ const value = resolveEntryPropertyValue(column, entry);
448
+ if (isEmptyValue(value)) return null;
449
+ return /* @__PURE__ */ u("div", { class: "bases-board-card-row", children: [
450
+ /* @__PURE__ */ u("span", { class: "bases-board-card-label", children: getColumnLabel(column, basesData) }),
451
+ /* @__PURE__ */ u("span", { class: "bases-board-card-value", children: renderCellValue(value, ctx) })
452
+ ] });
453
+ }) })
454
+ ] });
455
+ }) })
456
+ ] })) })
457
+ ] });
458
+ };
459
+ var boardViewRegistration = {
460
+ id: "board",
461
+ name: "Board",
462
+ icon: "columns",
463
+ render: BoardView
464
+ };
465
+
466
+ // src/components/views/cards.tsx
467
+ function formatMessage2(template, values) {
468
+ return Object.entries(values).reduce(
469
+ (text, [key, value]) => text.replace(`{${key}}`, String(value)),
470
+ template
471
+ );
472
+ }
473
+ var HEX_COLOR_RE = /^#(?:[0-9a-f]{3}){1,2}$/i;
474
+ var WIKILINK_RE2 = /^\[\[(.+?)(?:\|.*)?\]\]$/;
475
+ function resolveImageSrc(raw, opts) {
476
+ if (!raw) return { src: "", isColor: false };
477
+ if (HEX_COLOR_RE.test(raw)) {
478
+ return { src: raw, isColor: true };
479
+ }
480
+ const wikiMatch = WIKILINK_RE2.exec(raw);
481
+ if (wikiMatch?.[1]) {
482
+ const target = wikiMatch[1].trim();
483
+ const resolved = transformLink(opts.slug, target, {
484
+ strategy: opts.linkResolution,
485
+ allSlugs: opts.allSlugs
486
+ });
487
+ return { src: String(resolved), isColor: false };
488
+ }
489
+ return { src: raw, isColor: false };
490
+ }
491
+ var CardsView = ({
492
+ entries,
493
+ view,
494
+ basesData,
495
+ total,
496
+ locale,
497
+ slug,
498
+ allSlugs,
499
+ linkResolution
500
+ }) => {
501
+ const imageProperty = typeof view.image === "string" ? view.image : void 0;
502
+ const cardMetaColumns = view.order && view.order.length > 0 ? view.order.filter((column) => column !== imageProperty && column !== "file.name") : [];
503
+ const localeStrings = i18n(locale).components.bases;
504
+ const cardSize = view.cardSize;
505
+ const aspectRatio = view.imageAspectRatio ?? view.cardAspect;
506
+ const imageFit = view.imageFit === "contain" ? "contain" : "cover";
507
+ const gridStyle = typeof cardSize === "number" && cardSize > 0 ? { gridTemplateColumns: `repeat(auto-fit, minmax(${cardSize}px, 1fr))` } : void 0;
508
+ const imageOpts = { slug, allSlugs, linkResolution };
509
+ const transformOpts = { strategy: linkResolution, allSlugs };
510
+ return /* @__PURE__ */ u("div", { class: "bases-cards-wrapper", children: [
511
+ /* @__PURE__ */ u("div", { class: "bases-view-meta", children: formatMessage2(localeStrings.showingCount, {
512
+ count: entries.length,
513
+ total
514
+ }) }),
515
+ /* @__PURE__ */ u("div", { class: "bases-cards", style: gridStyle, children: entries.map((entry) => {
516
+ const ctx = { slug, allSlugs, linkResolution };
517
+ const imageValue = imageProperty ? resolveEntryPropertyValue(imageProperty, entry) : void 0;
518
+ const rawImage = imageValue ? String(imageValue) : "";
519
+ const { src: imageSrc, isColor } = resolveImageSrc(rawImage, imageOpts);
520
+ const imageAspect = typeof aspectRatio === "number" && aspectRatio > 0 ? { aspectRatio: String(aspectRatio) } : void 0;
521
+ const href = transformLink(slug, entry.slug, transformOpts);
522
+ return /* @__PURE__ */ u("a", { href, class: "internal internal-link bases-card", "data-slug": entry.slug, children: [
523
+ imageSrc && !isColor && /* @__PURE__ */ u("div", { class: "bases-card-image", style: imageAspect, children: /* @__PURE__ */ u(
524
+ "img",
525
+ {
526
+ src: imageSrc,
527
+ alt: entry.title,
528
+ loading: "lazy",
529
+ style: { objectFit: imageFit }
530
+ }
531
+ ) }),
532
+ imageSrc && isColor && /* @__PURE__ */ u(
533
+ "div",
534
+ {
535
+ class: "bases-card-image bases-card-color",
536
+ style: { ...imageAspect, backgroundColor: imageSrc }
537
+ }
538
+ ),
539
+ /* @__PURE__ */ u("div", { class: "bases-card-body", children: [
540
+ /* @__PURE__ */ u("span", { class: "bases-card-title", children: entry.title }),
541
+ /* @__PURE__ */ u("div", { class: "bases-card-meta", children: cardMetaColumns.map((column) => {
542
+ const value = resolveEntryPropertyValue(column, entry);
543
+ if (isEmptyValue(value)) return null;
544
+ return /* @__PURE__ */ u("div", { class: "bases-card-row", children: [
545
+ /* @__PURE__ */ u("span", { class: "bases-card-label", children: getColumnLabel(column, basesData) }),
546
+ /* @__PURE__ */ u("span", { class: "bases-card-value", children: renderCellValue(value, ctx) })
547
+ ] });
548
+ }) })
549
+ ] })
550
+ ] });
551
+ }) })
552
+ ] });
553
+ };
554
+ var cardsViewRegistration = {
555
+ id: "cards",
556
+ name: "Cards",
557
+ icon: "layout-grid",
558
+ render: CardsView
559
+ };
560
+
561
+ // src/components/views/gallery.tsx
562
+ function formatMessage3(template, values) {
563
+ return Object.entries(values).reduce(
564
+ (text, [key, value]) => text.replace(`{${key}}`, String(value)),
565
+ template
566
+ );
567
+ }
568
+ var GalleryView = ({
569
+ entries,
570
+ view,
571
+ total,
572
+ locale,
573
+ slug,
574
+ allSlugs,
575
+ linkResolution
576
+ }) => {
577
+ const imageProperty = typeof view.image === "string" ? view.image : void 0;
578
+ const localeStrings = i18n(locale).components.bases;
579
+ const columns = typeof view.cardSize === "number" && view.cardSize > 0 ? Math.round(view.cardSize) : 3;
580
+ const gridStyle = { gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` };
581
+ const imageOpts = { slug, allSlugs, linkResolution };
582
+ const transformOpts = { strategy: linkResolution, allSlugs };
583
+ return /* @__PURE__ */ u("div", { class: "bases-gallery-wrapper", children: [
584
+ /* @__PURE__ */ u("div", { class: "bases-view-meta", children: formatMessage3(localeStrings.showingCount, {
585
+ count: entries.length,
586
+ total
587
+ }) }),
588
+ /* @__PURE__ */ u("div", { class: "bases-gallery", style: gridStyle, children: entries.map((entry) => {
589
+ const imageValue = imageProperty ? resolveEntryPropertyValue(imageProperty, entry) : void 0;
590
+ const rawImage = imageValue ? String(imageValue) : "";
591
+ const { src: imageSrc, isColor } = resolveImageSrc(rawImage, imageOpts);
592
+ return /* @__PURE__ */ u("div", { class: "bases-gallery-item", children: [
593
+ /* @__PURE__ */ u("div", { class: "bases-gallery-image", children: imageSrc && !isColor ? /* @__PURE__ */ u("img", { src: imageSrc, alt: entry.title, loading: "lazy" }) : imageSrc && isColor ? /* @__PURE__ */ u("span", { class: "bases-gallery-placeholder", style: { background: imageSrc } }) : /* @__PURE__ */ u(
594
+ "span",
595
+ {
596
+ class: "bases-gallery-placeholder",
597
+ role: "img",
598
+ "aria-label": localeStrings.noImage
599
+ }
600
+ ) }),
601
+ /* @__PURE__ */ u("div", { class: "bases-gallery-title", children: /* @__PURE__ */ u(
602
+ "a",
603
+ {
604
+ href: transformLink(slug, entry.slug, transformOpts),
605
+ class: "internal internal-link",
606
+ "data-slug": entry.slug,
607
+ children: entry.title
608
+ }
609
+ ) })
610
+ ] });
611
+ }) })
612
+ ] });
613
+ };
614
+ var galleryViewRegistration = {
615
+ id: "gallery",
616
+ name: "Gallery",
617
+ icon: "image",
618
+ render: GalleryView
619
+ };
620
+
621
+ // src/components/views/list.tsx
622
+ function formatMessage4(template, values) {
623
+ return Object.entries(values).reduce(
624
+ (text, [key, value]) => text.replace(`{${key}}`, String(value)),
625
+ template
626
+ );
627
+ }
628
+ var ListView = ({
629
+ entries,
630
+ view,
631
+ basesData,
632
+ total,
633
+ locale,
634
+ slug,
635
+ allSlugs,
636
+ linkResolution
637
+ }) => {
638
+ const columns = getColumns(view, basesData, entries);
639
+ const localeStrings = i18n(locale).components.bases;
640
+ const transformOpts = { strategy: linkResolution, allSlugs };
641
+ return /* @__PURE__ */ u("div", { class: "bases-list-wrapper", children: [
642
+ /* @__PURE__ */ u("div", { class: "bases-view-meta", children: formatMessage4(localeStrings.showingCount, {
643
+ count: entries.length,
644
+ total
645
+ }) }),
646
+ /* @__PURE__ */ u("div", { class: "bases-list-group", children: /* @__PURE__ */ u("div", { class: "bases-list-group-list", children: entries.map((entry) => {
647
+ const ctx = { slug, allSlugs, linkResolution };
648
+ const primaryColumn = columns[0] ?? "file.name";
649
+ const secondaryColumns = columns.slice(1);
650
+ const primaryValue = primaryColumn === "file.name" ? /* @__PURE__ */ u(
651
+ "a",
652
+ {
653
+ href: transformLink(slug, entry.slug, transformOpts),
654
+ class: "internal internal-link",
655
+ "data-slug": entry.slug,
656
+ children: entry.title
657
+ }
658
+ ) : renderCellValue(resolveEntryPropertyValue(primaryColumn, entry), ctx);
659
+ const secondaryItems = [];
660
+ for (const column of secondaryColumns) {
661
+ const value = resolveEntryPropertyValue(column, entry);
662
+ if (isEmptyValue(value)) continue;
663
+ secondaryItems.push(
664
+ /* @__PURE__ */ u("span", { class: "bases-list-property", children: /* @__PURE__ */ u("span", { class: "bases-rendered-value", children: renderCellValue(value, ctx) }) })
665
+ );
666
+ }
667
+ return /* @__PURE__ */ u("div", { class: "bases-list-item", children: /* @__PURE__ */ u("div", { class: "bases-list-item-properties", children: [
668
+ /* @__PURE__ */ u("span", { class: "bases-list-property", children: [
669
+ /* @__PURE__ */ u("span", { class: "list-bullet", children: "-" }),
670
+ /* @__PURE__ */ u("span", { class: "bases-rendered-value", children: primaryValue })
671
+ ] }),
672
+ secondaryItems.map((item) => /* @__PURE__ */ u(S, { children: [
673
+ /* @__PURE__ */ u("span", { class: "bases-list-separator", children: ", " }),
674
+ item
675
+ ] }))
676
+ ] }) });
677
+ }) }) })
678
+ ] });
679
+ };
680
+ var listViewRegistration = {
681
+ id: "list",
682
+ name: "List",
683
+ icon: "list",
684
+ render: ListView
685
+ };
686
+
687
+ // src/components/shared/summary.tsx
688
+ function computeSummary(values, summary) {
689
+ const nonEmpty = values.filter((value) => value !== void 0 && value !== null && value !== "");
690
+ if (summary === "Empty") return String(values.length - nonEmpty.length);
691
+ if (summary === "Filled") return String(nonEmpty.length);
692
+ if (summary === "Checked") return String(values.filter((value) => value === true).length);
693
+ if (summary === "Unchecked") return String(values.filter((value) => value === false).length);
694
+ if (summary === "Unique") return String(new Set(values.map((value) => String(value))).size);
695
+ const numeric = nonEmpty.map((value) => typeof value === "number" ? value : Number(value)).filter((value) => !Number.isNaN(value));
696
+ if (numeric.length === 0) return summary;
697
+ if (summary === "Sum") return String(numeric.reduce((acc, value) => acc + value, 0));
698
+ if (summary === "Average")
699
+ return String(numeric.reduce((acc, value) => acc + value, 0) / numeric.length);
700
+ if (summary === "Min") return String(Math.min(...numeric));
701
+ if (summary === "Max") return String(Math.max(...numeric));
702
+ if (summary === "Range") return String(Math.max(...numeric) - Math.min(...numeric));
703
+ if (summary === "Median") {
704
+ const sorted = [...numeric].sort((a, b) => a - b);
705
+ const mid = Math.floor(sorted.length / 2);
706
+ const upper = sorted[mid] ?? 0;
707
+ const lower = sorted[mid - 1] ?? upper;
708
+ const median = sorted.length % 2 === 0 ? (lower + upper) / 2 : upper;
709
+ return String(median);
710
+ }
711
+ if (summary === "Stddev") {
712
+ const mean = numeric.reduce((acc, value) => acc + value, 0) / numeric.length;
713
+ const variance = numeric.reduce((acc, value) => acc + Math.pow(value - mean, 2), 0) / numeric.length;
714
+ return String(Math.sqrt(variance));
715
+ }
716
+ return summary;
717
+ }
718
+
719
+ // src/components/views/table.tsx
720
+ function formatMessage5(template, values) {
721
+ return Object.entries(values).reduce(
722
+ (text, [key, value]) => text.replace(`{${key}}`, String(value)),
723
+ template
724
+ );
725
+ }
726
+ function groupEntries(entries, groupProperty, emptyLabel) {
727
+ if (!groupProperty) return null;
728
+ const groups = /* @__PURE__ */ new Map();
729
+ for (const entry of entries) {
730
+ const rawValue = resolveEntryPropertyValue(groupProperty, entry);
731
+ const label = isEmptyValue(rawValue) ? emptyLabel : formatValue(rawValue);
732
+ const key = label || emptyLabel;
733
+ const existing = groups.get(key);
734
+ if (existing) {
735
+ existing.push(entry);
736
+ } else {
737
+ groups.set(key, [entry]);
738
+ }
739
+ }
740
+ return groups.size > 0 ? groups : null;
741
+ }
742
+ function renderRow(entry, columns, view, slug, allSlugs, linkResolution) {
743
+ const transformOpts = { strategy: linkResolution, allSlugs };
744
+ const ctx = { slug, allSlugs, linkResolution };
745
+ return /* @__PURE__ */ u("tr", { children: columns.map((column) => {
746
+ const value = resolveEntryPropertyValue(column, entry);
747
+ const display = formatValue(value);
748
+ const isPrimary = column === "file.name" || column === "title";
749
+ const columnWidth = view.columnSize?.[column];
750
+ const style = columnWidth ? { width: `${columnWidth}px`, minWidth: `${columnWidth}px` } : void 0;
751
+ return /* @__PURE__ */ u("td", { "data-value": display, style, children: isPrimary ? /* @__PURE__ */ u(
752
+ "a",
753
+ {
754
+ href: transformLink(slug, entry.slug, transformOpts),
755
+ class: "internal internal-link",
756
+ "data-slug": entry.slug,
757
+ children: display || entry.title
758
+ }
759
+ ) : renderCellValue(value, ctx) });
760
+ }) });
761
+ }
762
+ var TableView = ({
763
+ entries,
764
+ view,
765
+ basesData,
766
+ total,
767
+ locale,
768
+ slug,
769
+ allSlugs,
770
+ linkResolution
771
+ }) => {
772
+ const columns = getColumns(view, basesData, entries);
773
+ const summaries = view.summaries ?? {};
774
+ const hasSummary = Object.keys(summaries).length > 0;
775
+ const localeStrings = i18n(locale).components.bases;
776
+ const groupProperty = view.groupBy?.property;
777
+ const groupPropertyLabel = groupProperty ? getColumnLabel(groupProperty, basesData) : "";
778
+ const groups = groupEntries(entries, groupProperty, localeStrings.uncategorized);
779
+ return /* @__PURE__ */ u("div", { class: "bases-table-wrapper", children: [
780
+ /* @__PURE__ */ u("div", { class: "bases-view-meta", children: formatMessage5(localeStrings.showingCount, {
781
+ count: entries.length,
782
+ total
783
+ }) }),
784
+ /* @__PURE__ */ u("table", { class: "bases-table", "data-view-type": "table", children: [
785
+ /* @__PURE__ */ u("thead", { children: /* @__PURE__ */ u("tr", { children: columns.map((column) => {
786
+ const columnWidth = view.columnSize?.[column];
787
+ const style = columnWidth ? { width: `${columnWidth}px`, minWidth: `${columnWidth}px` } : void 0;
788
+ return /* @__PURE__ */ u("th", { "data-column": column, "data-sortable": "true", style, children: [
789
+ /* @__PURE__ */ u("span", { class: "bases-table-header", children: getColumnLabel(column, basesData) }),
790
+ /* @__PURE__ */ u("span", { class: "bases-table-header-sort", "aria-hidden": "true" })
791
+ ] });
792
+ }) }) }),
793
+ /* @__PURE__ */ u("tbody", { children: groups ? Array.from(groups.entries()).map(([label, groupEntries2]) => /* @__PURE__ */ u(S, { children: [
794
+ /* @__PURE__ */ u("tr", { class: "bases-table-group-header", children: /* @__PURE__ */ u("td", { colSpan: columns.length, children: [
795
+ groupPropertyLabel && /* @__PURE__ */ u("span", { class: "bases-table-group-property", children: [
796
+ groupPropertyLabel,
797
+ " "
798
+ ] }),
799
+ /* @__PURE__ */ u("span", { class: "bases-table-group-label", children: label }),
800
+ /* @__PURE__ */ u("span", { class: "bases-table-group-count", children: groupEntries2.length })
801
+ ] }) }),
802
+ groupEntries2.map(
803
+ (entry) => renderRow(entry, columns, view, slug, allSlugs, linkResolution)
804
+ )
805
+ ] })) : entries.map(
806
+ (entry) => renderRow(entry, columns, view, slug, allSlugs, linkResolution)
807
+ ) }),
808
+ hasSummary && /* @__PURE__ */ u("tfoot", { children: /* @__PURE__ */ u("tr", { class: "bases-summary-row", children: columns.map((column) => {
809
+ const summary = summaries[column];
810
+ if (!summary) return /* @__PURE__ */ u("td", {});
811
+ const values = entries.map((entry) => resolveEntryPropertyValue(column, entry));
812
+ return /* @__PURE__ */ u("td", { children: computeSummary(values, summary) });
813
+ }) }) })
814
+ ] })
815
+ ] });
816
+ };
817
+ var tableViewRegistration = {
818
+ id: "table",
819
+ name: "Table",
820
+ icon: "table",
821
+ render: TableView
822
+ };
823
+
824
+ // src/components/views/index.ts
825
+ function registerBuiltinViews() {
826
+ viewRegistry.register(tableViewRegistration);
827
+ viewRegistry.register(listViewRegistration);
828
+ viewRegistry.register(cardsViewRegistration);
829
+ viewRegistry.register(galleryViewRegistration);
830
+ viewRegistry.register(boardViewRegistration);
831
+ }
832
+
833
+ // src/components/styles/bases.scss
834
+ var bases_default = ".bases-page {\n width: 100%;\n max-width: 100%;\n display: flex;\n flex-direction: column;\n gap: 16px;\n overflow: hidden;\n}\n\n.bases-view-tabs {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n}\n.bases-view-tabs button {\n border: 1px solid var(--lightgray);\n background: var(--light);\n color: var(--darkgray);\n padding: 6px 12px;\n border-radius: 999px;\n cursor: pointer;\n font-size: 0.9rem;\n}\n.bases-view-tabs button.is-active {\n background: var(--secondary);\n color: var(--light);\n border-color: var(--secondary);\n}\n\n.bases-view-container {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.bases-view {\n display: none;\n}\n.bases-view.is-active {\n display: block;\n}\n\n.bases-view-meta {\n font-size: 0.85rem;\n color: var(--gray);\n margin-bottom: 8px;\n}\n\n.bases-table-wrapper {\n width: 100%;\n overflow-x: auto;\n}\n\n.bases-table {\n width: 100%;\n border-collapse: collapse;\n border: 1px solid var(--lightgray);\n border-radius: 8px;\n overflow: hidden;\n}\n.bases-table th,\n.bases-table td {\n padding: 10px 12px;\n text-align: left;\n border-bottom: 1px solid var(--lightgray);\n font-size: 0.9rem;\n}\n.bases-table thead th {\n position: sticky;\n top: 0;\n background: var(--light);\n color: var(--dark);\n font-weight: 600;\n cursor: pointer;\n}\n.bases-table td .bases-empty {\n padding: 0;\n border: 0;\n background: none;\n color: var(--gray);\n display: inline;\n}\n.bases-table td code {\n font-size: 0.85em;\n padding: 0.1rem 0.3rem;\n border-radius: 3px;\n background: var(--highlight);\n word-break: break-all;\n}\n.bases-table td .bases-list {\n flex-direction: row;\n flex-wrap: wrap;\n gap: 4px;\n}\n.bases-table td input[type=checkbox] {\n margin-inline: 0;\n}\n\n.bases-table-header-sort {\n position: absolute;\n right: 8px;\n top: calc(50% - 4px);\n display: inline-block;\n width: 8px;\n height: 8px;\n margin-left: 6px;\n border-right: 2px solid transparent;\n border-bottom: 2px solid transparent;\n}\n\nth.is-sorted-asc .bases-table-header-sort {\n border-right-color: var(--darkgray);\n border-bottom-color: var(--darkgray);\n transform: rotate(-45deg);\n}\n\nth.is-sorted-desc .bases-table-header-sort {\n border-right-color: var(--darkgray);\n border-bottom-color: var(--darkgray);\n transform: rotate(135deg);\n}\n\n.bases-summary-row td {\n background: var(--light);\n font-weight: 600;\n color: var(--darkgray);\n}\n\n.bases-table-group-header td {\n background: var(--lightgray);\n font-weight: 600;\n padding: 8px 12px;\n border-bottom: 2px solid var(--gray);\n}\n\n.bases-table-group-property {\n color: var(--gray);\n font-weight: 400;\n}\n\n.bases-table-group-label {\n margin-right: 8px;\n}\n\n.bases-table-group-count {\n background: var(--light);\n color: var(--darkgray);\n border-radius: 999px;\n padding: 2px 8px;\n font-size: 0.75rem;\n font-weight: 400;\n}\n\n.bases-separator {\n color: var(--gray);\n}\n\n.bases-number {\n font-variant-numeric: tabular-nums;\n}\n\n.bases-list {\n display: inline-flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n\n.bases-list-group {\n width: 100%;\n}\n\n.bases-list-group-list {\n display: flex;\n flex-direction: column;\n}\n\n.bases-list-item {\n padding: 2px 0;\n}\n\n.bases-list-item-properties {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: 0;\n}\n\n.bases-list-property {\n display: inline-flex;\n align-items: baseline;\n gap: 4px;\n}\n\n.list-bullet {\n color: var(--darkgray);\n user-select: none;\n}\n\n.bases-list-separator {\n color: var(--gray);\n margin-right: 4px;\n}\n\n.bases-rendered-value {\n display: inline;\n}\n\n.bases-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));\n gap: 16px;\n}\n\n.bases-card {\n border: 1px solid var(--lightgray);\n border-radius: 12px;\n overflow: hidden;\n background: var(--light);\n display: flex;\n flex-direction: column;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n color: inherit;\n text-decoration: none;\n transition: box-shadow 0.15s ease;\n}\n.bases-card:hover {\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.14);\n}\n\n.bases-card-image {\n overflow: hidden;\n background: var(--lightgray);\n}\n.bases-card-image img {\n width: 100%;\n height: 100%;\n display: block;\n object-fit: cover;\n}\n\n.bases-card-color {\n min-height: 60px;\n}\n\n.bases-card-title {\n font-weight: 600;\n color: var(--dark);\n}\n\n.bases-card-body {\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.bases-card-meta {\n display: grid;\n gap: 4px;\n}\n\n.bases-card-row {\n display: flex;\n justify-content: space-between;\n font-size: 0.8rem;\n color: var(--darkgray);\n}\n\n.bases-card-label {\n color: var(--gray);\n}\n\n.bases-map-placeholder {\n padding: 24px;\n border: 1px dashed var(--lightgray);\n border-radius: 12px;\n background: var(--light);\n}\n\n.bases-map-message {\n color: var(--darkgray);\n margin-top: 12px;\n}\n\n.bases-empty {\n padding: 24px;\n text-align: center;\n color: var(--darkgray);\n border: 1px dashed var(--lightgray);\n border-radius: 12px;\n background: var(--light);\n}\n\n.bases-gallery {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));\n gap: 16px;\n}\n\n.bases-gallery-item {\n position: relative;\n border-radius: 12px;\n overflow: hidden;\n border: 1px solid var(--lightgray);\n background: var(--light);\n}\n\n.bases-gallery-image {\n aspect-ratio: 4/3;\n overflow: hidden;\n background: var(--lightgray);\n}\n\n.bases-gallery-image img,\n.bases-gallery-placeholder {\n width: 100%;\n height: 100%;\n display: block;\n object-fit: cover;\n}\n\n.bases-gallery-placeholder {\n background: linear-gradient(135deg, var(--lightgray), var(--highlight));\n}\n\n.bases-gallery-title {\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n padding: 10px 12px;\n background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.65) 100%);\n color: var(--light);\n font-weight: 600;\n}\n\n.bases-gallery-title a {\n color: inherit;\n}\n\n.bases-board {\n display: flex;\n gap: 16px;\n overflow-x: auto;\n padding-bottom: 4px;\n}\n\n.bases-board-column {\n min-width: min(250px, 80vw);\n flex-shrink: 0;\n border: 1px solid var(--lightgray);\n border-radius: 12px;\n background: var(--light);\n display: flex;\n flex-direction: column;\n}\n\n.bases-board-column-header {\n position: sticky;\n top: 0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 10px 12px;\n font-weight: 600;\n background: var(--light);\n border-bottom: 1px solid var(--lightgray);\n border-radius: 12px 12px 0 0;\n z-index: 1;\n}\n\n.bases-board-count {\n background: var(--lightgray);\n color: var(--darkgray);\n border-radius: 999px;\n padding: 2px 8px;\n font-size: 0.75rem;\n}\n\n.bases-board-column-body {\n padding: 8px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.bases-board-card {\n border: 1px solid var(--lightgray);\n border-radius: 10px;\n background: var(--light);\n padding: 10px 12px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n box-shadow: 0 1px 6px rgba(0, 0, 0, 0.08);\n}\n\n.bases-board-card-meta {\n display: grid;\n gap: 4px;\n font-size: 0.8rem;\n color: var(--darkgray);\n}\n\n.bases-board-card-row {\n display: flex;\n justify-content: space-between;\n gap: 8px;\n}\n\n.bases-board-card-label {\n color: var(--gray);\n}";
835
+
836
+ // src/components/scripts/bases.inline.ts
837
+ var bases_inline_default = `function f(e,s){let n=e.querySelectorAll(".bases-view-tabs button"),r=e.querySelectorAll(".bases-view");n.forEach(t=>{t.classList.toggle("is-active",t.dataset.viewIndex===String(s))}),r.forEach(t=>{t.classList.toggle("is-active",t.dataset.viewIndex===String(s))})}function p(e,s){let n=Number(e),r=Number(s);return!Number.isNaN(n)&&!Number.isNaN(r)?n-r:String(e).localeCompare(String(s))}function h(e,s,n){return e.length===0||(e.sort((r,t)=>{let i=r.children[s],o=t.children[s],c=i?.dataset?.value??i?.textContent??"",a=o?.dataset?.value??o?.textContent??"";return p(c,a)}),n==="desc"&&e.reverse()),e}function v(e,s,n){let r=e.querySelector("tbody");if(!r)return;let t=Array.from(r.querySelectorAll("tr"));if(n==="none"){let o=e._originalOrder;o&&o.forEach(c=>r.appendChild(c));return}if(e._originalOrder||(e._originalOrder=Array.from(t)),t.some(o=>o.classList.contains("bases-table-group-header"))){let o=[],c=null;for(let a of t)a.classList.contains("bases-table-group-header")?(c={header:a,rows:[]},o.push(c)):c?c.rows.push(a):(c={header:null,rows:[a]},o.push(c));for(let a of o)h(a.rows,s,n);for(let a of o)a.header&&r.appendChild(a.header),a.rows.forEach(l=>r.appendChild(l))}else h(t,s,n),t.forEach(o=>r.appendChild(o))}function b(e,s){e.querySelectorAll(".bases-table").forEach(r=>{let t=r.querySelectorAll("th[data-sortable='true']");t.forEach((i,o)=>{let c=()=>{let a=i.dataset.sortDirection||"none",l=a==="asc"?"desc":a==="desc"?"none":"asc";t.forEach(u=>{u!==i&&(u.dataset.sortDirection="none"),u.classList.remove("is-sorted-asc","is-sorted-desc")}),i.dataset.sortDirection=l,i.classList.toggle("is-sorted-asc",l==="asc"),i.classList.toggle("is-sorted-desc",l==="desc"),v(r,o,l)};i.addEventListener("click",c),s.push(()=>i.removeEventListener("click",c))})})}function g(e,s){let n=e.querySelectorAll(".bases-view-tabs button");if(n.length===0)return;let r=parseInt(e.dataset.initialView||"0",10);f(e,Number.isNaN(r)?0:r),n.forEach(t=>{let i=()=>{let o=parseInt(t.dataset.viewIndex||"0",10);f(e,Number.isNaN(o)?0:o)};t.addEventListener("click",i),s.push(()=>t.removeEventListener("click",i))})}function d(){let e=document.querySelectorAll(".bases-page");if(e.length===0)return;let s=[];e.forEach(n=>{g(n,s),b(n,s)}),window.addCleanup&&window.addCleanup(()=>{s.forEach(n=>{n()})})}document.addEventListener("nav",()=>{d()});document.addEventListener("render",()=>{d()});d();
838
+ `;
839
+
840
+ // src/components/BasesBody.tsx
841
+ var builtinViewsRegistered = false;
842
+ var BasesBody_default = ((opts) => {
843
+ const Component = (props) => {
844
+ const locale = props.cfg?.locale ?? "en-US";
845
+ const localeStrings = i18n(locale).components.bases;
846
+ const fileData = props.fileData;
847
+ const basesData = fileData.basesData;
848
+ const basesOptions = fileData.basesOptions ?? opts;
849
+ const basesSelfContext = fileData.basesSelfContext;
850
+ const slug = props.fileData.slug ?? "";
851
+ const rawSlugs = props.ctx?.allSlugs ?? [];
852
+ const baseSlugs = new Set(rawSlugs.filter((s) => s.endsWith(".base")));
853
+ const baseAliases = new Set([...baseSlugs].map((s) => s.replace(/\.base$/, "")));
854
+ const allSlugs = rawSlugs.filter((s) => !baseSlugs.has(s) && !baseAliases.has(s));
855
+ const linkResolution = basesOptions?.linkResolution ?? "shortest";
856
+ if (!basesData) {
857
+ return /* @__PURE__ */ u("div", { class: "bases-page bases-empty", children: localeStrings.noData });
858
+ }
859
+ const views = basesData.views ?? [];
860
+ if (views.length === 0) {
861
+ return /* @__PURE__ */ u("div", { class: "bases-page bases-empty", children: localeStrings.noViews });
862
+ }
863
+ const preferredType = basesOptions?.defaultViewType ?? "table";
864
+ const initialIndex = Math.max(
865
+ 0,
866
+ views.findIndex((view) => view.type === preferredType)
867
+ );
868
+ if (!builtinViewsRegistered) {
869
+ registerBuiltinViews();
870
+ builtinViewsRegistered = true;
871
+ }
872
+ if (basesOptions?.customViews) {
873
+ registerCustomViews(basesOptions.customViews);
874
+ }
875
+ const activeTypes = new Set(views.map((v) => v.type));
876
+ const viewCssChunks = [];
877
+ for (const typeId of activeTypes) {
878
+ const reg = viewRegistry.get(typeId);
879
+ if (reg?.css) viewCssChunks.push(reg.css);
880
+ }
881
+ return /* @__PURE__ */ u("div", { class: "bases-page", "data-initial-view": initialIndex, children: [
882
+ viewCssChunks.length > 0 && /* @__PURE__ */ u("style", { dangerouslySetInnerHTML: { __html: viewCssChunks.join("\n") } }),
883
+ /* @__PURE__ */ u(ViewSelector, { views, activeIndex: initialIndex, locale }),
884
+ /* @__PURE__ */ u("div", { class: "bases-view-container", children: views.map((view, index) => {
885
+ const { entries, total } = resolveBasesEntries(
886
+ basesData,
887
+ props.allFiles,
888
+ view,
889
+ basesSelfContext
890
+ );
891
+ const registration = viewRegistry.get(view.type);
892
+ const Renderer = registration?.render;
893
+ return /* @__PURE__ */ u(
894
+ "div",
895
+ {
896
+ class: `bases-view ${index === initialIndex ? "is-active" : ""}`,
897
+ "data-view-index": index,
898
+ "data-view-type": view.type,
899
+ children: entries.length === 0 ? /* @__PURE__ */ u("div", { class: "bases-empty", children: localeStrings.noData }) : Renderer ? /* @__PURE__ */ u(
900
+ Renderer,
901
+ {
902
+ entries,
903
+ view,
904
+ basesData,
905
+ total,
906
+ locale,
907
+ slug,
908
+ allSlugs,
909
+ linkResolution,
910
+ options: registration.options
911
+ }
912
+ ) : /* @__PURE__ */ u("div", { class: "bases-empty", children: [
913
+ "Unknown view type: ",
914
+ view.type
915
+ ] })
916
+ }
917
+ );
918
+ }) })
919
+ ] });
920
+ };
921
+ Component.css = bases_default;
922
+ const viewScripts = viewRegistry.getAll().map((reg) => reg.afterDOMLoaded).filter((s) => typeof s === "string" && s.length > 0);
923
+ Component.afterDOMLoaded = [bases_inline_default, ...viewScripts];
924
+ return Component;
925
+ });
926
+
927
+ export { BasesBody_default, ViewSelector, i18n, registerBuiltinViews, resolveBasesEntries };
928
+ //# sourceMappingURL=chunk-4HXXKSJ4.js.map
929
+ //# sourceMappingURL=chunk-4HXXKSJ4.js.map