///|
pub(all) struct ReportOptions {
  svg : SvgOptions
  include_metadata : Bool
  theme : String
} derive(Debug, ToJson)

///|
pub fn ReportOptions::default() -> ReportOptions {
  { svg: SvgOptions::default(), include_metadata: true, theme: "light" }
}

///|
pub fn DebugDocument::to_html_report(self : DebugDocument) -> String {
  self.to_html_report_with(ReportOptions::default())
}

///|
pub fn DebugDocument::to_html_report_with(
  self : DebugDocument,
  options : ReportOptions,
) -> String {
  let out = StringBuilder()
  out.write_string("\n\n\n")
  out.write_string("\n")
  out.write_string(
    "\n",
  )
  out.write_string("\{escape_html(self.title)}\n")
  out.write_string("\n")
  out.write_string("\n\n")
  out.write_string("
\n") out.write_string("

\{escape_html(self.title)}

") out.write_string( "

\{self.image.width}x\{self.image.height}, \{self.overlay_count()} overlays

\n", ) out.write_string( "
\n\{self.to_svg_with(options.svg)}
\n", ) if options.include_metadata { write_layer_summary(out, self) } out.write_string("
\n\n\n") out.to_string() } ///| fn write_layer_summary(out : StringBuilder, doc : DebugDocument) -> Unit { out.write_string( "

Layers

", ) out.write_string( "", ) out.write_string("\n") for layer in doc.layers { out.write_string("") out.write_string("") out.write_string("\n") } out.write_string("
LayerVisibleOpacityOverlays
\{escape_html(layer.id)}\{layer.visible}\{layer.opacity}\{layer.overlays.length()}
\n") } ///| fn report_css(theme : String) -> String { let dark = theme == "dark" let bg = if dark { "#0f172a" } else { "#f8fafc" } let fg = if dark { "#e2e8f0" } else { "#0f172a" } let panel = if dark { "#111827" } else { "#ffffff" } let border = if dark { "#334155" } else { "#cbd5e1" } let css = $|:root{color-scheme:light dark} $|body{margin:0;background:\{bg};color:\{fg};font:14px/1.5 system-ui,-apple-system,Segoe UI,sans-serif} $|main{max-width:1120px;margin:0 auto;padding:24px} $|header{display:flex;align-items:baseline;justify-content:space-between;gap:16px;margin-bottom:18px} $|h1{font-size:24px;margin:0} $|h2{font-size:16px;margin:0 0 10px} $|p{margin:0;color:#64748b} $|.stage{background:\{panel};border:1px solid \{border};overflow:auto} $|.stage svg{display:block;max-width:100%;height:auto} $|.summary{margin-top:18px} $|table{width:100%;border-collapse:collapse;background:\{panel};border:1px solid \{border}} $|th,td{text-align:left;padding:8px 10px;border-bottom:1px solid \{border}} $|th{font-size:12px;text-transform:uppercase;color:#64748b} css } ///| fn escape_html(value : String) -> String { value .replace(old="&", new="&") .replace(old="<", new="<") .replace(old=">", new=">") .replace(old="\"", new=""") }