staticdash 2025.23__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.23
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.23"
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" }
@@ -467,33 +467,29 @@ class Dashboard:
467
467
  story.append(PageBreak())
468
468
 
469
469
  def render_page(page, level=0, sec_prefix=[]):
470
- heading_style = styles['Heading1'] if level == 0 else styles['Heading2']
470
+ heading_style = styles.get(f'Heading{min(level + 1, 4)}', styles['Heading4'])
471
471
 
472
- # Only add the page.title as a real heading if it's a top-level page
473
- # if level == 0:
474
- # story.append(Paragraph(page.title, heading_style))
475
- # story.append(Spacer(1, 12))
472
+ # Remember where we started
473
+ content_start = len(story)
476
474
 
477
- heading_style = styles['Heading1'] if level == 0 else styles['Heading2']
478
475
  story.append(Paragraph(page.title, heading_style))
479
476
  story.append(Spacer(1, 12))
480
477
 
481
-
482
478
  for kind, content, _ in page.elements:
483
- if kind == "text":
484
- story.append(Paragraph(content, normal_style))
485
- story.append(Spacer(1, 8))
486
-
487
- elif kind == "header":
488
- text, lvl = content
489
- safe_lvl = max(1, min(lvl + 1, 4)) # Clamp to Heading1–Heading4
490
- style = styles[f'Heading{safe_lvl}']
491
- story.append(Paragraph(text, style))
492
- story.append(Spacer(1, 8))
493
-
494
- elif kind == "table":
495
- df = content
496
- 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
497
493
  data = [df.columns.tolist()] + df.values.tolist()
498
494
  t = Table(data, repeatRows=1)
499
495
  t.setStyle(TableStyle([
@@ -515,48 +511,59 @@ class Dashboard:
515
511
  ]))
516
512
  story.append(t)
517
513
  story.append(Spacer(1, 12))
518
- except Exception:
519
- story.append(Paragraph("Table could not be rendered.", normal_style))
520
514
 
521
- elif kind == "plot":
522
- fig = content
523
- try:
524
- if hasattr(fig, "savefig"): # Matplotlib
525
- buf = io.BytesIO()
515
+ elif kind == "plot":
516
+ fig = content
517
+ buf = io.BytesIO()
518
+ if hasattr(fig, "savefig"):
526
519
  fig.savefig(buf, format="png", bbox_inches="tight", dpi=300)
527
- buf.seek(0)
528
- story.append(Spacer(1, 8))
529
- story.append(Image(buf, width=6*inch, height=4.5*inch))
530
- story.append(Spacer(1, 12))
531
- elif hasattr(fig, "write_image"): # Plotly
532
- with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmpfile:
533
- fig.write_image(tmpfile.name, width=600, height=360, scale=2)
534
- with open(tmpfile.name, "rb") as f:
535
- story.append(Spacer(1, 8))
536
- story.append(Image(io.BytesIO(f.read()), width=6*inch, height=3.6*inch))
537
- story.append(Spacer(1, 12))
538
- os.unlink(tmpfile.name)
539
- except Exception as e:
540
- 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))
541
525
 
542
- elif kind == "syntax":
543
- code, language = content
544
- from html import escape
545
- story.append(Paragraph(f"<b>Code ({language}):</b>", normal_style))
546
- story.append(Spacer(1, 4))
547
- code_html = escape(code).replace(" ", "&nbsp;").replace("\n", "<br/>")
548
- story.append(Paragraph(f"<font face='Courier'>{code_html}</font>", styles['CodeBlock']))
549
- 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))
550
534
 
551
- elif kind == "minipage":
552
- 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)
553
537
 
554
- for child in page.children:
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):
555
564
  story.append(PageBreak())
556
- render_page(child, level=level + 1, sec_prefix=sec_prefix + [1])
557
565
 
558
566
 
559
- story.append(PageBreak())
560
567
 
561
568
  for page in self.pages:
562
569
  render_page(page)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: staticdash
3
- Version: 2025.23
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