📦 EqualifyEverything / equalify-reflow

📄 bundleDownload.ts · 45 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45import JSZip from 'jszip';

import type { PipelineViewerResult } from '@/types/pipeline-viewer';

/**
 * Build a zip containing the selected version's markdown plus a `figures/`
 * folder of PNGs. Markdown already references `figures/{ref_id}.png` relative
 * paths (see `src/services/pipeline_viewer.py::_replace_image_placeholders`),
 * so no rewriting is needed — the zip is self-contained as-is.
 */
export async function buildMarkdownBundle(
  result: PipelineViewerResult,
  version: string,
  baseName: string,
): Promise<Blob> {
  const markdown = result.versions[version];
  if (!markdown) {
    throw new Error(`No markdown for version "${version}"`);
  }

  const zip = new JSZip();
  zip.file(`${baseName}-${version}.md`, markdown);

  const figuresDir = zip.folder('figures');
  if (figuresDir) {
    for (const fig of result.figures) {
      if (!fig.image_base64) continue;
      figuresDir.file(`${fig.ref_id}.png`, fig.image_base64, { base64: true });
    }
  }

  return zip.generateAsync({ type: 'blob' });
}

export function triggerBlobDownload(blob: Blob, filename: string): void {
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  URL.revokeObjectURL(url);
}