staticdash 0.1.0__tar.gz → 0.1.2__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,13 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: staticdash
3
- Version: 0.1.0
4
- Summary: A minimal static dashboard generator with Plotly support
3
+ Version: 0.1.2
4
+ Summary: A lightweight static HTML dashboard generator with Plotly and pandas support.
5
5
  Author-email: Brian Day <brian.day1@gmail.com>
6
- License-Expression: MIT
6
+ License: CC0-1.0
7
7
  Project-URL: Homepage, https://github.com/briday1/staticdash
8
8
  Project-URL: Repository, https://github.com/briday1/staticdash
9
9
  Requires-Python: >=3.8
10
10
  Description-Content-Type: text/markdown
11
+ Requires-Dist: plotly
12
+ Requires-Dist: pandas
13
+ Requires-Dist: dominate
11
14
 
12
15
  # staticdash
13
16
 
@@ -29,50 +32,50 @@ Create a Python script like this:
29
32
 
30
33
  ```python
31
34
  from staticdash.dashboard import Dashboard, Page
32
- import plotly.graph_objects as go
35
+ import plotly.express as px
33
36
  import pandas as pd
37
+ import numpy as np
34
38
 
35
- # Create the dashboard
36
- dashboard = Dashboard(title="StaticDash Demo")
39
+ # Create sample data
40
+ df = pd.DataFrame({
41
+ "Category": ["A", "B", "C", "D"],
42
+ "Value": [10, 20, 30, 40]
43
+ })
37
44
 
38
- # Page 1: Overview
39
- page1 = Page("overview", "Overview")
45
+ df2 = pd.DataFrame({
46
+ "Time": pd.date_range("2024-01-01", periods=10, freq="D"),
47
+ "Signal": np.random.randn(10).cumsum()
48
+ })
40
49
 
41
- # Add plo
42
- fig = go.Figure()
43
- fig.add_trace(go.Scatter(x=[1, 2, 3], y=[4, 1, 6], mode='lines+markers', name="Demo Line"))
44
- fig.update_layout(title="Sample Plot")
45
- page1.append(fig)
50
+ fig1 = px.bar(df, x="Category", y="Value", title="Bar Chart Example")
51
+ fig2 = px.line(df2, x="Time", y="Signal", title="Signal over Time")
46
52
 
47
- # Add table
48
- df1 = pd.DataFrame({
49
- "Category": ["A", "B", "C"],
50
- "Value": [100, 200, 150]
51
- })
52
- page1.append(df1)
53
+ # Build dashboard
54
+ dashboard = Dashboard(title="StaticDash Demo")
53
55
 
54
- # Add extra text
55
- page1.append("This page includes a sample plot, table, and descriptive text.")
56
+ # Page 1: Overview
57
+ page1 = Page("overview", "Overview")
58
+ page1.add("Welcome to the StaticDash demo. Below is a bar chart and a table.")
59
+ page1.add(fig1)
60
+ page1.add(df)
61
+
62
+ # Page 2: Timeseries
63
+ page2 = Page("timeseries", "Timeseries")
64
+ page2.add("Here is a random time series with cumulative noise.")
65
+ page2.add(fig2)
66
+ page2.add(df2)
67
+
68
+ # Page 3: Summary
69
+ page3 = Page("summary", "Summary")
70
+ page3.add("Summary and notes can be added here.")
71
+ page3.add("StaticDash is a lightweight static dashboard generator.")
72
+
73
+ # Register pages
56
74
  dashboard.add_page(page1)
57
-
58
- # Page 2: Data Table
59
- page2 = Page("data", "Data")
60
- df2 = pd.DataFrame({
61
- "Name": ["Alice", "Bob", "Charlie"],
62
- "Score": [85, 92, 78],
63
- "Passed": [True, True, False]
64
- })
65
- page2.append("This table shows individual scores and pass/fail status.")
66
- page2.append(df2)
67
75
  dashboard.add_page(page2)
68
-
69
- # Page 3: Notes
70
- page3 = Page("notes", "Notes")
71
- page3.append("These are concluding notes about the dataset.")
72
- page3.append("You can also add multiple text blocks like this.")
73
76
  dashboard.add_page(page3)
74
77
 
75
- # Publish the dashboard
78
+ # Export
76
79
  dashboard.publish(output_dir="output")
77
80
  ```
