@simple-photo-gallery/common 1.0.5 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/dist/client.d.ts +240 -0
- package/dist/client.js +433 -0
- package/dist/client.js.map +1 -0
- package/dist/gallery.cjs +32 -2
- package/dist/gallery.cjs.map +1 -1
- package/dist/gallery.d.cts +106 -6
- package/dist/gallery.d.ts +106 -6
- package/dist/gallery.js +32 -3
- package/dist/gallery.js.map +1 -1
- package/dist/styles/photoswipe/photoswipe.css +138 -0
- package/dist/theme.d.ts +442 -0
- package/dist/theme.js +387 -0
- package/dist/theme.js.map +1 -0
- package/package.json +25 -2
package/dist/theme.js
ADDED
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { marked } from 'marked';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import process from 'process';
|
|
6
|
+
|
|
7
|
+
// src/theme/config.ts
|
|
8
|
+
var ThumbnailConfigSchema = z.object({
|
|
9
|
+
size: z.number().min(50).max(4e3).optional(),
|
|
10
|
+
edge: z.enum(["auto", "width", "height"]).optional()
|
|
11
|
+
});
|
|
12
|
+
var ThemeConfigSchema = z.object({
|
|
13
|
+
thumbnails: ThumbnailConfigSchema.optional()
|
|
14
|
+
});
|
|
15
|
+
var DEFAULT_THUMBNAIL_CONFIG = {
|
|
16
|
+
size: 300,
|
|
17
|
+
edge: "auto"
|
|
18
|
+
};
|
|
19
|
+
function extractThumbnailConfigFromGallery(gallery) {
|
|
20
|
+
return {
|
|
21
|
+
size: gallery.thumbnails?.size,
|
|
22
|
+
edge: gallery.thumbnails?.edge
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function mergeThumbnailConfig(cliConfig, galleryConfig, themeConfig) {
|
|
26
|
+
return {
|
|
27
|
+
size: cliConfig?.size ?? galleryConfig?.size ?? themeConfig?.size ?? DEFAULT_THUMBNAIL_CONFIG.size,
|
|
28
|
+
edge: cliConfig?.edge ?? galleryConfig?.edge ?? themeConfig?.edge ?? DEFAULT_THUMBNAIL_CONFIG.edge
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/theme/constants.ts
|
|
33
|
+
var PORTRAIT_SIZES = [360, 480, 720, 1080];
|
|
34
|
+
var LANDSCAPE_SIZES = [640, 960, 1280, 1920, 2560, 3840];
|
|
35
|
+
var renderer = new marked.Renderer();
|
|
36
|
+
renderer.heading = ({ text }) => {
|
|
37
|
+
return "<p>" + text + "</p>\n";
|
|
38
|
+
};
|
|
39
|
+
renderer.image = () => "";
|
|
40
|
+
renderer.html = () => "";
|
|
41
|
+
renderer.table = () => "";
|
|
42
|
+
renderer.tablerow = () => "";
|
|
43
|
+
renderer.tablecell = () => "";
|
|
44
|
+
marked.use({
|
|
45
|
+
renderer,
|
|
46
|
+
breaks: true,
|
|
47
|
+
gfm: true
|
|
48
|
+
});
|
|
49
|
+
async function renderMarkdown(markdown) {
|
|
50
|
+
if (!markdown) return "";
|
|
51
|
+
return await marked.parse(markdown);
|
|
52
|
+
}
|
|
53
|
+
function getRelativePath(resourcePath, galleryJsonPath) {
|
|
54
|
+
const galleryConfigPath = path.resolve(galleryJsonPath);
|
|
55
|
+
const galleryConfigDir = path.dirname(galleryConfigPath);
|
|
56
|
+
const absoluteResourcePath = path.resolve(path.join(galleryConfigDir, resourcePath));
|
|
57
|
+
const baseDir = path.dirname(galleryConfigDir);
|
|
58
|
+
return path.relative(baseDir, absoluteResourcePath);
|
|
59
|
+
}
|
|
60
|
+
function getThumbnailPath(resourcePath, thumbsBaseUrl, thumbnailBaseUrl) {
|
|
61
|
+
if (thumbnailBaseUrl) {
|
|
62
|
+
return `${thumbnailBaseUrl}/${resourcePath}`;
|
|
63
|
+
}
|
|
64
|
+
return thumbsBaseUrl ? `${thumbsBaseUrl}/${resourcePath}` : `gallery/images/${path.basename(resourcePath)}`;
|
|
65
|
+
}
|
|
66
|
+
function getPhotoPath(filename, mediaBaseUrl, url) {
|
|
67
|
+
if (url) {
|
|
68
|
+
return url;
|
|
69
|
+
}
|
|
70
|
+
return mediaBaseUrl ? `${mediaBaseUrl}/${filename}` : filename;
|
|
71
|
+
}
|
|
72
|
+
function getSubgalleryThumbnailPath(subgalleryHeaderImagePath) {
|
|
73
|
+
const photoBasename = path.basename(subgalleryHeaderImagePath);
|
|
74
|
+
const subgalleryFolderName = path.basename(path.dirname(subgalleryHeaderImagePath));
|
|
75
|
+
return path.join(subgalleryFolderName, "gallery", "thumbnails", photoBasename);
|
|
76
|
+
}
|
|
77
|
+
function buildHeroSrcset(variants, sizes, thumbnailBasePath, imgBasename, orientation, format, useDefaultPaths) {
|
|
78
|
+
return sizes.map((size) => {
|
|
79
|
+
const customPath = variants?.[size];
|
|
80
|
+
if (customPath) {
|
|
81
|
+
return `${customPath} ${size}w`;
|
|
82
|
+
}
|
|
83
|
+
if (useDefaultPaths) {
|
|
84
|
+
return `${thumbnailBasePath}/${imgBasename}_${orientation}_${size}.${format} ${size}w`;
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}).filter(Boolean).join(", ");
|
|
88
|
+
}
|
|
89
|
+
var ThumbnailSchema = z.object({
|
|
90
|
+
baseUrl: z.string().optional(),
|
|
91
|
+
path: z.string(),
|
|
92
|
+
pathRetina: z.string(),
|
|
93
|
+
width: z.number(),
|
|
94
|
+
height: z.number(),
|
|
95
|
+
blurHash: z.string().optional()
|
|
96
|
+
});
|
|
97
|
+
var MediaFileSchema = z.object({
|
|
98
|
+
type: z.enum(["image", "video"]),
|
|
99
|
+
filename: z.string(),
|
|
100
|
+
url: z.string().optional(),
|
|
101
|
+
alt: z.string().optional(),
|
|
102
|
+
width: z.number(),
|
|
103
|
+
height: z.number(),
|
|
104
|
+
thumbnail: ThumbnailSchema.optional(),
|
|
105
|
+
lastMediaTimestamp: z.string().optional()
|
|
106
|
+
});
|
|
107
|
+
var MediaFileDeprecatedSchema = z.object({
|
|
108
|
+
type: z.enum(["image", "video"]),
|
|
109
|
+
path: z.string(),
|
|
110
|
+
alt: z.string().optional(),
|
|
111
|
+
width: z.number(),
|
|
112
|
+
height: z.number(),
|
|
113
|
+
thumbnail: ThumbnailSchema.optional(),
|
|
114
|
+
lastMediaTimestamp: z.string().optional()
|
|
115
|
+
});
|
|
116
|
+
var GallerySectionSchema = z.object({
|
|
117
|
+
title: z.string().optional(),
|
|
118
|
+
description: z.string().optional(),
|
|
119
|
+
images: z.array(MediaFileSchema)
|
|
120
|
+
});
|
|
121
|
+
var GallerySectionDeprecatedSchema = z.object({
|
|
122
|
+
title: z.string().optional(),
|
|
123
|
+
description: z.string().optional(),
|
|
124
|
+
images: z.array(MediaFileDeprecatedSchema)
|
|
125
|
+
});
|
|
126
|
+
var SubGallerySchema = z.object({
|
|
127
|
+
title: z.string(),
|
|
128
|
+
headerImage: z.string(),
|
|
129
|
+
path: z.string()
|
|
130
|
+
});
|
|
131
|
+
var PortraitSizesSchema = z.object({
|
|
132
|
+
360: z.string().optional(),
|
|
133
|
+
480: z.string().optional(),
|
|
134
|
+
720: z.string().optional(),
|
|
135
|
+
1080: z.string().optional()
|
|
136
|
+
});
|
|
137
|
+
var LandscapeSizesSchema = z.object({
|
|
138
|
+
640: z.string().optional(),
|
|
139
|
+
960: z.string().optional(),
|
|
140
|
+
1280: z.string().optional(),
|
|
141
|
+
1920: z.string().optional(),
|
|
142
|
+
2560: z.string().optional(),
|
|
143
|
+
3840: z.string().optional()
|
|
144
|
+
});
|
|
145
|
+
var HeaderImageVariantsSchema = z.object({
|
|
146
|
+
portrait: z.object({
|
|
147
|
+
avif: PortraitSizesSchema.optional(),
|
|
148
|
+
jpg: PortraitSizesSchema.optional()
|
|
149
|
+
}).optional(),
|
|
150
|
+
landscape: z.object({
|
|
151
|
+
avif: LandscapeSizesSchema.optional(),
|
|
152
|
+
jpg: LandscapeSizesSchema.optional()
|
|
153
|
+
}).optional()
|
|
154
|
+
});
|
|
155
|
+
var GalleryMetadataSchema = z.object({
|
|
156
|
+
image: z.string().optional(),
|
|
157
|
+
imageWidth: z.number().optional(),
|
|
158
|
+
imageHeight: z.number().optional(),
|
|
159
|
+
ogUrl: z.string().optional(),
|
|
160
|
+
ogType: z.string().optional(),
|
|
161
|
+
ogSiteName: z.string().optional(),
|
|
162
|
+
twitterSite: z.string().optional(),
|
|
163
|
+
twitterCreator: z.string().optional(),
|
|
164
|
+
author: z.string().optional(),
|
|
165
|
+
keywords: z.string().optional(),
|
|
166
|
+
canonicalUrl: z.string().optional(),
|
|
167
|
+
language: z.string().optional(),
|
|
168
|
+
robots: z.string().optional()
|
|
169
|
+
});
|
|
170
|
+
var GalleryDataSchema = z.object({
|
|
171
|
+
title: z.string(),
|
|
172
|
+
description: z.string(),
|
|
173
|
+
mediaBasePath: z.string().optional(),
|
|
174
|
+
url: z.string().optional(),
|
|
175
|
+
headerImage: z.string(),
|
|
176
|
+
headerImageBlurHash: z.string().optional(),
|
|
177
|
+
headerImageVariants: HeaderImageVariantsSchema.optional(),
|
|
178
|
+
theme: z.string().optional(),
|
|
179
|
+
thumbnails: z.object({
|
|
180
|
+
size: z.number().optional(),
|
|
181
|
+
edge: z.enum(["auto", "width", "height"]).optional()
|
|
182
|
+
}).optional(),
|
|
183
|
+
metadata: GalleryMetadataSchema,
|
|
184
|
+
mediaBaseUrl: z.string().optional(),
|
|
185
|
+
thumbsBaseUrl: z.string().optional(),
|
|
186
|
+
analyticsScript: z.string().optional(),
|
|
187
|
+
ctaBanner: z.boolean().optional(),
|
|
188
|
+
sections: z.array(GallerySectionSchema),
|
|
189
|
+
subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) })
|
|
190
|
+
});
|
|
191
|
+
z.object({
|
|
192
|
+
title: z.string(),
|
|
193
|
+
description: z.string(),
|
|
194
|
+
url: z.string().optional(),
|
|
195
|
+
headerImage: z.string(),
|
|
196
|
+
thumbnailSize: z.number().optional(),
|
|
197
|
+
metadata: GalleryMetadataSchema,
|
|
198
|
+
mediaBaseUrl: z.string().optional(),
|
|
199
|
+
analyticsScript: z.string().optional(),
|
|
200
|
+
sections: z.array(GallerySectionDeprecatedSchema),
|
|
201
|
+
subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) })
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// src/theme/loader.ts
|
|
205
|
+
function loadThemeConfig(themePath) {
|
|
206
|
+
const themeConfigPaths = [path.resolve(process.cwd(), "themeConfig.json")];
|
|
207
|
+
if (themePath) {
|
|
208
|
+
themeConfigPaths.push(path.resolve(themePath, "themeConfig.json"));
|
|
209
|
+
}
|
|
210
|
+
for (const configPath of themeConfigPaths) {
|
|
211
|
+
if (fs.existsSync(configPath)) {
|
|
212
|
+
try {
|
|
213
|
+
const configData = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
214
|
+
const parsed = ThemeConfigSchema.safeParse(configData);
|
|
215
|
+
if (parsed.success) {
|
|
216
|
+
return parsed.data.thumbnails;
|
|
217
|
+
}
|
|
218
|
+
if (process.env.DEBUG || process.env.VERBOSE) {
|
|
219
|
+
console.warn(`Failed to validate themeConfig at ${configPath}:`, parsed.error.message);
|
|
220
|
+
}
|
|
221
|
+
} catch (error) {
|
|
222
|
+
if (process.env.DEBUG || process.env.VERBOSE) {
|
|
223
|
+
console.warn(`Failed to parse themeConfig at ${configPath}:`, error);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return void 0;
|
|
229
|
+
}
|
|
230
|
+
function loadGalleryData(galleryJsonPath = "./gallery.json", options) {
|
|
231
|
+
const galleryData = JSON.parse(fs.readFileSync(galleryJsonPath, "utf8"));
|
|
232
|
+
if (options?.validate) {
|
|
233
|
+
const result = GalleryDataSchema.safeParse(galleryData);
|
|
234
|
+
if (!result.success) {
|
|
235
|
+
throw new Error(`Invalid gallery.json at ${galleryJsonPath}: ${result.error.message}`);
|
|
236
|
+
}
|
|
237
|
+
return result.data;
|
|
238
|
+
}
|
|
239
|
+
return galleryData;
|
|
240
|
+
}
|
|
241
|
+
function resolveImage(image, mediaBaseUrl, thumbsBaseUrl) {
|
|
242
|
+
const imagePath = getPhotoPath(image.filename, mediaBaseUrl, image.url);
|
|
243
|
+
const thumbnailPath = image.thumbnail ? getThumbnailPath(image.thumbnail.path, thumbsBaseUrl, image.thumbnail.baseUrl) : imagePath;
|
|
244
|
+
const thumbnailSrcSet = image.thumbnail ? getThumbnailPath(image.thumbnail.path, thumbsBaseUrl, image.thumbnail.baseUrl) + " 1x, " + getThumbnailPath(image.thumbnail.pathRetina, thumbsBaseUrl, image.thumbnail.baseUrl) + " 2x" : void 0;
|
|
245
|
+
return {
|
|
246
|
+
type: image.type,
|
|
247
|
+
filename: image.filename,
|
|
248
|
+
alt: image.alt,
|
|
249
|
+
width: image.width,
|
|
250
|
+
height: image.height,
|
|
251
|
+
imagePath,
|
|
252
|
+
thumbnailPath,
|
|
253
|
+
thumbnailSrcSet,
|
|
254
|
+
thumbnailWidth: image.thumbnail?.width,
|
|
255
|
+
thumbnailHeight: image.thumbnail?.height,
|
|
256
|
+
blurHash: image.thumbnail?.blurHash
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
async function resolveSection(section, mediaBaseUrl, thumbsBaseUrl) {
|
|
260
|
+
const parsedDescription = section.description ? await renderMarkdown(section.description) : "";
|
|
261
|
+
return {
|
|
262
|
+
title: section.title,
|
|
263
|
+
description: section.description,
|
|
264
|
+
parsedDescription,
|
|
265
|
+
images: section.images.map((img) => resolveImage(img, mediaBaseUrl, thumbsBaseUrl))
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function resolveSubGallery(subGallery, galleryJsonPath) {
|
|
269
|
+
return {
|
|
270
|
+
title: subGallery.title,
|
|
271
|
+
headerImage: subGallery.headerImage,
|
|
272
|
+
path: subGallery.path,
|
|
273
|
+
thumbnailPath: getSubgalleryThumbnailPath(subGallery.headerImage),
|
|
274
|
+
resolvedPath: galleryJsonPath ? getRelativePath(subGallery.path, galleryJsonPath) : void 0
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
async function resolveHero(gallery) {
|
|
278
|
+
const { title, description, headerImage, headerImageBlurHash, headerImageVariants, mediaBaseUrl, thumbsBaseUrl } = gallery;
|
|
279
|
+
const parsedDescription = description ? await renderMarkdown(description) : "";
|
|
280
|
+
const imgBasename = headerImage ? path.basename(headerImage, path.extname(headerImage)) : "header";
|
|
281
|
+
const thumbnailBasePath = thumbsBaseUrl || "gallery/images";
|
|
282
|
+
const headerPhotoPath = getPhotoPath(headerImage || "", mediaBaseUrl);
|
|
283
|
+
const useDefaultPaths = !headerImageVariants;
|
|
284
|
+
const srcsets = {
|
|
285
|
+
portraitAvif: buildHeroSrcset(
|
|
286
|
+
headerImageVariants?.portrait?.avif,
|
|
287
|
+
PORTRAIT_SIZES,
|
|
288
|
+
thumbnailBasePath,
|
|
289
|
+
imgBasename,
|
|
290
|
+
"portrait",
|
|
291
|
+
"avif",
|
|
292
|
+
useDefaultPaths
|
|
293
|
+
),
|
|
294
|
+
portraitJpg: buildHeroSrcset(
|
|
295
|
+
headerImageVariants?.portrait?.jpg,
|
|
296
|
+
PORTRAIT_SIZES,
|
|
297
|
+
thumbnailBasePath,
|
|
298
|
+
imgBasename,
|
|
299
|
+
"portrait",
|
|
300
|
+
"jpg",
|
|
301
|
+
useDefaultPaths
|
|
302
|
+
),
|
|
303
|
+
landscapeAvif: buildHeroSrcset(
|
|
304
|
+
headerImageVariants?.landscape?.avif,
|
|
305
|
+
LANDSCAPE_SIZES,
|
|
306
|
+
thumbnailBasePath,
|
|
307
|
+
imgBasename,
|
|
308
|
+
"landscape",
|
|
309
|
+
"avif",
|
|
310
|
+
useDefaultPaths
|
|
311
|
+
),
|
|
312
|
+
landscapeJpg: buildHeroSrcset(
|
|
313
|
+
headerImageVariants?.landscape?.jpg,
|
|
314
|
+
LANDSCAPE_SIZES,
|
|
315
|
+
thumbnailBasePath,
|
|
316
|
+
imgBasename,
|
|
317
|
+
"landscape",
|
|
318
|
+
"jpg",
|
|
319
|
+
useDefaultPaths
|
|
320
|
+
)
|
|
321
|
+
};
|
|
322
|
+
return {
|
|
323
|
+
title,
|
|
324
|
+
description,
|
|
325
|
+
parsedDescription,
|
|
326
|
+
headerImage,
|
|
327
|
+
headerPhotoPath,
|
|
328
|
+
headerImageBlurHash,
|
|
329
|
+
headerImageVariants,
|
|
330
|
+
thumbnailBasePath,
|
|
331
|
+
imgBasename,
|
|
332
|
+
srcsets
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
async function resolveGalleryData(gallery, options) {
|
|
336
|
+
const { mediaBaseUrl, thumbsBaseUrl, subGalleries } = gallery;
|
|
337
|
+
const { galleryJsonPath, themeConfig, cliConfig } = options ?? {};
|
|
338
|
+
const hero = await resolveHero(gallery);
|
|
339
|
+
const sections = await Promise.all(
|
|
340
|
+
gallery.sections.map((section) => resolveSection(section, mediaBaseUrl, thumbsBaseUrl))
|
|
341
|
+
);
|
|
342
|
+
const resolvedSubGalleries = subGalleries?.galleries?.length ? {
|
|
343
|
+
title: subGalleries.title,
|
|
344
|
+
galleries: subGalleries.galleries.map((sg) => resolveSubGallery(sg, galleryJsonPath))
|
|
345
|
+
} : void 0;
|
|
346
|
+
const galleryThumbnailConfig = extractThumbnailConfigFromGallery(gallery);
|
|
347
|
+
const thumbnails = mergeThumbnailConfig(cliConfig, galleryThumbnailConfig, themeConfig);
|
|
348
|
+
return {
|
|
349
|
+
title: gallery.title,
|
|
350
|
+
url: gallery.url,
|
|
351
|
+
metadata: gallery.metadata,
|
|
352
|
+
analyticsScript: gallery.analyticsScript,
|
|
353
|
+
ctaBanner: gallery.ctaBanner,
|
|
354
|
+
hero,
|
|
355
|
+
sections,
|
|
356
|
+
subGalleries: resolvedSubGalleries,
|
|
357
|
+
mediaBaseUrl,
|
|
358
|
+
thumbsBaseUrl,
|
|
359
|
+
thumbnails
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function preventEmptyContentFiles() {
|
|
363
|
+
return {
|
|
364
|
+
name: "prevent-empty-content-files",
|
|
365
|
+
hooks: {
|
|
366
|
+
"astro:build:done": ({ dir }) => {
|
|
367
|
+
const filesToRemove = ["content-assets.mjs", "content-modules.mjs"];
|
|
368
|
+
for (const fileName of filesToRemove) {
|
|
369
|
+
const filePath = path.join(dir.pathname, fileName);
|
|
370
|
+
if (fs.existsSync(filePath)) {
|
|
371
|
+
try {
|
|
372
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
373
|
+
if (content.trim() === "export default new Map();" || content.trim() === "") {
|
|
374
|
+
fs.unlinkSync(filePath);
|
|
375
|
+
}
|
|
376
|
+
} catch {
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
export { DEFAULT_THUMBNAIL_CONFIG, LANDSCAPE_SIZES, PORTRAIT_SIZES, ThemeConfigSchema, ThumbnailConfigSchema, buildHeroSrcset, extractThumbnailConfigFromGallery, getPhotoPath, getRelativePath, getSubgalleryThumbnailPath, getThumbnailPath, loadGalleryData, loadThemeConfig, mergeThumbnailConfig, preventEmptyContentFiles, renderMarkdown, resolveGalleryData };
|
|
386
|
+
//# sourceMappingURL=theme.js.map
|
|
387
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/theme/config.ts","../src/theme/constants.ts","../src/theme/markdown.ts","../src/theme/paths.ts","../src/gallery/schemas.ts","../src/theme/loader.ts","../src/theme/resolver.ts","../src/theme/astro.ts"],"names":["z","path","fs"],"mappings":";;;;;;;AAGO,IAAM,qBAAA,GAAwB,EAAE,MAAA,CAAO;AAAA,EAC5C,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,EAAE,CAAA,CAAE,GAAA,CAAI,GAAI,CAAA,CAAE,QAAA,EAAS;AAAA,EAC5C,IAAA,EAAM,EAAE,IAAA,CAAK,CAAC,QAAQ,OAAA,EAAS,QAAQ,CAAC,CAAA,CAAE,QAAA;AAC5C,CAAC;AAGM,IAAM,iBAAA,GAAoB,EAAE,MAAA,CAAO;AAAA,EACxC,UAAA,EAAY,sBAAsB,QAAA;AACpC,CAAC;AASM,IAAM,wBAAA,GAAsD;AAAA,EACjE,IAAA,EAAM,GAAA;AAAA,EACN,IAAA,EAAM;AACR;AAOO,SAAS,kCAAkC,OAAA,EAA4D;AAC5G,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,QAAQ,UAAA,EAAY,IAAA;AAAA,IAC1B,IAAA,EAAM,QAAQ,UAAA,EAAY;AAAA,GAC5B;AACF;AAcO,SAAS,oBAAA,CACd,SAAA,EACA,aAAA,EACA,WAAA,EAC2B;AAC3B,EAAA,OAAO;AAAA,IACL,MAAM,SAAA,EAAW,IAAA,IAAQ,eAAe,IAAA,IAAQ,WAAA,EAAa,QAAQ,wBAAA,CAAyB,IAAA;AAAA,IAC9F,MAAM,SAAA,EAAW,IAAA,IAAQ,eAAe,IAAA,IAAQ,WAAA,EAAa,QAAQ,wBAAA,CAAyB;AAAA,GAChG;AACF;;;ACzDO,IAAM,cAAA,GAAiB,CAAC,GAAA,EAAK,GAAA,EAAK,KAAK,IAAI;AAG3C,IAAM,kBAAkB,CAAC,GAAA,EAAK,KAAK,IAAA,EAAM,IAAA,EAAM,MAAM,IAAI;ACDhE,IAAM,QAAA,GAAW,IAAI,MAAA,CAAO,QAAA,EAAS;AAGrC,QAAA,CAAS,OAAA,GAAU,CAAC,EAAE,IAAA,EAAK,KAAwB;AACjD,EAAA,OAAO,QAAQ,IAAA,GAAO,QAAA;AACxB,CAAA;AAGA,QAAA,CAAS,QAAQ,MAAM,EAAA;AAGvB,QAAA,CAAS,OAAO,MAAM,EAAA;AAGtB,QAAA,CAAS,QAAQ,MAAM,EAAA;AACvB,QAAA,CAAS,WAAW,MAAM,EAAA;AAC1B,QAAA,CAAS,YAAY,MAAM,EAAA;AAG3B,MAAA,CAAO,GAAA,CAAI;AAAA,EACT,QAAA;AAAA,EACA,MAAA,EAAQ,IAAA;AAAA,EACR,GAAA,EAAK;AACP,CAAC,CAAA;AAOD,eAAsB,eAAe,QAAA,EAAmC;AACtE,EAAA,IAAI,CAAC,UAAU,OAAO,EAAA;AACtB,EAAA,OAAO,MAAM,MAAA,CAAO,KAAA,CAAM,QAAQ,CAAA;AACpC;AC3BO,SAAS,eAAA,CAAgB,cAAsB,eAAA,EAAiC;AACrF,EAAA,MAAM,iBAAA,GAAoB,IAAA,CAAK,OAAA,CAAQ,eAAe,CAAA;AACtD,EAAA,MAAM,gBAAA,GAAmB,IAAA,CAAK,OAAA,CAAQ,iBAAiB,CAAA;AAEvD,EAAA,MAAM,uBAAuB,IAAA,CAAK,OAAA,CAAQ,KAAK,IAAA,CAAK,gBAAA,EAAkB,YAAY,CAAC,CAAA;AACnF,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,gBAAgB,CAAA;AAE7C,EAAA,OAAO,IAAA,CAAK,QAAA,CAAS,OAAA,EAAS,oBAAoB,CAAA;AACpD;AAUO,SAAS,gBAAA,CAAiB,YAAA,EAAsB,aAAA,EAAwB,gBAAA,EAAmC;AAEhH,EAAA,IAAI,gBAAA,EAAkB;AACpB,IAAA,OAAO,CAAA,EAAG,gBAAgB,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA;AAAA,EAC5C;AAEA,EAAA,OAAO,aAAA,GAAgB,CAAA,EAAG,aAAa,CAAA,CAAA,EAAI,YAAY,KAAK,CAAA,eAAA,EAAkB,IAAA,CAAK,QAAA,CAAS,YAAY,CAAC,CAAA,CAAA;AAC3G;AAUO,SAAS,YAAA,CAAa,QAAA,EAAkB,YAAA,EAAuB,GAAA,EAAsB;AAE1F,EAAA,IAAI,GAAA,EAAK;AACP,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,OAAO,YAAA,GAAe,CAAA,EAAG,YAAY,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA,GAAK,QAAA;AACxD;AAQO,SAAS,2BAA2B,yBAAA,EAA2C;AACpF,EAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,QAAA,CAAS,yBAAyB,CAAA;AAC7D,EAAA,MAAM,uBAAuB,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,OAAA,CAAQ,yBAAyB,CAAC,CAAA;AAElF,EAAA,OAAO,IAAA,CAAK,IAAA,CAAK,oBAAA,EAAsB,SAAA,EAAW,cAAc,aAAa,CAAA;AAC/E;AAeO,SAAS,gBACd,QAAA,EACA,KAAA,EACA,mBACA,WAAA,EACA,WAAA,EACA,QACA,eAAA,EACQ;AACR,EAAA,OAAO,KAAA,CACJ,GAAA,CAAI,CAAC,IAAA,KAAS;AACb,IAAA,MAAM,UAAA,GAAa,WAAW,IAAI,CAAA;AAClC,IAAA,IAAI,UAAA,EAAY;AACd,MAAA,OAAO,CAAA,EAAG,UAAU,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,CAAA;AAAA,IAC9B;AACA,IAAA,IAAI,eAAA,EAAiB;AACnB,MAAA,OAAO,CAAA,EAAG,iBAAiB,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,CAAA;AAAA,IACrF;AACA,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA,CACA,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,IAAI,CAAA;AACd;AClGO,IAAM,eAAA,GAAkBA,EAAE,MAAA,CAAO;AAAA,EACtC,OAAA,EAASA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC7B,IAAA,EAAMA,EAAE,MAAA,EAAO;AAAA,EACf,UAAA,EAAYA,EAAE,MAAA,EAAO;AAAA,EACrB,KAAA,EAAOA,EAAE,MAAA,EAAO;AAAA,EAChB,MAAA,EAAQA,EAAE,MAAA,EAAO;AAAA,EACjB,QAAA,EAAUA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACvB,CAAC,CAAA;AAGM,IAAM,eAAA,GAAkBA,EAAE,MAAA,CAAO;AAAA,EACtC,MAAMA,CAAAA,CAAE,IAAA,CAAK,CAAC,OAAA,EAAS,OAAO,CAAC,CAAA;AAAA,EAC/B,QAAA,EAAUA,EAAE,MAAA,EAAO;AAAA,EACnB,GAAA,EAAKA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,GAAA,EAAKA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,KAAA,EAAOA,EAAE,MAAA,EAAO;AAAA,EAChB,MAAA,EAAQA,EAAE,MAAA,EAAO;AAAA,EACjB,SAAA,EAAW,gBAAgB,QAAA,EAAS;AAAA,EACpC,kBAAA,EAAoBA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACjC,CAAC,CAAA;AAMM,IAAM,yBAAA,GAA4BA,EAAE,MAAA,CAAO;AAAA,EAChD,MAAMA,CAAAA,CAAE,IAAA,CAAK,CAAC,OAAA,EAAS,OAAO,CAAC,CAAA;AAAA,EAC/B,IAAA,EAAMA,EAAE,MAAA,EAAO;AAAA,EACf,GAAA,EAAKA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,KAAA,EAAOA,EAAE,MAAA,EAAO;AAAA,EAChB,MAAA,EAAQA,EAAE,MAAA,EAAO;AAAA,EACjB,SAAA,EAAW,gBAAgB,QAAA,EAAS;AAAA,EACpC,kBAAA,EAAoBA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACjC,CAAC,CAAA;AAGM,IAAM,oBAAA,GAAuBA,EAAE,MAAA,CAAO;AAAA,EAC3C,KAAA,EAAOA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC3B,WAAA,EAAaA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,MAAA,EAAQA,CAAAA,CAAE,KAAA,CAAM,eAAe;AACjC,CAAC,CAAA;AAMM,IAAM,8BAAA,GAAiCA,EAAE,MAAA,CAAO;AAAA,EACrD,KAAA,EAAOA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC3B,WAAA,EAAaA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,MAAA,EAAQA,CAAAA,CAAE,KAAA,CAAM,yBAAyB;AAC3C,CAAC,CAAA;AAGM,IAAM,gBAAA,GAAmBA,EAAE,MAAA,CAAO;AAAA,EACvC,KAAA,EAAOA,EAAE,MAAA,EAAO;AAAA,EAChB,WAAA,EAAaA,EAAE,MAAA,EAAO;AAAA,EACtB,IAAA,EAAMA,EAAE,MAAA;AACV,CAAC,CAAA;AAGD,IAAM,mBAAA,GAAsBA,EAAE,MAAA,CAAO;AAAA,EACnC,GAAA,EAAKA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,GAAA,EAAKA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,GAAA,EAAKA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,IAAA,EAAMA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACnB,CAAC,CAAA;AAGD,IAAM,oBAAA,GAAuBA,EAAE,MAAA,CAAO;AAAA,EACpC,GAAA,EAAKA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,GAAA,EAAKA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,IAAA,EAAMA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC1B,IAAA,EAAMA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC1B,IAAA,EAAMA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC1B,IAAA,EAAMA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACnB,CAAC,CAAA;AAGM,IAAM,yBAAA,GAA4BA,EAAE,MAAA,CAAO;AAAA,EAChD,QAAA,EAAUA,EACP,MAAA,CAAO;AAAA,IACN,IAAA,EAAM,oBAAoB,QAAA,EAAS;AAAA,IACnC,GAAA,EAAK,oBAAoB,QAAA;AAAS,GACnC,EACA,QAAA,EAAS;AAAA,EACZ,SAAA,EAAWA,EACR,MAAA,CAAO;AAAA,IACN,IAAA,EAAM,qBAAqB,QAAA,EAAS;AAAA,IACpC,GAAA,EAAK,qBAAqB,QAAA;AAAS,GACpC,EACA,QAAA;AACL,CAAC,CAAA;AAGM,IAAM,qBAAA,GAAwBA,EAAE,MAAA,CAAO;AAAA,EAC5C,KAAA,EAAOA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC3B,UAAA,EAAYA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAChC,WAAA,EAAaA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,KAAA,EAAOA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC3B,MAAA,EAAQA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC5B,UAAA,EAAYA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAChC,WAAA,EAAaA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,cAAA,EAAgBA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACpC,MAAA,EAAQA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC5B,QAAA,EAAUA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC9B,YAAA,EAAcA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAClC,QAAA,EAAUA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC9B,MAAA,EAAQA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACrB,CAAC,CAAA;AAGM,IAAM,iBAAA,GAAoBA,EAAE,MAAA,CAAO;AAAA,EACxC,KAAA,EAAOA,EAAE,MAAA,EAAO;AAAA,EAChB,WAAA,EAAaA,EAAE,MAAA,EAAO;AAAA,EACtB,aAAA,EAAeA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACnC,GAAA,EAAKA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,WAAA,EAAaA,EAAE,MAAA,EAAO;AAAA,EACtB,mBAAA,EAAqBA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzC,mBAAA,EAAqB,0BAA0B,QAAA,EAAS;AAAA,EACxD,KAAA,EAAOA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC3B,UAAA,EAAYA,EACT,MAAA,CAAO;AAAA,IACN,IAAA,EAAMA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IAC1B,IAAA,EAAMA,EAAE,IAAA,CAAK,CAAC,QAAQ,OAAA,EAAS,QAAQ,CAAC,CAAA,CAAE,QAAA;AAAS,GACpD,EACA,QAAA,EAAS;AAAA,EACZ,QAAA,EAAU,qBAAA;AAAA,EACV,YAAA,EAAcA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAClC,aAAA,EAAeA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACnC,eAAA,EAAiBA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACrC,SAAA,EAAWA,CAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EAChC,QAAA,EAAUA,CAAAA,CAAE,KAAA,CAAM,oBAAoB,CAAA;AAAA,EACtC,YAAA,EAAcA,CAAAA,CAAE,MAAA,CAAO,EAAE,KAAA,EAAOA,CAAAA,CAAE,MAAA,EAAO,EAAG,SAAA,EAAWA,CAAAA,CAAE,KAAA,CAAM,gBAAgB,GAAG;AACpF,CAAC,CAAA;AAM0CA,EAAE,MAAA,CAAO;AAAA,EAClD,KAAA,EAAOA,EAAE,MAAA,EAAO;AAAA,EAChB,WAAA,EAAaA,EAAE,MAAA,EAAO;AAAA,EACtB,GAAA,EAAKA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,WAAA,EAAaA,EAAE,MAAA,EAAO;AAAA,EACtB,aAAA,EAAeA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACnC,QAAA,EAAU,qBAAA;AAAA,EACV,YAAA,EAAcA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAClC,eAAA,EAAiBA,CAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACrC,QAAA,EAAUA,CAAAA,CAAE,KAAA,CAAM,8BAA8B,CAAA;AAAA,EAChD,YAAA,EAAcA,CAAAA,CAAE,MAAA,CAAO,EAAE,KAAA,EAAOA,CAAAA,CAAE,MAAA,EAAO,EAAG,SAAA,EAAWA,CAAAA,CAAE,KAAA,CAAM,gBAAgB,GAAG;AACpF,CAAC;;;AC9GM,SAAS,gBAAgB,SAAA,EAAiD;AAC/E,EAAA,MAAM,gBAAA,GAA6B,CAACC,IAAAA,CAAK,OAAA,CAAQ,QAAQ,GAAA,EAAI,EAAG,kBAAkB,CAAC,CAAA;AAEnF,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,gBAAA,CAAiB,IAAA,CAAKA,IAAAA,CAAK,OAAA,CAAQ,SAAA,EAAW,kBAAkB,CAAC,CAAA;AAAA,EACnE;AAEA,EAAA,KAAA,MAAW,cAAc,gBAAA,EAAkB;AACzC,IAAA,IAAI,EAAA,CAAG,UAAA,CAAW,UAAU,CAAA,EAAG;AAC7B,MAAA,IAAI;AACF,QAAA,MAAM,aAAa,IAAA,CAAK,KAAA,CAAM,GAAG,YAAA,CAAa,UAAA,EAAY,MAAM,CAAC,CAAA;AACjE,QAAA,MAAM,MAAA,GAAS,iBAAA,CAAkB,SAAA,CAAU,UAAU,CAAA;AACrD,QAAA,IAAI,OAAO,OAAA,EAAS;AAClB,UAAA,OAAO,OAAO,IAAA,CAAK,UAAA;AAAA,QACrB;AAEA,QAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,KAAA,IAAS,OAAA,CAAQ,IAAI,OAAA,EAAS;AAC5C,UAAA,OAAA,CAAQ,KAAK,CAAA,kCAAA,EAAqC,UAAU,CAAA,CAAA,CAAA,EAAK,MAAA,CAAO,MAAM,OAAO,CAAA;AAAA,QACvF;AAAA,MACF,SAAS,KAAA,EAAO;AAEd,QAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,KAAA,IAAS,OAAA,CAAQ,IAAI,OAAA,EAAS;AAC5C,UAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,+BAAA,EAAkC,UAAU,CAAA,CAAA,CAAA,EAAK,KAAK,CAAA;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAmBO,SAAS,eAAA,CAAgB,eAAA,GAAkB,gBAAA,EAAkB,OAAA,EAA+C;AACjH,EAAA,MAAM,cAAc,IAAA,CAAK,KAAA,CAAM,GAAG,YAAA,CAAa,eAAA,EAAiB,MAAM,CAAC,CAAA;AAEvE,EAAA,IAAI,SAAS,QAAA,EAAU;AACrB,IAAA,MAAM,MAAA,GAAS,iBAAA,CAAkB,SAAA,CAAU,WAAW,CAAA;AACtD,IAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,MAAA,MAAM,IAAI,MAAM,CAAA,wBAAA,EAA2B,eAAe,KAAK,MAAA,CAAO,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AAAA,IACvF;AACA,IAAA,OAAO,MAAA,CAAO,IAAA;AAAA,EAChB;AAEA,EAAA,OAAO,WAAA;AACT;AC1FA,SAAS,YAAA,CAAa,KAAA,EAAkB,YAAA,EAAuB,aAAA,EAAuC;AACpG,EAAA,MAAM,YAAY,YAAA,CAAa,KAAA,CAAM,QAAA,EAAU,YAAA,EAAc,MAAM,GAAG,CAAA;AACtE,EAAA,MAAM,aAAA,GAAgB,KAAA,CAAM,SAAA,GACxB,gBAAA,CAAiB,KAAA,CAAM,SAAA,CAAU,IAAA,EAAM,aAAA,EAAe,KAAA,CAAM,SAAA,CAAU,OAAO,CAAA,GAC7E,SAAA;AAEJ,EAAA,MAAM,eAAA,GAAkB,MAAM,SAAA,GAC1B,gBAAA,CAAiB,MAAM,SAAA,CAAU,IAAA,EAAM,aAAA,EAAe,KAAA,CAAM,SAAA,CAAU,OAAO,IAC7E,OAAA,GACA,gBAAA,CAAiB,MAAM,SAAA,CAAU,UAAA,EAAY,eAAe,KAAA,CAAM,SAAA,CAAU,OAAO,CAAA,GACnF,KAAA,GACA,MAAA;AAEJ,EAAA,OAAO;AAAA,IACL,MAAM,KAAA,CAAM,IAAA;AAAA,IACZ,UAAU,KAAA,CAAM,QAAA;AAAA,IAChB,KAAK,KAAA,CAAM,GAAA;AAAA,IACX,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,QAAQ,KAAA,CAAM,MAAA;AAAA,IACd,SAAA;AAAA,IACA,aAAA;AAAA,IACA,eAAA;AAAA,IACA,cAAA,EAAgB,MAAM,SAAA,EAAW,KAAA;AAAA,IACjC,eAAA,EAAiB,MAAM,SAAA,EAAW,MAAA;AAAA,IAClC,QAAA,EAAU,MAAM,SAAA,EAAW;AAAA,GAC7B;AACF;AAKA,eAAe,cAAA,CACb,OAAA,EACA,YAAA,EACA,aAAA,EAC0B;AAC1B,EAAA,MAAM,oBAAoB,OAAA,CAAQ,WAAA,GAAc,MAAM,cAAA,CAAe,OAAA,CAAQ,WAAW,CAAA,GAAI,EAAA;AAE5F,EAAA,OAAO;AAAA,IACL,OAAO,OAAA,CAAQ,KAAA;AAAA,IACf,aAAa,OAAA,CAAQ,WAAA;AAAA,IACrB,iBAAA;AAAA,IACA,MAAA,EAAQ,OAAA,CAAQ,MAAA,CAAO,GAAA,CAAI,CAAC,QAAQ,YAAA,CAAa,GAAA,EAAK,YAAA,EAAc,aAAa,CAAC;AAAA,GACpF;AACF;AAKA,SAAS,iBAAA,CAAkB,YAAwB,eAAA,EAA8C;AAC/F,EAAA,OAAO;AAAA,IACL,OAAO,UAAA,CAAW,KAAA;AAAA,IAClB,aAAa,UAAA,CAAW,WAAA;AAAA,IACxB,MAAM,UAAA,CAAW,IAAA;AAAA,IACjB,aAAA,EAAe,0BAAA,CAA2B,UAAA,CAAW,WAAW,CAAA;AAAA,IAChE,cAAc,eAAA,GAAkB,eAAA,CAAgB,UAAA,CAAW,IAAA,EAAM,eAAe,CAAA,GAAI;AAAA,GACtF;AACF;AAKA,eAAe,YAAY,OAAA,EAA6C;AACtE,EAAA,MAAM,EAAE,OAAO,WAAA,EAAa,WAAA,EAAa,qBAAqB,mBAAA,EAAqB,YAAA,EAAc,eAAc,GAAI,OAAA;AAEnH,EAAA,MAAM,iBAAA,GAAoB,WAAA,GAAc,MAAM,cAAA,CAAe,WAAW,CAAA,GAAI,EAAA;AAC5E,EAAA,MAAM,WAAA,GAAc,cAAcA,IAAAA,CAAK,QAAA,CAAS,aAAaA,IAAAA,CAAK,OAAA,CAAQ,WAAW,CAAC,CAAA,GAAI,QAAA;AAC1F,EAAA,MAAM,oBAAoB,aAAA,IAAiB,gBAAA;AAC3C,EAAA,MAAM,eAAA,GAAkB,YAAA,CAAa,WAAA,IAAe,EAAA,EAAI,YAAY,CAAA;AAIpE,EAAA,MAAM,kBAAkB,CAAC,mBAAA;AAEzB,EAAA,MAAM,OAAA,GAAU;AAAA,IACd,YAAA,EAAc,eAAA;AAAA,MACZ,qBAAqB,QAAA,EAAU,IAAA;AAAA,MAC/B,cAAA;AAAA,MACA,iBAAA;AAAA,MACA,WAAA;AAAA,MACA,UAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA,KACF;AAAA,IACA,WAAA,EAAa,eAAA;AAAA,MACX,qBAAqB,QAAA,EAAU,GAAA;AAAA,MAC/B,cAAA;AAAA,MACA,iBAAA;AAAA,MACA,WAAA;AAAA,MACA,UAAA;AAAA,MACA,KAAA;AAAA,MACA;AAAA,KACF;AAAA,IACA,aAAA,EAAe,eAAA;AAAA,MACb,qBAAqB,SAAA,EAAW,IAAA;AAAA,MAChC,eAAA;AAAA,MACA,iBAAA;AAAA,MACA,WAAA;AAAA,MACA,WAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA,KACF;AAAA,IACA,YAAA,EAAc,eAAA;AAAA,MACZ,qBAAqB,SAAA,EAAW,GAAA;AAAA,MAChC,eAAA;AAAA,MACA,iBAAA;AAAA,MACA,WAAA;AAAA,MACA,WAAA;AAAA,MACA,KAAA;AAAA,MACA;AAAA;AACF,GACF;AAEA,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,WAAA;AAAA,IACA,iBAAA;AAAA,IACA,WAAA;AAAA,IACA,eAAA;AAAA,IACA,mBAAA;AAAA,IACA,mBAAA;AAAA,IACA,iBAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACF;AACF;AA+BA,eAAsB,kBAAA,CACpB,SACA,OAAA,EAC8B;AAC9B,EAAA,MAAM,EAAE,YAAA,EAAc,aAAA,EAAe,YAAA,EAAa,GAAI,OAAA;AACtD,EAAA,MAAM,EAAE,eAAA,EAAiB,WAAA,EAAa,SAAA,EAAU,GAAI,WAAW,EAAC;AAEhE,EAAA,MAAM,IAAA,GAAO,MAAM,WAAA,CAAY,OAAO,CAAA;AACtC,EAAA,MAAM,QAAA,GAAW,MAAM,OAAA,CAAQ,GAAA;AAAA,IAC7B,OAAA,CAAQ,SAAS,GAAA,CAAI,CAAC,YAAY,cAAA,CAAe,OAAA,EAAS,YAAA,EAAc,aAAa,CAAC;AAAA,GACxF;AAEA,EAAA,MAAM,oBAAA,GAAuB,YAAA,EAAc,SAAA,EAAW,MAAA,GAClD;AAAA,IACE,OAAO,YAAA,CAAa,KAAA;AAAA,IACpB,SAAA,EAAW,aAAa,SAAA,CAAU,GAAA,CAAI,CAAC,EAAA,KAAO,iBAAA,CAAkB,EAAA,EAAI,eAAe,CAAC;AAAA,GACtF,GACA,MAAA;AAGJ,EAAA,MAAM,sBAAA,GAAyB,kCAAkC,OAAO,CAAA;AACxE,EAAA,MAAM,UAAA,GAAa,oBAAA,CAAqB,SAAA,EAAW,sBAAA,EAAwB,WAAW,CAAA;AAEtF,EAAA,OAAO;AAAA,IACL,OAAO,OAAA,CAAQ,KAAA;AAAA,IACf,KAAK,OAAA,CAAQ,GAAA;AAAA,IACb,UAAU,OAAA,CAAQ,QAAA;AAAA,IAClB,iBAAiB,OAAA,CAAQ,eAAA;AAAA,IACzB,WAAW,OAAA,CAAQ,SAAA;AAAA,IACnB,IAAA;AAAA,IACA,QAAA;AAAA,IACA,YAAA,EAAc,oBAAA;AAAA,IACd,YAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACF;AACF;AC9LO,SAAS,wBAAA,GAA6C;AAC3D,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,6BAAA;AAAA,IACN,KAAA,EAAO;AAAA,MACL,kBAAA,EAAoB,CAAC,EAAE,GAAA,EAAI,KAAM;AAC/B,QAAA,MAAM,aAAA,GAAgB,CAAC,oBAAA,EAAsB,qBAAqB,CAAA;AAClE,QAAA,KAAA,MAAW,YAAY,aAAA,EAAe;AACpC,UAAA,MAAM,QAAA,GAAWA,IAAAA,CAAK,IAAA,CAAK,GAAA,CAAI,UAAU,QAAQ,CAAA;AACjD,UAAA,IAAIC,EAAAA,CAAG,UAAA,CAAW,QAAQ,CAAA,EAAG;AAC3B,YAAA,IAAI;AACF,cAAA,MAAM,OAAA,GAAUA,EAAAA,CAAG,YAAA,CAAa,QAAA,EAAU,MAAM,CAAA;AAChD,cAAA,IAAI,QAAQ,IAAA,EAAK,KAAM,+BAA+B,OAAA,CAAQ,IAAA,OAAW,EAAA,EAAI;AAC3E,gBAAAA,EAAAA,CAAG,WAAW,QAAQ,CAAA;AAAA,cACxB;AAAA,YACF,CAAA,CAAA,MAAQ;AAAA,YAER;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA;AACF,GACF;AACF","file":"theme.js","sourcesContent":["import { z } from 'zod';\n\n/** Zod schema for thumbnail configuration */\nexport const ThumbnailConfigSchema = z.object({\n size: z.number().min(50).max(4000).optional(),\n edge: z.enum(['auto', 'width', 'height']).optional(),\n});\n\n/** Zod schema for theme configuration file (themeConfig.json) */\nexport const ThemeConfigSchema = z.object({\n thumbnails: ThumbnailConfigSchema.optional(),\n});\n\n/** TypeScript type for thumbnail configuration */\nexport type ThumbnailConfig = z.infer<typeof ThumbnailConfigSchema>;\n\n/** TypeScript type for theme configuration */\nexport type ThemeConfig = z.infer<typeof ThemeConfigSchema>;\n\n/** Default thumbnail configuration values */\nexport const DEFAULT_THUMBNAIL_CONFIG: Required<ThumbnailConfig> = {\n size: 300,\n edge: 'auto',\n};\n\n/**\n * Extracts thumbnail config from gallery data.\n * @param gallery - The gallery data object\n * @returns ThumbnailConfig with values from gallery data\n */\nexport function extractThumbnailConfigFromGallery(gallery: { thumbnails?: ThumbnailConfig }): ThumbnailConfig {\n return {\n size: gallery.thumbnails?.size,\n edge: gallery.thumbnails?.edge,\n };\n}\n\n/**\n * Merges thumbnail configurations with hierarchy:\n * 1. CLI flags (highest precedence)\n * 2. gallery.json settings\n * 3. themeConfig.json (theme defaults)\n * 4. Built-in defaults (lowest)\n *\n * @param cliConfig - Config from CLI flags (optional)\n * @param galleryConfig - Config from gallery.json (optional)\n * @param themeConfig - Config from themeConfig.json (optional)\n * @returns Merged thumbnail configuration with all values resolved\n */\nexport function mergeThumbnailConfig(\n cliConfig?: ThumbnailConfig,\n galleryConfig?: ThumbnailConfig,\n themeConfig?: ThumbnailConfig,\n): Required<ThumbnailConfig> {\n return {\n size: cliConfig?.size ?? galleryConfig?.size ?? themeConfig?.size ?? DEFAULT_THUMBNAIL_CONFIG.size,\n edge: cliConfig?.edge ?? galleryConfig?.edge ?? themeConfig?.edge ?? DEFAULT_THUMBNAIL_CONFIG.edge,\n };\n}\n","/** Portrait image sizes for responsive hero images */\nexport const PORTRAIT_SIZES = [360, 480, 720, 1080] as const;\n\n/** Landscape image sizes for responsive hero images */\nexport const LANDSCAPE_SIZES = [640, 960, 1280, 1920, 2560, 3840] as const;\n","import { marked } from 'marked';\n\n// Configure marked to only allow specific formatting options\nconst renderer = new marked.Renderer();\n\n// Disable headings by rendering them as paragraphs\nrenderer.heading = ({ text }: { text: string }) => {\n return '<p>' + text + '</p>\\n';\n};\n\n// Disable images\nrenderer.image = () => '';\n\n// Disable HTML\nrenderer.html = () => '';\n\n// Disable tables\nrenderer.table = () => '';\nrenderer.tablerow = () => '';\nrenderer.tablecell = () => '';\n\n// Configure marked options\nmarked.use({\n renderer: renderer,\n breaks: true,\n gfm: true,\n});\n\n/**\n * Renders markdown with limited formatting options.\n * Supported: paragraphs, bold, italic, lists, code blocks, blockquotes, links\n * Disabled: headings (rendered as paragraphs), images, HTML, tables\n */\nexport async function renderMarkdown(markdown: string): Promise<string> {\n if (!markdown) return '';\n return await marked.parse(markdown);\n}\n","import path from 'node:path';\n\n/**\n * Normalizes resource paths to be relative to the gallery root directory.\n *\n * @param resourcePath - The resource path (file or directory), typically relative to the gallery.json file\n * @param galleryJsonPath - Path to the gallery.json file used to resolve relative paths\n * @returns The normalized path relative to the gallery root directory\n */\nexport function getRelativePath(resourcePath: string, galleryJsonPath: string): string {\n const galleryConfigPath = path.resolve(galleryJsonPath);\n const galleryConfigDir = path.dirname(galleryConfigPath);\n\n const absoluteResourcePath = path.resolve(path.join(galleryConfigDir, resourcePath));\n const baseDir = path.dirname(galleryConfigDir);\n\n return path.relative(baseDir, absoluteResourcePath);\n}\n\n/**\n * Get the path to a thumbnail that is relative to the gallery root directory or the thumbnails base URL.\n *\n * @param resourcePath - The resource path (file or directory), typically relative to the gallery.json file\n * @param thumbsBaseUrl - The base URL for the thumbnails (gallery-level)\n * @param thumbnailBaseUrl - Optional thumbnail-specific base URL that overrides thumbsBaseUrl if provided\n * @returns The normalized path relative to the gallery root directory or the thumbnails base URL\n */\nexport function getThumbnailPath(resourcePath: string, thumbsBaseUrl?: string, thumbnailBaseUrl?: string): string {\n // If thumbnail-specific baseUrl is provided, use it and combine with the path\n if (thumbnailBaseUrl) {\n return `${thumbnailBaseUrl}/${resourcePath}`;\n }\n // Otherwise, use the gallery-level thumbsBaseUrl if provided\n return thumbsBaseUrl ? `${thumbsBaseUrl}/${resourcePath}` : `gallery/images/${path.basename(resourcePath)}`;\n}\n\n/**\n * Get the path to a photo that is always in the gallery root directory.\n *\n * @param filename - The filename to get the path for\n * @param mediaBaseUrl - The base URL for the media\n * @param url - Optional URL that, if provided, will be used directly regardless of base URL or path\n * @returns The normalized path relative to the gallery root directory, or the provided URL\n */\nexport function getPhotoPath(filename: string, mediaBaseUrl?: string, url?: string): string {\n // If url is provided, always use it regardless of base URL or path\n if (url) {\n return url;\n }\n\n return mediaBaseUrl ? `${mediaBaseUrl}/${filename}` : filename;\n}\n\n/**\n * Get the path to a subgallery thumbnail that is always in the subgallery directory.\n *\n * @param subgalleryHeaderImagePath - The path to the subgallery header image on the hard disk\n * @returns The normalized path relative to the subgallery directory\n */\nexport function getSubgalleryThumbnailPath(subgalleryHeaderImagePath: string): string {\n const photoBasename = path.basename(subgalleryHeaderImagePath);\n const subgalleryFolderName = path.basename(path.dirname(subgalleryHeaderImagePath));\n\n return path.join(subgalleryFolderName, 'gallery', 'thumbnails', photoBasename);\n}\n\n/**\n * Build a srcset string for responsive images.\n * Uses custom paths from variants when provided, otherwise generates default paths.\n *\n * @param variants - Optional record mapping sizes to custom URLs\n * @param sizes - Array of image widths to include\n * @param thumbnailBasePath - Base path for generated thumbnails\n * @param imgBasename - Image basename for generated paths\n * @param orientation - 'portrait' or 'landscape'\n * @param format - Image format ('avif' or 'jpg')\n * @param useDefaultPaths - Whether to use generated paths when no custom variant exists\n * @returns Comma-separated srcset string\n */\nexport function buildHeroSrcset(\n variants: Record<number, string | undefined> | undefined,\n sizes: readonly number[],\n thumbnailBasePath: string,\n imgBasename: string,\n orientation: 'portrait' | 'landscape',\n format: 'avif' | 'jpg',\n useDefaultPaths: boolean,\n): string {\n return sizes\n .map((size) => {\n const customPath = variants?.[size];\n if (customPath) {\n return `${customPath} ${size}w`;\n }\n if (useDefaultPaths) {\n return `${thumbnailBasePath}/${imgBasename}_${orientation}_${size}.${format} ${size}w`;\n }\n return null;\n })\n .filter(Boolean)\n .join(', ');\n}\n","import { z } from 'zod';\n\n/** Zod schema for thumbnail metadata including path and dimensions */\nexport const ThumbnailSchema = z.object({\n baseUrl: z.string().optional(),\n path: z.string(),\n pathRetina: z.string(),\n width: z.number(),\n height: z.number(),\n blurHash: z.string().optional(),\n});\n\n/** Zod schema for media file metadata including type, dimensions, and thumbnail info */\nexport const MediaFileSchema = z.object({\n type: z.enum(['image', 'video']),\n filename: z.string(),\n url: z.string().optional(),\n alt: z.string().optional(),\n width: z.number(),\n height: z.number(),\n thumbnail: ThumbnailSchema.optional(),\n lastMediaTimestamp: z.string().optional(),\n});\n\n/**\n * Zod schema for media file with path.\n * @deprecated Use MediaFileSchema instead which uses 'filename' instead of 'path'.\n */\nexport const MediaFileDeprecatedSchema = z.object({\n type: z.enum(['image', 'video']),\n path: z.string(),\n alt: z.string().optional(),\n width: z.number(),\n height: z.number(),\n thumbnail: ThumbnailSchema.optional(),\n lastMediaTimestamp: z.string().optional(),\n});\n\n/** Zod schema for a gallery section containing title, description, and media files */\nexport const GallerySectionSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n images: z.array(MediaFileSchema),\n});\n\n/**\n * Zod schema for a gallery section containing title, description, and media files.\n * @deprecated Use GallerySectionSchema instead which uses MediaFileSchema.\n */\nexport const GallerySectionDeprecatedSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n images: z.array(MediaFileDeprecatedSchema),\n});\n\n/** Zod schema for sub-gallery metadata including title, header image, and path */\nexport const SubGallerySchema = z.object({\n title: z.string(),\n headerImage: z.string(),\n path: z.string(),\n});\n\n/** Zod schema for portrait image size variants */\nconst PortraitSizesSchema = z.object({\n 360: z.string().optional(),\n 480: z.string().optional(),\n 720: z.string().optional(),\n 1080: z.string().optional(),\n});\n\n/** Zod schema for landscape image size variants */\nconst LandscapeSizesSchema = z.object({\n 640: z.string().optional(),\n 960: z.string().optional(),\n 1280: z.string().optional(),\n 1920: z.string().optional(),\n 2560: z.string().optional(),\n 3840: z.string().optional(),\n});\n\n/** Zod schema for header image variants allowing explicit specification of responsive hero images */\nexport const HeaderImageVariantsSchema = z.object({\n portrait: z\n .object({\n avif: PortraitSizesSchema.optional(),\n jpg: PortraitSizesSchema.optional(),\n })\n .optional(),\n landscape: z\n .object({\n avif: LandscapeSizesSchema.optional(),\n jpg: LandscapeSizesSchema.optional(),\n })\n .optional(),\n});\n\n/** Zod schema for complete gallery data including metadata, sections, and sub-galleries */\nexport const GalleryMetadataSchema = z.object({\n image: z.string().optional(),\n imageWidth: z.number().optional(),\n imageHeight: z.number().optional(),\n ogUrl: z.string().optional(),\n ogType: z.string().optional(),\n ogSiteName: z.string().optional(),\n twitterSite: z.string().optional(),\n twitterCreator: z.string().optional(),\n author: z.string().optional(),\n keywords: z.string().optional(),\n canonicalUrl: z.string().optional(),\n language: z.string().optional(),\n robots: z.string().optional(),\n});\n\n/** Zod schema for complete gallery data including metadata, sections, and sub-galleries */\nexport const GalleryDataSchema = z.object({\n title: z.string(),\n description: z.string(),\n mediaBasePath: z.string().optional(),\n url: z.string().optional(),\n headerImage: z.string(),\n headerImageBlurHash: z.string().optional(),\n headerImageVariants: HeaderImageVariantsSchema.optional(),\n theme: z.string().optional(),\n thumbnails: z\n .object({\n size: z.number().optional(),\n edge: z.enum(['auto', 'width', 'height']).optional(),\n })\n .optional(),\n metadata: GalleryMetadataSchema,\n mediaBaseUrl: z.string().optional(),\n thumbsBaseUrl: z.string().optional(),\n analyticsScript: z.string().optional(),\n ctaBanner: z.boolean().optional(),\n sections: z.array(GallerySectionSchema),\n subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) }),\n});\n\n/**\n * Zod schema for complete gallery data without mediaBasePath.\n * @deprecated Use GalleryDataSchema instead which includes mediaBasePath and headerImageVariants.\n */\nexport const GalleryDataDeprecatedSchema = z.object({\n title: z.string(),\n description: z.string(),\n url: z.string().optional(),\n headerImage: z.string(),\n thumbnailSize: z.number().optional(),\n metadata: GalleryMetadataSchema,\n mediaBaseUrl: z.string().optional(),\n analyticsScript: z.string().optional(),\n sections: z.array(GallerySectionDeprecatedSchema),\n subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) }),\n});\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\n\nimport { ThemeConfigSchema, type ThumbnailConfig } from './config';\n\nimport { GalleryDataSchema, type GalleryData } from '../gallery';\n\nexport interface LoadGalleryDataOptions {\n /**\n * When true, validates the loaded JSON against the GalleryData schema.\n * Throws a descriptive error if validation fails.\n * @default false\n */\n validate?: boolean;\n}\n\n/**\n * Load theme configuration from themeConfig.json file.\n *\n * Searches for themeConfig.json in the following locations (in priority order):\n * 1. Current working directory (process.cwd()) - checked first\n * 2. Provided themePath parameter - checked second\n *\n * The first valid configuration found is returned. This means a themeConfig.json\n * in the project root will take precedence over the theme's built-in configuration,\n * allowing users to override theme defaults without modifying the theme itself.\n *\n * **Note for theme authors:** Your theme's themeConfig.json provides sensible defaults,\n * but users can override these by placing their own themeConfig.json in their project root.\n *\n * @param themePath - Optional path to the theme directory\n * @returns The thumbnail configuration from the theme, or undefined if not found\n *\n * @example\n * ```typescript\n * // Load from theme directory\n * const themeConfig = loadThemeConfig('/path/to/theme');\n *\n * // Load from current directory\n * const themeConfig = loadThemeConfig();\n * ```\n */\nexport function loadThemeConfig(themePath?: string): ThumbnailConfig | undefined {\n const themeConfigPaths: string[] = [path.resolve(process.cwd(), 'themeConfig.json')];\n\n if (themePath) {\n themeConfigPaths.push(path.resolve(themePath, 'themeConfig.json'));\n }\n\n for (const configPath of themeConfigPaths) {\n if (fs.existsSync(configPath)) {\n try {\n const configData = JSON.parse(fs.readFileSync(configPath, 'utf8'));\n const parsed = ThemeConfigSchema.safeParse(configData);\n if (parsed.success) {\n return parsed.data.thumbnails;\n }\n // Log validation errors for debugging\n if (process.env.DEBUG || process.env.VERBOSE) {\n console.warn(`Failed to validate themeConfig at ${configPath}:`, parsed.error.message);\n }\n } catch (error) {\n // Log parse errors for debugging\n if (process.env.DEBUG || process.env.VERBOSE) {\n console.warn(`Failed to parse themeConfig at ${configPath}:`, error);\n }\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Load gallery data from a JSON file.\n *\n * @param galleryJsonPath - Path to the gallery.json file. Defaults to './gallery.json'.\n * @param options - Optional settings for loading behavior.\n * @returns The parsed gallery data\n * @throws Error if file cannot be read, parsed, or fails validation\n *\n * @example\n * ```typescript\n * // Basic usage (no validation)\n * const gallery = loadGalleryData('./gallery.json');\n *\n * // With schema validation\n * const gallery = loadGalleryData('./gallery.json', { validate: true });\n * ```\n */\nexport function loadGalleryData(galleryJsonPath = './gallery.json', options?: LoadGalleryDataOptions): GalleryData {\n const galleryData = JSON.parse(fs.readFileSync(galleryJsonPath, 'utf8'));\n\n if (options?.validate) {\n const result = GalleryDataSchema.safeParse(galleryData);\n if (!result.success) {\n throw new Error(`Invalid gallery.json at ${galleryJsonPath}: ${result.error.message}`);\n }\n return result.data;\n }\n\n return galleryData as GalleryData;\n}\n","import path from 'node:path';\n\nimport { extractThumbnailConfigFromGallery, mergeThumbnailConfig, type ThumbnailConfig } from './config';\nimport { LANDSCAPE_SIZES, PORTRAIT_SIZES } from './constants';\nimport { renderMarkdown } from './markdown';\nimport { buildHeroSrcset, getPhotoPath, getRelativePath, getSubgalleryThumbnailPath, getThumbnailPath } from './paths';\n\nimport type { GalleryData, GallerySection, MediaFile, SubGallery } from '../gallery';\nimport type { ResolvedGalleryData, ResolvedHero, ResolvedImage, ResolvedSection, ResolvedSubGallery } from './types';\n\n/**\n * Resolve a single image with all paths computed.\n */\nfunction resolveImage(image: MediaFile, mediaBaseUrl?: string, thumbsBaseUrl?: string): ResolvedImage {\n const imagePath = getPhotoPath(image.filename, mediaBaseUrl, image.url);\n const thumbnailPath = image.thumbnail\n ? getThumbnailPath(image.thumbnail.path, thumbsBaseUrl, image.thumbnail.baseUrl)\n : imagePath;\n\n const thumbnailSrcSet = image.thumbnail\n ? getThumbnailPath(image.thumbnail.path, thumbsBaseUrl, image.thumbnail.baseUrl) +\n ' 1x, ' +\n getThumbnailPath(image.thumbnail.pathRetina, thumbsBaseUrl, image.thumbnail.baseUrl) +\n ' 2x'\n : undefined;\n\n return {\n type: image.type,\n filename: image.filename,\n alt: image.alt,\n width: image.width,\n height: image.height,\n imagePath,\n thumbnailPath,\n thumbnailSrcSet,\n thumbnailWidth: image.thumbnail?.width,\n thumbnailHeight: image.thumbnail?.height,\n blurHash: image.thumbnail?.blurHash,\n };\n}\n\n/**\n * Resolve a section with parsed markdown and resolved image paths.\n */\nasync function resolveSection(\n section: GallerySection,\n mediaBaseUrl?: string,\n thumbsBaseUrl?: string,\n): Promise<ResolvedSection> {\n const parsedDescription = section.description ? await renderMarkdown(section.description) : '';\n\n return {\n title: section.title,\n description: section.description,\n parsedDescription,\n images: section.images.map((img) => resolveImage(img, mediaBaseUrl, thumbsBaseUrl)),\n };\n}\n\n/**\n * Resolve a sub-gallery with computed thumbnail path and optional resolved path.\n */\nfunction resolveSubGallery(subGallery: SubGallery, galleryJsonPath?: string): ResolvedSubGallery {\n return {\n title: subGallery.title,\n headerImage: subGallery.headerImage,\n path: subGallery.path,\n thumbnailPath: getSubgalleryThumbnailPath(subGallery.headerImage),\n resolvedPath: galleryJsonPath ? getRelativePath(subGallery.path, galleryJsonPath) : undefined,\n };\n}\n\n/**\n * Resolve hero data with all paths computed and srcsets built.\n */\nasync function resolveHero(gallery: GalleryData): Promise<ResolvedHero> {\n const { title, description, headerImage, headerImageBlurHash, headerImageVariants, mediaBaseUrl, thumbsBaseUrl } = gallery;\n\n const parsedDescription = description ? await renderMarkdown(description) : '';\n const imgBasename = headerImage ? path.basename(headerImage, path.extname(headerImage)) : 'header';\n const thumbnailBasePath = thumbsBaseUrl || 'gallery/images';\n const headerPhotoPath = getPhotoPath(headerImage || '', mediaBaseUrl);\n\n // Determine which sources to show based on headerImageVariants\n // If headerImageVariants is not set, use all generated paths (default behavior)\n const useDefaultPaths = !headerImageVariants;\n\n const srcsets = {\n portraitAvif: buildHeroSrcset(\n headerImageVariants?.portrait?.avif,\n PORTRAIT_SIZES,\n thumbnailBasePath,\n imgBasename,\n 'portrait',\n 'avif',\n useDefaultPaths,\n ),\n portraitJpg: buildHeroSrcset(\n headerImageVariants?.portrait?.jpg,\n PORTRAIT_SIZES,\n thumbnailBasePath,\n imgBasename,\n 'portrait',\n 'jpg',\n useDefaultPaths,\n ),\n landscapeAvif: buildHeroSrcset(\n headerImageVariants?.landscape?.avif,\n LANDSCAPE_SIZES,\n thumbnailBasePath,\n imgBasename,\n 'landscape',\n 'avif',\n useDefaultPaths,\n ),\n landscapeJpg: buildHeroSrcset(\n headerImageVariants?.landscape?.jpg,\n LANDSCAPE_SIZES,\n thumbnailBasePath,\n imgBasename,\n 'landscape',\n 'jpg',\n useDefaultPaths,\n ),\n };\n\n return {\n title,\n description,\n parsedDescription,\n headerImage,\n headerPhotoPath,\n headerImageBlurHash,\n headerImageVariants,\n thumbnailBasePath,\n imgBasename,\n srcsets,\n };\n}\n\n/**\n * Options for resolving gallery data.\n */\nexport interface ResolveGalleryDataOptions {\n /**\n * Path to the gallery.json file. When provided, enables resolution of\n * relative paths for sub-galleries (resolvedPath field).\n */\n galleryJsonPath?: string;\n /**\n * Theme-specific thumbnail configuration from themeConfig.json.\n * Used as fallback when gallery.json doesn't specify thumbnail settings.\n */\n themeConfig?: ThumbnailConfig;\n /**\n * CLI-specified thumbnail configuration (highest priority).\n * Overrides both gallery.json and theme config settings.\n */\n cliConfig?: ThumbnailConfig;\n}\n\n/**\n * Transform raw gallery data into a fully resolved structure with all paths\n * computed and markdown parsed. This is the main API for themes.\n *\n * @param gallery - Raw gallery data from loadGalleryData()\n * @param options - Optional configuration for path resolution\n * @returns Fully resolved gallery data ready for rendering\n */\nexport async function resolveGalleryData(\n gallery: GalleryData,\n options?: ResolveGalleryDataOptions,\n): Promise<ResolvedGalleryData> {\n const { mediaBaseUrl, thumbsBaseUrl, subGalleries } = gallery;\n const { galleryJsonPath, themeConfig, cliConfig } = options ?? {};\n\n const hero = await resolveHero(gallery);\n const sections = await Promise.all(\n gallery.sections.map((section) => resolveSection(section, mediaBaseUrl, thumbsBaseUrl)),\n );\n\n const resolvedSubGalleries = subGalleries?.galleries?.length\n ? {\n title: subGalleries.title,\n galleries: subGalleries.galleries.map((sg) => resolveSubGallery(sg, galleryJsonPath)),\n }\n : undefined;\n\n // Merge thumbnail config: CLI > gallery.json > themeConfig > defaults\n const galleryThumbnailConfig = extractThumbnailConfigFromGallery(gallery);\n const thumbnails = mergeThumbnailConfig(cliConfig, galleryThumbnailConfig, themeConfig);\n\n return {\n title: gallery.title,\n url: gallery.url,\n metadata: gallery.metadata,\n analyticsScript: gallery.analyticsScript,\n ctaBanner: gallery.ctaBanner,\n hero,\n sections,\n subGalleries: resolvedSubGalleries,\n mediaBaseUrl,\n thumbsBaseUrl,\n thumbnails,\n };\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\n/** Astro integration type (simplified to avoid astro dependency in common) */\ninterface AstroIntegration {\n name: string;\n hooks: {\n 'astro:build:done': (options: { dir: URL }) => void;\n };\n}\n\n/**\n * Astro integration to prevent empty content collection files from being generated.\n * Removes empty content-assets.mjs and content-modules.mjs files after build.\n */\nexport function preventEmptyContentFiles(): AstroIntegration {\n return {\n name: 'prevent-empty-content-files',\n hooks: {\n 'astro:build:done': ({ dir }) => {\n const filesToRemove = ['content-assets.mjs', 'content-modules.mjs'];\n for (const fileName of filesToRemove) {\n const filePath = path.join(dir.pathname, fileName);\n if (fs.existsSync(filePath)) {\n try {\n const content = fs.readFileSync(filePath, 'utf8');\n if (content.trim() === 'export default new Map();' || content.trim() === '') {\n fs.unlinkSync(filePath);\n }\n } catch {\n // Silently ignore errors\n }\n }\n }\n },\n },\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simple-photo-gallery/common",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Shared utilities and types for Simple Photo Gallery",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Vladimir Haltakov, Tomasz Rusin",
|
|
@@ -16,7 +16,16 @@
|
|
|
16
16
|
"types": "./dist/gallery.d.ts",
|
|
17
17
|
"import": "./dist/gallery.js",
|
|
18
18
|
"require": "./dist/gallery.cjs"
|
|
19
|
-
}
|
|
19
|
+
},
|
|
20
|
+
"./theme": {
|
|
21
|
+
"types": "./dist/theme.d.ts",
|
|
22
|
+
"import": "./dist/theme.js"
|
|
23
|
+
},
|
|
24
|
+
"./client": {
|
|
25
|
+
"types": "./dist/client.d.ts",
|
|
26
|
+
"import": "./dist/client.js"
|
|
27
|
+
},
|
|
28
|
+
"./styles/photoswipe": "./dist/styles/photoswipe/photoswipe.css"
|
|
20
29
|
},
|
|
21
30
|
"files": [
|
|
22
31
|
"dist"
|
|
@@ -33,12 +42,26 @@
|
|
|
33
42
|
"prepublish": "yarn build"
|
|
34
43
|
},
|
|
35
44
|
"dependencies": {
|
|
45
|
+
"marked": "^16.0.0",
|
|
36
46
|
"zod": "^4.0.14"
|
|
37
47
|
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"blurhash": "^2.0.5",
|
|
50
|
+
"photoswipe": "^5.4.4"
|
|
51
|
+
},
|
|
52
|
+
"peerDependenciesMeta": {
|
|
53
|
+
"blurhash": {
|
|
54
|
+
"optional": true
|
|
55
|
+
},
|
|
56
|
+
"photoswipe": {
|
|
57
|
+
"optional": true
|
|
58
|
+
}
|
|
59
|
+
},
|
|
38
60
|
"devDependencies": {
|
|
39
61
|
"@eslint/eslintrc": "^3.3.1",
|
|
40
62
|
"@eslint/js": "^9.30.1",
|
|
41
63
|
"@types/node": "^24.0.10",
|
|
64
|
+
"@types/photoswipe": "^4.1.6",
|
|
42
65
|
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
|
43
66
|
"@typescript-eslint/parser": "^8.38.0",
|
|
44
67
|
"eslint": "^9.30.1",
|