staticdash 2025.33__tar.gz → 2025.35__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.
- {staticdash-2025.33 → staticdash-2025.35}/PKG-INFO +8 -1
- {staticdash-2025.33 → staticdash-2025.35}/README.md +7 -0
- {staticdash-2025.33 → staticdash-2025.35}/pyproject.toml +1 -1
- {staticdash-2025.33 → staticdash-2025.35}/staticdash/__init__.py +2 -2
- {staticdash-2025.33 → staticdash-2025.35}/staticdash/dashboard.py +222 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash.egg-info/PKG-INFO +8 -1
- {staticdash-2025.33 → staticdash-2025.35}/setup.cfg +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/setup.py +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/css/style.css +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/js/script.js +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/vendor/mathjax/tex-mml-chtml.js +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/vendor/plotly/plotly.min.js +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/vendor/prism/components/prism-bash.min.js +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/vendor/prism/components/prism-c.min.js +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/vendor/prism/components/prism-javascript.min.js +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/vendor/prism/components/prism-json.min.js +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/vendor/prism/components/prism-markup.min.js +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/vendor/prism/components/prism-python.min.js +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/vendor/prism/components/prism-sql.min.js +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/vendor/prism/prism-tomorrow.min.css +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/vendor/prism/prism.min.js +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash.egg-info/SOURCES.txt +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash.egg-info/dependency_links.txt +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash.egg-info/requires.txt +0 -0
- {staticdash-2025.33 → staticdash-2025.35}/staticdash.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: staticdash
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.35
|
|
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
|
|
@@ -57,6 +57,13 @@ pip install staticdash
|
|
|
57
57
|
|
|
58
58
|
[View the latest demo dashboard](https://staticdash.github.io/staticdash/)
|
|
59
59
|
|
|
60
|
+
## Examples
|
|
61
|
+
|
|
62
|
+
This repository includes two example dashboards that demonstrate staticdash capabilities:
|
|
63
|
+
|
|
64
|
+
- **Tutorial Dashboard:** [View tutorial_output/index.html](https://staticdash.github.io/staticdash/tutorial_output/index.html) - A comprehensive tutorial showing all staticdash features
|
|
65
|
+
- **Directory Example:** [View directory_out/index.html](https://staticdash.github.io/staticdash/directory_out/index.html) - Demonstrates the Directory class for aggregating multiple dashboards
|
|
66
|
+
|
|
60
67
|
---
|
|
61
68
|
|
|
62
69
|
For a full example, see [`demo.py`](./demo.py) in this repository.
|
|
@@ -40,6 +40,13 @@ pip install staticdash
|
|
|
40
40
|
|
|
41
41
|
[View the latest demo dashboard](https://staticdash.github.io/staticdash/)
|
|
42
42
|
|
|
43
|
+
## Examples
|
|
44
|
+
|
|
45
|
+
This repository includes two example dashboards that demonstrate staticdash capabilities:
|
|
46
|
+
|
|
47
|
+
- **Tutorial Dashboard:** [View tutorial_output/index.html](https://staticdash.github.io/staticdash/tutorial_output/index.html) - A comprehensive tutorial showing all staticdash features
|
|
48
|
+
- **Directory Example:** [View directory_out/index.html](https://staticdash.github.io/staticdash/directory_out/index.html) - Demonstrates the Directory class for aggregating multiple dashboards
|
|
49
|
+
|
|
43
50
|
---
|
|
44
51
|
|
|
45
52
|
For a full example, see [`demo.py`](./demo.py) in this repository.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "staticdash"
|
|
7
|
-
version = "2025.
|
|
7
|
+
version = "2025.35"
|
|
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" }
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Import everything you want to expose at the package level
|
|
2
|
-
from .dashboard import Dashboard, MiniPage, Page
|
|
2
|
+
from .dashboard import Dashboard, MiniPage, Page, Directory
|
|
3
3
|
|
|
4
4
|
# Optionally, define __all__ to control what gets imported with `from staticdash import *`
|
|
5
|
-
__all__ = ["Dashboard", "MiniPage", "Page"]
|
|
5
|
+
__all__ = ["Dashboard", "MiniPage", "Page", "Directory"]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import shutil
|
|
3
3
|
import uuid
|
|
4
|
+
import re
|
|
4
5
|
import pandas as pd
|
|
5
6
|
import plotly.graph_objects as go
|
|
6
7
|
from dominate import document
|
|
@@ -401,3 +402,224 @@ class Dashboard:
|
|
|
401
402
|
|
|
402
403
|
with open(os.path.join(output_dir, "index.html"), "w", encoding="utf-8") as f:
|
|
403
404
|
f.write(str(index_doc))
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
class Directory:
|
|
408
|
+
"""
|
|
409
|
+
A Directory aggregates multiple Dashboard instances and publishes them
|
|
410
|
+
as a landing page listing multiple dashboards. Each dashboard is published
|
|
411
|
+
into its own subfolder under the output directory.
|
|
412
|
+
"""
|
|
413
|
+
|
|
414
|
+
def __init__(self, title="Dashboard Directory", page_width=900):
|
|
415
|
+
"""
|
|
416
|
+
Initialize a Directory.
|
|
417
|
+
|
|
418
|
+
Args:
|
|
419
|
+
title (str): The title of the directory landing page
|
|
420
|
+
page_width (int): The default page width for the landing page
|
|
421
|
+
"""
|
|
422
|
+
self.title = title
|
|
423
|
+
self.page_width = page_width
|
|
424
|
+
self.dashboards = [] # List of (slug, dashboard) tuples
|
|
425
|
+
|
|
426
|
+
def add_dashboard(self, dashboard, slug=None):
|
|
427
|
+
"""
|
|
428
|
+
Add a Dashboard instance to the directory.
|
|
429
|
+
|
|
430
|
+
Args:
|
|
431
|
+
dashboard (Dashboard): The Dashboard instance to add
|
|
432
|
+
slug (str, optional): URL-friendly identifier for the dashboard.
|
|
433
|
+
If None, derived from dashboard title.
|
|
434
|
+
"""
|
|
435
|
+
if slug is None:
|
|
436
|
+
# Generate slug from dashboard title
|
|
437
|
+
slug = dashboard.title.lower().replace(" ", "-")
|
|
438
|
+
# Remove special characters
|
|
439
|
+
slug = "".join(c for c in slug if c.isalnum() or c == "-")
|
|
440
|
+
# Clean up multiple consecutive hyphens
|
|
441
|
+
slug = re.sub(r'-+', '-', slug)
|
|
442
|
+
# Remove leading/trailing hyphens
|
|
443
|
+
slug = slug.strip("-")
|
|
444
|
+
|
|
445
|
+
self.dashboards.append((slug, dashboard))
|
|
446
|
+
|
|
447
|
+
def publish(self, output_dir="output"):
|
|
448
|
+
"""
|
|
449
|
+
Publish the directory landing page and all dashboards.
|
|
450
|
+
|
|
451
|
+
Creates a landing page (index.html) that links to each dashboard,
|
|
452
|
+
and publishes each dashboard into its own subfolder.
|
|
453
|
+
|
|
454
|
+
Args:
|
|
455
|
+
output_dir (str): The output directory path
|
|
456
|
+
"""
|
|
457
|
+
output_dir = os.path.abspath(output_dir)
|
|
458
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
459
|
+
|
|
460
|
+
# Copy assets to the root output directory
|
|
461
|
+
assets_src = os.path.join(os.path.dirname(__file__), "assets")
|
|
462
|
+
assets_dst = os.path.join(output_dir, "assets")
|
|
463
|
+
shutil.copytree(assets_src, assets_dst, dirs_exist_ok=True)
|
|
464
|
+
|
|
465
|
+
# Publish each dashboard to its own subfolder
|
|
466
|
+
for slug, dashboard in self.dashboards:
|
|
467
|
+
dashboard_dir = os.path.join(output_dir, slug)
|
|
468
|
+
dashboard.publish(output_dir=dashboard_dir)
|
|
469
|
+
|
|
470
|
+
# Add a "Back to Directory" link to each dashboard's index page
|
|
471
|
+
self._add_back_link(dashboard_dir, slug)
|
|
472
|
+
|
|
473
|
+
# Create the landing page
|
|
474
|
+
self._create_landing_page(output_dir)
|
|
475
|
+
|
|
476
|
+
def _add_back_link(self, dashboard_dir, slug):
|
|
477
|
+
"""
|
|
478
|
+
Add a navigation link back to the directory landing page in the dashboard.
|
|
479
|
+
|
|
480
|
+
Args:
|
|
481
|
+
dashboard_dir (str): Path to the dashboard output directory
|
|
482
|
+
slug (str): The slug of the dashboard
|
|
483
|
+
"""
|
|
484
|
+
index_path = os.path.join(dashboard_dir, "index.html")
|
|
485
|
+
if not os.path.exists(index_path):
|
|
486
|
+
return
|
|
487
|
+
|
|
488
|
+
# Read the existing index.html
|
|
489
|
+
with open(index_path, "r", encoding="utf-8") as f:
|
|
490
|
+
content = f.read()
|
|
491
|
+
|
|
492
|
+
# Add a back link in the sidebar footer
|
|
493
|
+
# Replace the sidebar-footer section with one that includes a back link
|
|
494
|
+
back_link = '<div id="sidebar-footer"><a href="../index.html">← Back to Directory</a></div>'
|
|
495
|
+
|
|
496
|
+
# Find and replace the sidebar-footer
|
|
497
|
+
pattern = r'<div id="sidebar-footer">.*?</div>'
|
|
498
|
+
content = re.sub(pattern, back_link, content, flags=re.DOTALL)
|
|
499
|
+
|
|
500
|
+
# Write back the modified content
|
|
501
|
+
with open(index_path, "w", encoding="utf-8") as f:
|
|
502
|
+
f.write(content)
|
|
503
|
+
|
|
504
|
+
# Also update all page HTML files to have the back link
|
|
505
|
+
pages_dir = os.path.join(dashboard_dir, "pages")
|
|
506
|
+
if os.path.exists(pages_dir):
|
|
507
|
+
for page_file in os.listdir(pages_dir):
|
|
508
|
+
if page_file.endswith(".html"):
|
|
509
|
+
page_path = os.path.join(pages_dir, page_file)
|
|
510
|
+
with open(page_path, "r", encoding="utf-8") as f:
|
|
511
|
+
page_content = f.read()
|
|
512
|
+
|
|
513
|
+
# For pages, the back link needs to go up two levels
|
|
514
|
+
back_link_pages = '<div id="sidebar-footer"><a href="../../index.html">← Back to Directory</a></div>'
|
|
515
|
+
page_content = re.sub(pattern, back_link_pages, page_content, flags=re.DOTALL)
|
|
516
|
+
|
|
517
|
+
with open(page_path, "w", encoding="utf-8") as f:
|
|
518
|
+
f.write(page_content)
|
|
519
|
+
|
|
520
|
+
def _create_landing_page(self, output_dir):
|
|
521
|
+
"""
|
|
522
|
+
Create the landing page HTML that lists all dashboards.
|
|
523
|
+
|
|
524
|
+
Args:
|
|
525
|
+
output_dir (str): Path to the output directory
|
|
526
|
+
"""
|
|
527
|
+
doc = document(title=self.title)
|
|
528
|
+
|
|
529
|
+
# Add CSS and basic styling
|
|
530
|
+
with doc.head:
|
|
531
|
+
link(rel="stylesheet", href="assets/css/style.css")
|
|
532
|
+
raw_util("""
|
|
533
|
+
<style>
|
|
534
|
+
body {
|
|
535
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
536
|
+
margin: 0;
|
|
537
|
+
padding: 0;
|
|
538
|
+
background-color: #f5f5f5;
|
|
539
|
+
}
|
|
540
|
+
.directory-container {
|
|
541
|
+
max-width: """ + str(self.page_width) + """px;
|
|
542
|
+
margin: 0 auto;
|
|
543
|
+
padding: 40px 20px;
|
|
544
|
+
}
|
|
545
|
+
.directory-header {
|
|
546
|
+
text-align: center;
|
|
547
|
+
margin-bottom: 50px;
|
|
548
|
+
}
|
|
549
|
+
.directory-header h1 {
|
|
550
|
+
font-size: 2.5em;
|
|
551
|
+
margin-bottom: 10px;
|
|
552
|
+
color: #333;
|
|
553
|
+
}
|
|
554
|
+
.directory-header p {
|
|
555
|
+
font-size: 1.2em;
|
|
556
|
+
color: #666;
|
|
557
|
+
}
|
|
558
|
+
.dashboard-grid {
|
|
559
|
+
display: grid;
|
|
560
|
+
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
561
|
+
gap: 30px;
|
|
562
|
+
margin-top: 30px;
|
|
563
|
+
}
|
|
564
|
+
.dashboard-card {
|
|
565
|
+
background: white;
|
|
566
|
+
border-radius: 8px;
|
|
567
|
+
padding: 30px;
|
|
568
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
569
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
570
|
+
text-decoration: none;
|
|
571
|
+
color: inherit;
|
|
572
|
+
display: block;
|
|
573
|
+
}
|
|
574
|
+
.dashboard-card:hover {
|
|
575
|
+
transform: translateY(-4px);
|
|
576
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
|
577
|
+
}
|
|
578
|
+
.dashboard-card h2 {
|
|
579
|
+
margin: 0 0 10px 0;
|
|
580
|
+
font-size: 1.5em;
|
|
581
|
+
color: #2c3e50;
|
|
582
|
+
}
|
|
583
|
+
.dashboard-card p {
|
|
584
|
+
margin: 0;
|
|
585
|
+
color: #7f8c8d;
|
|
586
|
+
font-size: 0.95em;
|
|
587
|
+
}
|
|
588
|
+
.dashboard-arrow {
|
|
589
|
+
display: inline-block;
|
|
590
|
+
margin-left: 5px;
|
|
591
|
+
transition: transform 0.2s;
|
|
592
|
+
}
|
|
593
|
+
.dashboard-card:hover .dashboard-arrow {
|
|
594
|
+
transform: translateX(5px);
|
|
595
|
+
}
|
|
596
|
+
.footer {
|
|
597
|
+
text-align: center;
|
|
598
|
+
margin-top: 60px;
|
|
599
|
+
padding: 20px;
|
|
600
|
+
color: #999;
|
|
601
|
+
font-size: 0.9em;
|
|
602
|
+
}
|
|
603
|
+
</style>
|
|
604
|
+
""")
|
|
605
|
+
|
|
606
|
+
with doc:
|
|
607
|
+
with div(cls="directory-container"):
|
|
608
|
+
with div(cls="directory-header"):
|
|
609
|
+
h1(self.title)
|
|
610
|
+
p(f"Explore {len(self.dashboards)} dashboard{'s' if len(self.dashboards) != 1 else ''}")
|
|
611
|
+
|
|
612
|
+
with div(cls="dashboard-grid"):
|
|
613
|
+
for slug, dashboard in self.dashboards:
|
|
614
|
+
with a(href=f"{slug}/index.html", cls="dashboard-card"):
|
|
615
|
+
h2(dashboard.title)
|
|
616
|
+
num_pages = len(dashboard.pages)
|
|
617
|
+
p(f"{num_pages} page{'s' if num_pages != 1 else ''} ")
|
|
618
|
+
span("→", cls="dashboard-arrow")
|
|
619
|
+
|
|
620
|
+
with div(cls="footer"):
|
|
621
|
+
p("Produced by staticdash")
|
|
622
|
+
|
|
623
|
+
# Write the landing page
|
|
624
|
+
with open(os.path.join(output_dir, "index.html"), "w", encoding="utf-8") as f:
|
|
625
|
+
f.write(str(doc))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: staticdash
|
|
3
|
-
Version: 2025.
|
|
3
|
+
Version: 2025.35
|
|
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
|
|
@@ -57,6 +57,13 @@ pip install staticdash
|
|
|
57
57
|
|
|
58
58
|
[View the latest demo dashboard](https://staticdash.github.io/staticdash/)
|
|
59
59
|
|
|
60
|
+
## Examples
|
|
61
|
+
|
|
62
|
+
This repository includes two example dashboards that demonstrate staticdash capabilities:
|
|
63
|
+
|
|
64
|
+
- **Tutorial Dashboard:** [View tutorial_output/index.html](https://staticdash.github.io/staticdash/tutorial_output/index.html) - A comprehensive tutorial showing all staticdash features
|
|
65
|
+
- **Directory Example:** [View directory_out/index.html](https://staticdash.github.io/staticdash/directory_out/index.html) - Demonstrates the Directory class for aggregating multiple dashboards
|
|
66
|
+
|
|
60
67
|
---
|
|
61
68
|
|
|
62
69
|
For a full example, see [`demo.py`](./demo.py) in this repository.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/vendor/prism/components/prism-c.min.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/vendor/prism/components/prism-sql.min.js
RENAMED
|
File without changes
|
{staticdash-2025.33 → staticdash-2025.35}/staticdash/assets/vendor/prism/prism-tomorrow.min.css
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|