78
81
 
@@ -0,0 +1,68 @@
1
+ # staticdash
2
+
3
+ staticdash is a lightweight Python module for creating static, multi-page HTML dashboards. It supports Plotly plots, tables, and text content, with a fixed sidebar for navigation.
4
+
5
+ ## Installation
6
+
7
+ Clone the repository and install it in editable mode:
8
+
9
+ ```bash
10
+ git clone https://github.com/briday1/staticdash.git
11
+ cd staticdash
12
+ pip install .
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ Create a Python script like this:
18
+
19
+ ```python
20
+ from staticdash.dashboard import Dashboard, Page
21
+ import plotly.express as px
22
+ import pandas as pd
23
+ import numpy as np
24
+
25
+ # Create sample data
26
+ df = pd.DataFrame({
27
+ "Category": ["A", "B", "C", "D"],
28
+ "Value": [10, 20, 30, 40]
29
+ })
30
+
31
+ df2 = pd.DataFrame({
32
+ "Time": pd.date_range("2024-01-01", periods=10, freq="D"),
33
+ "Signal": np.random.randn(10).cumsum()
34
+ })
35
+
36
+ fig1 = px.bar(df, x="Category", y="Value", title="Bar Chart Example")
37
+ fig2 = px.line(df2, x="Time", y="Signal", title="Signal over Time")
38
+
39
+ # Build dashboard
40
+ dashboard = Dashboard(title="StaticDash Demo")
41
+
42
+ # Page 1: Overview
43
+ page1 = Page("overview", "Overview")
44
+ page1.add("Welcome to the StaticDash demo. Below is a bar chart and a table.")
45
+ page1.add(fig1)
46
+ page1.add(df)
47
+
48
+ # Page 2: Timeseries
49
+ page2 = Page("timeseries", "Timeseries")
50
+ page2.add("Here is a random time series with cumulative noise.")
51
+ page2.add(fig2)
52
+ page2.add(df2)
53
+
54
+ # Page 3: Summary
55
+ page3 = Page("summary", "Summary")
56
+ page3.add("Summary and notes can be added here.")
57
+ page3.add("StaticDash is a lightweight static dashboard generator.")
58
+
59
+ # Register pages
60
+ dashboard.add_page(page1)
61
+ dashboard.add_page(page2)
62
+ dashboard.add_page(page3)
63
+
64
+ # Export
65
+ dashboard.publish(output_dir="output")
66
+ ```
67
+
68
+ After running the script, open output/index.html in your browser.
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "staticdash"
7
+ version = "0.1.2"
8
+ description = "A lightweight static HTML dashboard generator with Plotly and pandas support."
9
+ authors = [
10
+ { name = "Brian Day", email = "brian.day1@gmail.com" }
11
+ ]
12
+ license = { text = "CC0-1.0" }
13
+ readme = "README.md"
14
+ requires-python = ">=3.8"
15
+ dependencies = [
16
+ "plotly",
17
+ "pandas",
18
+ "dominate"
19
+ ]
20
+
21
+ [tool.setuptools]
22
+ packages = ["staticdash"]
23
+
24
+ [tool.setuptools.package-data]
25
+ staticdash = ["assets/css/*.css", "assets/js/*.js"]
26
+
27
+ [project.urls]
28
+ Homepage = "https://github.com/briday1/staticdash"
29
+ Repository = "https://github.com/briday1/staticdash"
@@ -0,0 +1 @@
1
+ from .dashboard import Page, Dashboard
@@ -0,0 +1,100 @@
1
+ body {
2
+ margin: 0;
3
+ font-family: sans-serif;
4
+ background-color: #f9f9f9;
5
+ color: #333;
6
+ }
7
+
8
+ #sidebar {
9
+ position: fixed;
10
+ top: 0;
11
+ left: 0;
12
+ width: 240px;
13
+ height: 100vh;
14
+ background-color: #2c3e50;
15
+ padding: 20px;
16
+ box-sizing: border-box;
17
+ overflow-y: auto;
18
+ }
19
+
20
+ #sidebar h1 {
21
+ color: #ecf0f1;
22
+ font-size: 20px;
23
+ margin-bottom: 20px;
24
+ }
25
+
26
+ .nav-link {
27
+ display: block;
28
+ color: #bdc3c7;
29
+ text-decoration: none;
30
+ margin: 10px 0;
31
+ font-weight: bold;
32
+ transition: color 0.3s;
33
+ }
34
+
35
+ .nav-link.active,
36
+ .nav-link:hover {
37
+ color: #ffffff;
38
+ }
39
+
40
+ #content {
41
+ margin-left: 260px;
42
+ padding: 20px;
43
+ box-sizing: border-box;
44
+ }
45
+
46
+ .page-section {
47
+ display: none;
48
+ }
49
+
50
+ .page-section.active {
51
+ display: block;
52
+ }
53
+
54
+ .plot-container {
55
+ margin: 20px 0;
56
+ }
57
+
58
+ table {
59
+ width: 100%;
60
+ border-collapse: collapse;
61
+ margin-top: 1em;
62
+ background-color: white;
63
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
64
+ }
65
+
66
+ thead {
67
+ background-color: #2c3e50;
68
+ color: white;
69
+ }
70
+
71
+ th,
72
+ td {
73
+ padding: 10px;
74
+ border: 1px solid #ddd;
75
+ text-align: left;
76
+ }
77
+
78
+ tr:nth-child(even) {
79
+ background-color: #f2f2f2;
80
+ }
81
+
82
+ tr:hover {
83
+ background-color: #e8f0fe;
84
+ }
85
+
86
+ .dash-image {
87
+ max-width: 100%;
88
+ height: auto;
89
+ margin: 1em 0;
90
+ }
91
+
92
+
93
+ .plot-container {
94
+ width: 100%;
95
+ }
96
+
97
+ .plot-container .plotly-graph-div {
98
+ width: 100% !important;
99
+ height: auto !important;
100
+ }
@@ -0,0 +1,43 @@
1
+ document.addEventListener("DOMContentLoaded", () => {
2
+ const links = document.querySelectorAll(".nav-link");
3
+ const sections = document.querySelectorAll(".page-section");
4
+
5
+ function resizePlotsIn(section) {
6
+ const plots = section.querySelectorAll(".plotly-graph-div");
7
+ plots.forEach(plot => {
8
+ if (typeof Plotly !== "undefined" && plot.data) {
9
+ Plotly.Plots.resize(plot);
10
+ }
11
+ });
12
+ }
13
+
14
+ function showPage(id) {
15
+ sections.forEach(section => section.style.display = "none");
16
+ const page = document.getElementById(id);
17
+ if (page) {
18
+ page.style.display = "block";
19
+
20
+ // Resize Plotly charts within the newly visible section
21
+ requestAnimationFrame(() => {
22
+ resizePlotsIn(page);
23
+ });
24
+ }
25
+
26
+ links.forEach(link => link.classList.remove("active"));
27
+ const activeLink = Array.from(links).find(link => link.dataset.target === id);
28
+ if (activeLink) activeLink.classList.add("active");
29
+ }
30
+
31
+ links.forEach(link => {
32
+ link.addEventListener("click", e => {
33
+ e.preventDefault();
34
+ const targetId = link.dataset.target;
35
+ showPage(targetId);
36
+ });
37
+ });
38
+
39
+ // Initial page load
40
+ if (sections.length > 0) {
41
+ showPage(sections[0].id);
42
+ }
43
+ });
@@ -0,0 +1,119 @@
1
+ import os
2
+ import shutil
3
+ import uuid
4
+ import pandas as pd
5
+ import plotly.graph_objects as go
6
+ import plotly.express as px
7
+ from dominate import document
8
+ from dominate.tags import div, h1, h2, p, a, script, link, table, thead, tr, th, tbody, td, span
9
+ from dominate.util import raw as raw_util # To avoid ambiguity
10
+
11
+ class Page:
12
+ def __init__(self, slug, title):
13
+ self.slug = slug
14
+ self.title = title
15
+ self.elements = []
16
+
17
+ def add_text(self, text):
18
+ self.elements.append(("text", text))
19
+
20
+ def add_plot(self, plot):
21
+ html = raw_util(plot.to_html(full_html=False, include_plotlyjs='cdn', config={'responsive': True}))
22
+ self.elements.append(("plot", html))
23
+
24
+ def add_table(self, df, table_id=None):
25
+ if table_id is None:
26
+ table_id = f"table-{len(self.elements)}"
27
+ html = df.to_html(classes="table-hover table-striped", index=False, border=0, table_id=table_id)
28
+ self.elements.append(("table", (html, table_id)))
29
+
30
+ def add(self, element):
31
+ if isinstance(element, str):
32
+ self.add_text(element)
33
+ elif isinstance(element, go.Figure):
34
+ self.add_plot(element)
35
+ elif isinstance(element, pd.DataFrame):
36
+ self.add_table(element)
37
+ else:
38
+ raise ValueError(f"Unsupported element type: {type(element)}")
39
+
40
+ def render(self, index):
41
+ section = div(id=f"page-{index}", cls="page-section")
42
+ section += h1(self.title)
43
+ for kind, content in self.elements:
44
+ if kind == "text":
45
+ section += p(content)
46
+ elif kind == "plot":
47
+ section += div(content, cls="plot-container")
48
+ elif kind == "table":
49
+ table_html, _ = content
50
+ section += raw_util(table_html)
51
+ return section
52
+
53
+ class Dashboard:
54
+ def __init__(self, title="Dashboard"):
55
+ self.title = title
56
+ self.pages = []
57
+
58
+ def add_page(self, page: Page):
59
+ self.pages.append(page)
60
+
61
+ def publish(self, output_dir="output"):
62
+ os.makedirs(output_dir, exist_ok=True)
63
+ pages_dir = os.path.join(output_dir, "pages")
64
+ os.makedirs(pages_dir, exist_ok=True)
65
+
66
+ # Copy assets
67
+ assets_src = os.path.join(os.path.dirname(__file__), "assets")
68
+ assets_dst = os.path.join(output_dir, "assets")
69
+ shutil.copytree(assets_src, assets_dst, dirs_exist_ok=True)
70
+
71
+ # Generate each page
72
+ for page in self.pages:
73
+ doc = document(title=page.title)
74
+ with doc.head:
75
+ doc.head.add(link(rel="stylesheet", href="../assets/css/style.css"))
76
+ doc.head.add(script(type="text/javascript", src="../assets/js/script.js"))
77
+
78
+ with doc:
79
+ with div(cls="page-section", id=f"page-{page.slug}"):
80
+ h1(page.title)
81
+ for kind, content in page.elements:
82
+ if kind == "text":
83
+ p(content)
84
+ elif kind == "plot":
85
+ div(content, cls="plot-container")
86
+ elif kind == "table":
87
+ table_html, _ = content
88
+ doc.add(raw_util(table_html))
89
+
90
+ with open(os.path.join(pages_dir, f"{page.slug}.html"), "w") as f:
91
+ f.write(str(doc))
92
+
93
+ # Generate index.html with navigation
94
+ index_doc = document(title=self.title)
95
+ with index_doc.head:
96
+ index_doc.head.add(link(rel="stylesheet", href="assets/css/style.css"))
97
+ index_doc.head.add(script(type="text/javascript", src="assets/js/script.js"))
98
+
99
+ with index_doc:
100
+ with div(id="sidebar"):
101
+ h1(self.title)
102
+ for page in self.pages:
103
+ a(page.title, cls="nav-link", href="#", **{"data-target": f"page-{page.slug}"})
104
+ with div(id="content"):
105
+ for page in self.pages:
106
+ with div(id=f"page-{page.slug}", cls="page-section", style="display:none;"):
107
+ h2(page.title)
108
+ for kind, content in page.elements:
109
+ if kind == "text":
110
+ p(content)
111
+ elif kind == "plot":
112
+ div(content, cls="plot-container")
113
+ elif kind == "table":
114
+ table_html, _ = content
115
+ div(raw_util(table_html))
116
+
117
+
118
+ with open(os.path.join(output_dir, "index.html"), "w") as f:
119
+ f.write(str(index_doc))
@@ -1,13 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: staticdash
3
- Version: 0.1.0
4
- Summary: A minimal static dashboard generator with Plotly support
3
+ Version: 0.1.2
4
+ Summary: A lightweight static HTML dashboard generator with Plotly and pandas support.
5
5
  Author-email: Brian Day <brian.day1@gmail.com>
6
- License-Expression: MIT
6
+ License: CC0-1.0
7
7
  Project-URL: Homepage, https://github.com/briday1/staticdash
8
8
  Project-URL: Repository, https://github.com/briday1/staticdash
9
9
  Requires-Python: >=3.8
10
10
  Description-Content-Type: text/markdown
11
+ Requires-Dist: plotly
12
+ Requires-Dist: pandas
13
+ Requires-Dist: dominate
11
14
 
12
15
  # staticdash
13
16
 
@@ -29,50 +32,50 @@ Create a Python script like this:
29
32
 
30
33
  ```python
