1import { mediaKindFromPath } from "@t3tools/shared/filePreview";
2import { mediaUrlReference } from "@t3tools/client-runtime/media-reference";
3import type { ExpandedImageItem, ExpandedImagePreview } from "./ExpandedImagePreview";
4import { resolveExternalWebLinkHost } from "./externalLinkContextMenu";
5import { resolveProtocolRelativeMediaUrl } from "../media/mediaContent";
6
7// Weak keys retain resolved media actions only while the rendered image is reachable.
8export const markdownImageItems = new WeakMap<Element, ExpandedImageItem>();
9
10/** Collect in document order only when opened, including PR sections separated by videos. */
11export function markdownImageGallery(
12 element: Element,
13 selected: ExpandedImageItem,
14): ExpandedImagePreview {
15 const scope = element.closest("[data-image-gallery]") ?? element.closest(".chat-markdown");
16 const images: ExpandedImageItem[] = [];
17 let index = -1;
18 for (const image of scope?.querySelectorAll("img") ?? []) {
19 const registered = markdownImageItems.get(image);
20 if (!registered) continue;
21 const link = image.closest("a");
22 const href = link?.getAttribute("href") ?? "";
23 if (link && mediaKindFromPath(href) !== "image") continue;
24 const linkedSource =
25 resolveExternalWebLinkHost(href) !== null ? resolveProtocolRelativeMediaUrl(href) : null;
26 const reference = mediaUrlReference(href);
27 const item = linkedSource
28 ? {
29 ...registered,
30 src: linkedSource,
31 originalUrl: href,
32 actionsSource: {
33 kind: "image" as const,
34 name: registered.name,
35 src: linkedSource,
36 ...(reference ? { reference } : {}),
37 },
38 }
39 : registered;
40 if (
41 image === element ||
42 (!markdownImageItems.has(element) && index < 0 && item.src === selected.src)
43 ) {
44 index = images.length;
45 images.push(selected);
46 } else {
47 images.push(item);
48 }
49 }
50 return index < 0 ? { images: [selected], index: 0 } : { images, index };
51}