staticdash 2025.22__tar.gz → 2025.24__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: staticdash
3
- Version: 2025.22
3
+ Version: 2025.24
4
4
  Summary: A lightweight static HTML dashboard generator with Plotly and pandas support.
5
5
  Author-email: Brian Day <brian.day1@gmail.com>
6
6
  License: CC0-1.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "staticdash"
7
- version = "2025.22"
7
+ version = "2025.24"
8
8
  description = "A lightweight static HTML dashboard generator with Plotly and pandas support."
9
9
  authors = [
10
10
  { name = "Brian Day", email = "brian.day1@gmail.com" }
@@ -427,6 +427,7 @@ class Dashboard:
427
427
  self.canv.bookmarkPage(key)
428
428
  self.canv.addOutlineEntry(text, key, level=outline_level, closed=False)
429
429
 
430
+
430
431
  self.notify('TOCEntry', (outline_level, text, self.page))
431
432
 
432
433
 
@@ -466,28 +467,29 @@ class Dashboard:
466
467
  story.append(PageBreak())
467
468
 
468
469
  def render_page(page, level=0, sec_prefix=[]):
469
- heading_style = styles['Heading1'] if level == 0 else styles['Heading2']
470
+ heading_style = styles.get(f'Heading{min(level + 1, 4)}', styles['Heading4'])
471
+
472
+ # Remember where we started
473
+ content_start = len(story)
470
474
 
471
- # Only add the page.title as a real heading if it's a top-level page
472
- if level == 0:
473
- story.append(Paragraph(page.title, heading_style))
474
- story.append(Spacer(1, 12))
475
+ story.append(Paragraph(page.title, heading_style))
476
+ story.append(Spacer(1, 12))
475
477
 
476
478
  for kind, content, _ in page.elements:
477
- if kind == "text":
478
- story.append(Paragraph(content, normal_style))
479
- story.append(Spacer(1, 8))
480
-
481
- elif kind == "header":
482
- text, lvl = content
483
- safe_lvl = max(1, min(lvl + 1, 4)) # Clamp to Heading1–Heading4
484
- style = styles[f'Heading{safe_lvl}']
485
- story.append(Paragraph(text, style))
486
- story.append(Spacer(1, 8))
487
-
488
- elif kind == "table":
489
- df = content
490
- try:
479
+ try:
480
+ if kind == "text":
481
+ story.append(Paragraph(content, normal_style))
482
+ story.append(Spacer(1, 8))
483
+
484
+ elif kind == "header":
485
+ text, lvl = content
486
+ safe_lvl = max(1, min(lvl + 1, 4))
487
+ style = styles[f'Heading{safe_lvl}']
488
+ story.append(Paragraph(text, style))
489
+ story.append(Spacer(1, 8))
490
+
491
+ elif kind == "table":
492
+ df = content
491
493
  data = [df.columns.tolist()] + df.values.tolist()
492
494
  t = Table(data, repeatRows=1)
493
495
  t.setStyle(TableStyle([
@@ -509,47 +511,59 @@ class Dashboard:
509
511
  ]))
510
512
  story.append(t)
511
513
  story.append(Spacer(1, 12))
512
- except Exception:
513
- story.append(Paragraph("Table could not be rendered.", normal_style))
514
514
 
515
- elif kind == "plot":
516
- fig = content
517
- try:
518
- if hasattr(fig, "savefig"): # Matplotlib
519
- buf = io.BytesIO()
515
+ elif kind == "plot":
516
+ fig = content
517
+ buf = io.BytesIO()
518
+ if hasattr(fig, "savefig"):
520
519
  fig.savefig(buf, format="png", bbox_inches="tight", dpi=300)
521
- buf.seek(0)
522
- story.append(Spacer(1, 8))
523
- story.append(Image(buf, width=6*inch, height=4.5*inch))
524
- story.append(Spacer(1, 12))
525
- elif hasattr(fig, "write_image"): # Plotly
526
- with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmpfile:
527
- fig.write_image(tmpfile.name, width=600, height=360, scale=2)
528
- with open(tmpfile.name, "rb") as f:
529
- story.append(Spacer(1, 8))
530
- story.append(Image(io.BytesIO(f.read()), width=6*inch, height=3.6*inch))
531
- story.append(Spacer(1, 12))
532
- os.unlink(tmpfile.name)
533
- except Exception as e:
534
- story.append(Paragraph(f"Plot rendering failed: {e}", normal_style))
520
+ else:
521
+ fig.write_image(buf, format="png", width=600, height=360, scale=2)
522
+ buf.seek(0)
523
+ story.append(Image(buf, width=6 * inch, height=4.5 * inch))
524
+ story.append(Spacer(1, 12))
535
525
 
536
- elif kind == "syntax":
537
- code, language = content
538
- from html import escape
539
- story.append(Paragraph(f"<b>Code ({language}):</b>", normal_style))
540
- story.append(Spacer(1, 4))
541
- code_html = escape(code).replace(" ", "&nbsp;").replace("\n", "<br/>")
542
- story.append(Paragraph(f"<font face='Courier'>{code_html}</font>", styles['CodeBlock']))
543
- story.append(Spacer(1, 12))
526
+ elif kind == "syntax":
527
+ code, language = content
528
+ from html import escape
529
+ story.append(Paragraph(f"<b>Code ({language}):</b>", normal_style))
530
+ story.append(Spacer(1, 4))
531
+ code_html = escape(code).replace(" ", "&nbsp;").replace("\n", "<br/>")
532
+ story.append(Paragraph(f"<font face='Courier'>{code_html}</font>", styles['CodeBlock']))
533
+ story.append(Spacer(1, 12))
544
534
 
545
- elif kind == "minipage":
546
- render_page(content, level=level + 1, sec_prefix=sec_prefix)
535
+ elif kind == "minipage":
536
+ render_page(content, level=level + 1, sec_prefix=sec_prefix)
537
+
538
+ except Exception as e:
539
+ story.append(Paragraph(f"Error rendering element: {e}", normal_style))
540
+
541
+
542
+ just_broke = False
543
+
544
+ for i, child in enumerate(page.children):
545
+ if i > 0 and not just_broke:
546
+ story.append(PageBreak())
547
+
548
+ before = len(story)
549
+ render_page(child, level=level + 1, sec_prefix=sec_prefix + [i + 1])
550
+ after = len(story)
551
+
552
+ # Determine if child added a PageBreak
553
+ just_broke = isinstance(story[-1], PageBreak) if after > before else False
554
+
555
+
556
+ # Determine if anything meaningful was added
557
+ def has_meaningful_content(start_idx):
558
+ for elem in story[start_idx:]:
559
+ if isinstance(elem, (Paragraph, Table, Image)):
560
+ return True
561
+ return False
562
+
563
+ if not page.children and has_meaningful_content(content_start):
564
+ story.append(PageBreak())
547
565
 
548
- # for child in getattr(page, "children", []):
549
- # story.append(PageBreak())
550
- # render_page(child, level=level + 2, sec_prefix=sec_prefix + [1])
551
566
 
552
- story.append(PageBreak())
553
567
 
554
568
  for page in self.pages:
555
569
  render_page(page)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: staticdash
3
- Version: 2025.22
3
+ Version: 2025.24
4
4
  Summary: A lightweight static HTML dashboard generator with Plotly and pandas support.
5
5
  Author-email: Brian Day <brian.day1@gmail.com>
6
6
  License: CC0-1.0
File without changes
File without changes