31
34
  from staticdash.dashboard import Dashboard, Page
32
- import plotly.graph_objects as go
35
+ import plotly.express as px
33
36
  import pandas as pd
37
+ import numpy as np
34
38
 
35
- # Create the dashboard
36
- dashboard = Dashboard(title="StaticDash Demo")
39
+ # Create sample data
40
+ df = pd.DataFrame({
41
+ "Category": ["A", "B", "C", "D"],
42
+ "Value": [10, 20, 30, 40]
43
+ })
37
44
 
38
- # Page 1: Overview
39
- page1 = Page("overview", "Overview")
45
+ df2 = pd.DataFrame({
46
+ "Time": pd.date_range("2024-01-01", periods=10, freq="D"),
47
+ "Signal": np.random.randn(10).cumsum()
48
+ })
40
49
 
41
- # Add plo
42
- fig = go.Figure()
43
- fig.add_trace(go.Scatter(x=[1, 2, 3], y=[4, 1, 6], mode='lines+markers', name="Demo Line"))
44
- fig.update_layout(title="Sample Plot")
45
- page1.append(fig)
50
+ fig1 = px.bar(df, x="Category", y="Value", title="Bar Chart Example")
51
+ fig2 = px.line(df2, x="Time", y="Signal", title="Signal over Time")
46
52
 
47
- # Add table
48
- df1 = pd.DataFrame({
49
- "Category": ["A", "B", "C"],
50
- "Value": [100, 200, 150]
51
- })
52
- page1.append(df1)
53
+ # Build dashboard
54
+ dashboard = Dashboard(title="StaticDash Demo")
53
55
 
54
- # Add extra text
55
- page1.append("This page includes a sample plot, table, and descriptive text.")
56
+ # Page 1: Overview
57
+ page1 = Page("overview", "Overview")
58
+ page1.add("Welcome to the StaticDash demo. Below is a bar chart and a table.")
59
+ page1.add(fig1)
60
+ page1.add(df)
61
+
62
+ # Page 2: Timeseries
63
+ page2 = Page("timeseries", "Timeseries")
64
+ page2.add("Here is a random time series with cumulative noise.")
65
+ page2.add(fig2)
66
+ page2.add(df2)
67
+
68
+ # Page 3: Summary
69
+ page3 = Page("summary", "Summary")
70
+ page3.add("Summary and notes can be added here.")
71
+ page3.add("StaticDash is a lightweight static dashboard generator.")
72
+
73
+ # Register pages
56
74
  dashboard.add_page(page1)
57
-
58
- # Page 2: Data Table
59
- page2 = Page("data", "Data")
60
- df2 = pd.DataFrame({
61
- "Name": ["Alice", "Bob", "Charlie"],
62
- "Score": [85, 92, 78],
63
- "Passed": [True, True, False]
64
- })
65
- page2.append("This table shows individual scores and pass/fail status.")
66
- page2.append(df2)
67
75
  dashboard.add_page(page2)
68
-
69
- # Page 3: Notes
70
- page3 = Page("notes", "Notes")
71
- page3.append("These are concluding notes about the dataset.")
72
- page3.append("You can also add multiple text blocks like this.")
73
76
  dashboard.add_page(page3)
74
77
 
75
- # Publish the dashboard
78
+ # Export
76
79
  dashboard.publish(output_dir="output")
77
80
  ```
78
81
 
@@ -5,4 +5,7 @@ staticdash/dashboard.py
5
5
  staticdash.egg-info/PKG-INFO
6
6
  staticdash.egg-info/SOURCES.txt
7
7
  staticdash.egg-info/dependency_links.txt
8
- staticdash.egg-info/top_level.txt
8
+ staticdash.egg-info/requires.txt
9
+ staticdash.egg-info/top_level.txt
10
+ staticdash/assets/css/style.css
11
+ staticdash/assets/js/script.js
@@ -0,0 +1,3 @@
1
+ plotly
2
+ pandas
3
+ dominate
@@ -1,68 +0,0 @@
1
- # staticdash
2
-
3
- staticdash is a lightweight Python module for creating static, multi-page HTML dashboards. It supports Plotly plots, tables, and text content, with a fixed sidebar for navigation.
4
-
5
- ## Installation
6
-
7
- Clone the repository and install it in editable mode:
8
-
9
- ```bash
10
- git clone https://github.com/briday1/staticdash.git
11
- cd staticdash
12
- pip install .
13
- ```
14
-
15
- ## Usage
16
-
17
- Create a Python script like this:
18
-
19
- ```python
20
- from staticdash.dashboard import Dashboard, Page
21
- import plotly.graph_objects as go
22
- import pandas as pd
23
-
24
- # Create the dashboard
25
- dashboard = Dashboard(title="StaticDash Demo")
26
-
27
- # Page 1: Overview
28
- page1 = Page("overview", "Overview")
29
-
30
- # Add plo
31
- fig = go.Figure()
32
- fig.add_trace(go.Scatter(x=[1, 2, 3], y=[4, 1, 6], mode='lines+markers', name="Demo Line"))
33
- fig.update_layout(title="Sample Plot")
34
- page1.append(fig)
35
-
36
- # Add table
37
- df1 = pd.DataFrame({
38
- "Category": ["A", "B", "C"],
39
- "Value": [100, 200, 150]
40
- })
41
- page1.append(df1)
42
-
43
- # Add extra text
44
- page1.append("This page includes a sample plot, table, and descriptive text.")
45
- dashboard.add_page(page1)
46
-
47
- # Page 2: Data Table
48
- page2 = Page("data", "Data")
49
- df2 = pd.DataFrame({
50
- "Name": ["Alice", "Bob", "Charlie"],
51
- "Score": [85, 92, 78],
52
- "Passed": [True, True, False]
53
- })
54
- page2.append("This table shows individual scores and pass/fail status.")
55
- page2.append(df2)
56
- dashboard.add_page(page2)
57
-
58
- # Page 3: Notes
59
- page3 = Page("notes", "Notes")
60
- page3.append("These are concluding notes about the dataset.")
61
- page3.append("You can also add multiple text blocks like this.")
62
- dashboard.add_page(page3)
63
-
64
- # Publish the dashboard
65
- dashboard.publish(output_dir="output")
66
- ```
67
-
68
- After running the script, open output/index.html in your browser.
@@ -1,22 +0,0 @@
1
- [project]
2
- name = "staticdash"
3
- version = "0.1.0"
4
- description = "A minimal static dashboard generator with Plotly support"
5
- authors = [
6
- { name = "Brian Day", email = "brian.day1@gmail.com" }
7
- ]
8
- license = "MIT"
9
- readme = "README.md"
10
- requires-python = ">=3.8"
11
-
12
- [project.urls]
13
- Homepage = "https://github.com/briday1/staticdash"
14
- Repository = "https://github.com/briday1/staticdash"
15
-
16
- [build-system]
17
- requires = ["setuptools>=61.0"]
18
- build-backend = "setuptools.build_meta"
19
-
20
- [tool.setuptools.packages.find]
21
- include = ["staticdash*"]
22
- exclude = ["output*"]
@@ -1,2 +0,0 @@
1
- from .dashboard import Page, Dashboard
2
- import simpledash.assets.css
@@ -1,88 +0,0 @@
1
- import os
2
- import shutil
3
- import dominate
4
- from dominate.tags import div, h1, h2, p, a, script, link, table, thead, tr, th, tbody, td
5
- from dominate.util import raw # ✅ correct usage
6
-
7
- import plotly.graph_objs as go
8
- import pandas as pd
9
-
10
-
11
- class Page:
12
- def __init__(self, slug, title):
13
- self.slug = slug
14
- self.title = title
15
- self.elements = []
16
-
17
- def append(self, element):
18
- if isinstance(element, str):
19
- self.elements.append(p(element))
20
- elif isinstance(element, go.Figure):
21
- html = element.to_html(include_plotlyjs=False, full_html=False)
22
- self.elements.append(raw(html))
23
- elif isinstance(element, pd.DataFrame):
24
- tbl = table()
25
- tbl.add(thead(tr(*[th(col) for col in element.columns])))
26
- tb = tbody()
27
- for _, row in element.iterrows():
28
- tb.add(tr(*[td(str(val)) for val in row]))
29
- tbl.add(tb)
30
- self.elements.append(tbl)
31
- else:
32
- self.elements.append(element)
33
-
34
-
35
- class Dashboard:
36
- def __init__(self, title="Dashboard"):
37
- self.title = title
38
- self.pages = []
39
-
40
- def add_page(self, page):
41
- self.pages.append(page)
42
-
43
- def publish(self, output_dir="output"):
44
- os.makedirs(output_dir, exist_ok=True)
45
- self._write_assets(output_dir)
46
- self._write_index(output_dir)
47
-
48
- def _write_assets(self, output_dir):
49
- css_src = os.path.join(os.path.dirname(__file__), "assets", "css", "style.css")
50
- css_dst_dir = os.path.join(output_dir, "assets", "css")
51
- os.makedirs(css_dst_dir, exist_ok=True)
52
- shutil.copyfile(css_src, os.path.join(css_dst_dir, "style.css"))
53
-
54
- def _write_index(self, output_dir):
55
- doc = dominate.document(title=self.title)
56
-
57
- with doc.head:
58
- link(rel="stylesheet", href="assets/css/style.css")
59
- script(src="https://cdn.plot.ly/plotly-latest.min.js")
60
-
61
- with doc:
62
- with div(id="sidebar"):
63
- h1(self.title)
64
- for i, page in enumerate(self.pages):
65
- a(page.title, href="#", cls="nav-link", onclick=f"showPage('page-{i}')")
66
-
67
- with div(id="content"):
68
- for i, page in enumerate(self.pages):
69
- section = div(id=f"page-{i}", cls="page-section")
70
- section.add(h2(page.title))
71
- for elem in page.elements:
72
- section.add(elem)
73
-
74
- # JavaScript block
75
- js_code = """
76
- function showPage(id) {
77
- document.querySelectorAll('.page-section').forEach(el => el.style.display = 'none');
78
- document.getElementById(id).style.display = 'block';
79
- document.querySelectorAll('.nav-link').forEach(el => el.classList.remove('active'));
80
- event.target.classList.add('active');
81
- }
82
- window.onload = () => showPage('page-0');
83
- """
84
- with doc:
85
- script(raw(js_code))
86
-
87
- with open(os.path.join(output_dir, "index.html"), "w") as f:
88
- f.write(doc.render())
File without changes