diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml
index 7d98e6d..5da08aa 100644
--- a/.github/workflows/docs-deploy.yml
+++ b/.github/workflows/docs-deploy.yml
@@ -6,7 +6,6 @@ on:
- main
paths:
- "docs/**"
- - "mkdocs.yml"
- "pyproject.toml"
- "sst.config.ts"
- "package.json"
@@ -66,7 +65,7 @@ jobs:
run: |
set -euo pipefail
python -m pip install --upgrade pip
- python -m pip install mkdocs mkdocs-material mkdocs-jupyter
+ python -m pip install sphinx pydata-sphinx-theme myst-parser myst-nb sphinx-copybutton sphinx-design linkify-it-py
- name: Install deploy dependencies
run: |
diff --git a/.github/workflows/docs-doctest.yml b/.github/workflows/docs-doctest.yml
index cb5ec0c..c53b9c4 100644
--- a/.github/workflows/docs-doctest.yml
+++ b/.github/workflows/docs-doctest.yml
@@ -30,7 +30,7 @@ jobs:
run: |
set -euo pipefail
python -m pip install --upgrade pip
- python -m pip install mkdocs mkdocs-material mkdocs-jupyter pytest
+ python -m pip install sphinx pydata-sphinx-theme myst-parser myst-nb sphinx-copybutton sphinx-design linkify-it-py pytest
- name: Run docs build doctest
run: |
diff --git a/.gitignore b/.gitignore
index 7ff9750..efd4560 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,6 +28,8 @@ MANIFEST
# built docs
site/
+jupyter_execute/
+.jupyter_cache/
# Installer logs
pip-log.txt
diff --git a/README.md b/README.md
index 4d864f4..b8eca3c 100644
--- a/README.md
+++ b/README.md
@@ -100,7 +100,7 @@ dipole antennas, horn antennas, and planar microwave circuits.
## Building the docs
The documentation site is built with
-[MkDocs Material](https://squidfunk.github.io/mkdocs-material/).
+[PyData Sphinx Theme](https://pydata-sphinx-theme.readthedocs.io/en/stable/index.html).
A [justfile](https://github.com/casey/just) automates the full pipeline.
```bash
@@ -118,8 +118,8 @@ just doctest
# Or run each step individually:
just nbrun # execute docs example notebooks with papermill
-just nbdocs # no-op (MkDocs renders .ipynb directly)
-just docs # build the MkDocs static site
+just nbdocs # no-op (Sphinx renders .ipynb directly)
+just docs # build the Sphinx static site (strict mode)
# Serve locally for development
just serve # starts a dev server on http://localhost:8080
@@ -136,7 +136,7 @@ Router managed by the private website infrastructure.
```bash
npm install
-python -m pip install mkdocs mkdocs-material mkdocs-jupyter
+python -m pip install sphinx pydata-sphinx-theme myst-parser myst-nb sphinx-copybutton sphinx-design linkify-it-py
```
2. Set environment variables:
diff --git a/docs/PalaceToolkit.png b/docs/PalaceToolkit.png
index 85f3fc3..facc6a2 100644
Binary files a/docs/PalaceToolkit.png and b/docs/PalaceToolkit.png differ
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..b61beed
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,79 @@
+"""Sphinx configuration for PalaceToolkit documentation."""
+
+from __future__ import annotations
+
+project = "PalaceToolkit"
+author = "EpsilonForge"
+
+extensions = [
+ "myst_nb",
+ "sphinx.ext.mathjax",
+ "sphinx_copybutton",
+ "sphinx_design",
+]
+
+source_suffix = {
+ ".md": "myst-nb",
+ ".ipynb": "myst-nb",
+}
+
+root_doc = "index"
+exclude_patterns = [
+ "_build",
+ "Thumbs.db",
+ ".DS_Store",
+ "**/.ipynb_checkpoints",
+]
+
+# MyST and notebook behavior
+myst_enable_extensions = [
+ "colon_fence",
+ "deflist",
+ "dollarmath",
+ "html_admonition",
+ "html_image",
+ "linkify",
+ "replacements",
+ "substitution",
+ "tasklist",
+]
+
+nb_execution_mode = "off"
+nb_render_markdown_format = "myst"
+suppress_warnings = ["myst.header"]
+
+html_theme = "pydata_sphinx_theme"
+html_title = "PalaceToolkit"
+html_logo = "PalaceToolkit.png"
+html_favicon = "PalaceToolkit.png"
+
+html_theme_options = {
+ "show_nav_level": 2,
+ "navigation_with_keys": True,
+ "logo": {
+ "text": "PalaceToolkit",
+ },
+}
+
+html_static_path = [
+ "stylesheets",
+ "javascripts",
+]
+
+html_css_files = ["interactive.css"]
+html_js_files = [
+ "https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js",
+ "mathjax.js",
+]
+
+mathjax3_config = {
+ "tex": {
+ "inlineMath": [["$", "$"], ["\\(", "\\)"]],
+ "displayMath": [["$$", "$$"], ["\\[", "\\]"]],
+ "processEscapes": True,
+ "processEnvironments": True,
+ },
+ "options": {
+ "ignoreHtmlClass": "tex2jax_ignore|mathjax_ignore",
+ },
+}
diff --git a/docs/examples/differential_microstrip_modes.ipynb b/docs/examples/differential_microstrip_modes.ipynb
index d50659f..56a449a 100644
--- a/docs/examples/differential_microstrip_modes.ipynb
+++ b/docs/examples/differential_microstrip_modes.ipynb
@@ -14,7 +14,7 @@
"tags": []
},
"source": [
- "# Differential Microstrip Modes (2D Cross-Section)\n",
+ "# Differential Microstrip Modes\n",
"\n",
"This notebook builds a boxed differential microstrip cross-section (substrate + air + ground plane + two PEC strips), solves eigenmodes, and plots the first fields."
]
@@ -491,4 +491,4 @@
},
"nbformat": 4,
"nbformat_minor": 5
-}
\ No newline at end of file
+}
diff --git a/docs/examples/img/dipole_mesh.htm b/docs/examples/img/dipole_mesh.htm
deleted file mode 100644
index 2780b12..0000000
--- a/docs/examples/img/dipole_mesh.htm
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
- VTK.js | Example - OfflineLocalView
-
-
-
-
-
-
-
-
-
diff --git a/docs/examples/index.md b/docs/examples/index.md
index 2ac5c50..4b7e923 100644
--- a/docs/examples/index.md
+++ b/docs/examples/index.md
@@ -7,36 +7,176 @@ Palace configuration, simulation, and post-processing.
## Antennas
-| Example | Description |
-|:--------|:------------|
-| [Horn Antenna](horn_antenna.ipynb) | WR-90 rectangular waveguide transition to a horn antenna with waveport boundaries. |
-| [Dipole Antenna Mesh](dipole_antenna_mesh.ipynb) | Half-wave dipole geometry and mesh generation workflow. |
-| [Monopole Antenna](monopole_antenna.ipynb) | Quarter-wave monopole example with meshing and Palace setup. |
-| [L Antenna](l_antenna.ipynb) | Bent-wire L-shaped antenna workflow including geometry and driven simulation setup. |
-| [Patch Antenna](patch_antenna.ipynb) | Rectangular patch antenna model with substrate, feed, and boundary setup. |
-| [Vivaldi Antenna](vivaldi_antenna.ipynb) | Tapered-slot (Vivaldi) antenna geometry and simulation example. |
+
## Planar Microwave Circuits
-| Example | Description |
-|:--------|:------------|
-| [Coax](coax.ipynb) | Coaxial line baseline example for geometry, mesh, and configuration setup. |
-| [Coax to Waveguide Transition](coax_to_waveguide.ipynb) | Driven coax-to-waveguide transition example including geometry, mesh, and setup. |
-| [Open-ended Stub](open_ended_stub.ipynb) | Open-ended microstrip stub component with geometry and simulation setup. |
-| [Step in Width](step_in_width.ipynb) | Microstrip step-discontinuity example for meshing and EM analysis. |
+
## Waveguide Structures
-| Example | Description |
-|:--------|:------------|
-| [Waveguide Box](waveguide_box.ipynb) | Closed waveguide cavity/box example including full 3D setup and analysis. |
+
## Waveguide Mode Solver
-| Example | Description |
-|:--------|:------------|
-| [Hollow Rectangular Waveguide Modes](hollow_waveguide_modes.ipynb) | PEC waveguide eigenmodes compared with analytic TE/TM propagation constants. |
-| [Dielectric Waveguide Modes](dielectric_waveguide_modes.ipynb) | Rectangular dielectric core in cladding with guided-mode classification and field plots. |
-| [Microstrip Modes](microstrip_modes.ipynb) | Boxed 2D microstrip cross-section with PEC strip and outer conductor boundaries for hybrid mode analysis. |
-| [Slotline Modes](slotline_modes.ipynb) | Boxed 2D slotline cross-section with two PEC slot conductors and open outer boundaries. |
-| [Differential Microstrip Modes](differential_microstrip_modes.ipynb) | Boxed 2D differential microstrip with ground plane and two PEC strips for coupled-mode analysis. |
+
+
+```{toctree}
+:caption: Antennas
+:maxdepth: 1
+:hidden:
+
+horn_antenna
+dipole_antenna_mesh
+monopole_antenna
+l_antenna
+patch_antenna
+vivaldi_antenna
+```
+
+```{toctree}
+:caption: Planar Microwave Circuits
+:maxdepth: 1
+:hidden:
+
+coax
+coax_to_waveguide
+open_ended_stub
+step_in_width
+```
+
+```{toctree}
+:caption: Waveguide Structures
+:maxdepth: 1
+:hidden:
+
+waveguide_box
+```
+
+```{toctree}
+:caption: Waveguide Mode Solver
+:maxdepth: 1
+:hidden:
+
+hollow_waveguide_modes
+dielectric_waveguide_modes
+microstrip_modes
+slotline_modes
+differential_microstrip_modes
+```
diff --git a/docs/examples/microstrip_modes.ipynb b/docs/examples/microstrip_modes.ipynb
index 3db4015..bc4bf62 100644
--- a/docs/examples/microstrip_modes.ipynb
+++ b/docs/examples/microstrip_modes.ipynb
@@ -14,7 +14,7 @@
"tags": []
},
"source": [
- "# Microstrip Modes (2D Cross-Section)\n",
+ "# Microstrip Modes\n",
"\n",
"This notebook builds a simple boxed microstrip cross-section (substrate + air + PEC strip conductor), solves eigenmodes with `WaveguideModeSolver`, and plots the first fields."
]
diff --git a/docs/examples/slotline_modes.ipynb b/docs/examples/slotline_modes.ipynb
index 240f261..108158f 100644
--- a/docs/examples/slotline_modes.ipynb
+++ b/docs/examples/slotline_modes.ipynb
@@ -14,7 +14,7 @@
"tags": []
},
"source": [
- "# Slotline Modes (2D Cross-Section)\n",
+ "# Slotline Modes\n",
"\n",
"This notebook builds a boxed slotline cross-section (substrate + air + two PEC slot conductors), solves eigenmodes with `WaveguideModeSolver`, and plots mode fields."
]
diff --git a/docs/full-course.md b/docs/full-course.md
index 4278153..7a41248 100644
--- a/docs/full-course.md
+++ b/docs/full-course.md
@@ -37,7 +37,7 @@ design workflows.
---
diff --git a/docs/getting-started/geometry-and-meshing.md b/docs/getting-started/geometry-and-meshing.md
index 2001f77..b3d820e 100644
--- a/docs/getting-started/geometry-and-meshing.md
+++ b/docs/getting-started/geometry-and-meshing.md
@@ -45,9 +45,10 @@ The pipeline:
5. **Assigns physical groups** — volumes get their entity name; surfaces
at material interfaces are auto-labelled (e.g. `"conductor__dielectric"`).
-!!! tip
- The `mesh_order` controls which material wins at overlapping regions.
- Think of it as a z-index: small number = highest priority = never cut.
+```{tip}
+The `mesh_order` controls which material wins at overlapping regions.
+Think of it as a z-index: small number = highest priority = never cut.
+```
## Mesh generation
diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md
index 5c36630..6c866ee 100644
--- a/docs/getting-started/index.md
+++ b/docs/getting-started/index.md
@@ -73,3 +73,11 @@ python -c "from palacetoolkit.simulation import set_palace_path; set_palace_path
See the dedicated Ubuntu build guide and compatibility policy for details.
+```{toctree}
+:maxdepth: 1
+
+geometry-and-meshing
+simulation-setup
+post-processing
+```
+
diff --git a/docs/getting-started/simulation-setup.md b/docs/getting-started/simulation-setup.md
index 60bc70d..d718c78 100644
--- a/docs/getting-started/simulation-setup.md
+++ b/docs/getting-started/simulation-setup.md
@@ -76,8 +76,8 @@ A typical Palace JSON config has these top-level keys:
{
"Problem": { "Type": "Driven" },
"Model": { "Mesh": "model.msh", "L0": 1e-3 },
- "Domains": { "Materials": [...] },
- "Boundaries": { "PEC": {...}, "LumpedPort": [...], "Absorbing": {...} },
+ "Domains": { "Materials": [] },
+ "Boundaries": { "PEC": {}, "LumpedPort": [], "Absorbing": {} },
"Solver": { "Driven": { "MinFreq": 1.0, "MaxFreq": 10.0, "FreqStep": 0.5 } }
}
```
diff --git a/docs/index.md b/docs/index.md
index 958a940..be197d5 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,12 +1,12 @@
-

+
# PalaceToolkit
-A lightweight Python package that integrates
+PalaceToolkit is a lightweight Python package that integrates
[Palace](https://awslabs.github.io/palace/) and
-[Gmsh](https://gmsh.info/) into a unified simulation workflow.
+[Gmsh](https://gmsh.info/) into a unified open-source electromagnetic FEM simulation workflow.
---
@@ -33,3 +33,12 @@ electromagnetic solving. In a single Python script you can:
| [Full Course](full-course.md) | Structured video lectures |
| [Palace docs](https://awslabs.github.io/palace/) | Upstream Palace reference |
| [Gmsh docs](https://gmsh.info/doc/texinfo/gmsh.html) | Upstream Gmsh reference |
+
+```{toctree}
+:maxdepth: 2
+:hidden:
+
+getting-started/index
+examples/index
+full-course
+```
diff --git a/docs/javascripts/mathjax.js b/docs/javascripts/mathjax.js
index 68dbff0..dc16d4e 100644
--- a/docs/javascripts/mathjax.js
+++ b/docs/javascripts/mathjax.js
@@ -1,16 +1,3 @@
-window.MathJax = {
- tex: {
- inlineMath: [["$", "$"], ["\\(", "\\)"]],
- displayMath: [["$$", "$$"], ["\\[", "\\]"]],
- processEscapes: true,
- processEnvironments: true,
- },
- options: {
- ignoreHtmlClass: "tex2jax_ignore|mathjax_ignore",
- processHtmlClass: "arithmatex|jp-RenderedHTMLCommon|jp-RenderedMarkdown",
- },
-};
-
(() => {
const mathTargetSelector = [
".arithmatex",
@@ -31,21 +18,16 @@ window.MathJax = {
});
};
- // Run once after all scripts are loaded.
- window.addEventListener("load", typesetMath);
-
- // Re-typeset after Material for MkDocs instant navigation updates the DOM.
- const subscribeToInstantNavigation = () => {
- if (typeof document$ !== "undefined" && document$.subscribe) {
- document$.subscribe(() => {
- window.requestAnimationFrame(typesetMath);
- });
- }
- };
-
- if (document.readyState === "complete") {
- subscribeToInstantNavigation();
+ if (document.readyState === "complete" || document.readyState === "interactive") {
+ window.requestAnimationFrame(typesetMath);
} else {
- window.addEventListener("load", subscribeToInstantNavigation);
+ window.addEventListener("DOMContentLoaded", () => {
+ window.requestAnimationFrame(typesetMath);
+ });
}
+
+ // Some browsers restore page state from bfcache on history navigation.
+ window.addEventListener("pageshow", () => {
+ window.requestAnimationFrame(typesetMath);
+ });
})();
diff --git a/docs/stylesheets/interactive.css b/docs/stylesheets/interactive.css
index 34e412d..1291701 100644
--- a/docs/stylesheets/interactive.css
+++ b/docs/stylesheets/interactive.css
@@ -1,3 +1,11 @@
+/* Theme variable bridge: Material (old) + PyData (new). */
+:root {
+ --ptk-border-color: var(--pst-color-border, var(--md-default-fg-color--lightest, #d1d5db));
+ --ptk-muted-text-color: var(--pst-color-text-muted, var(--md-default-fg-color--light, #6b7280));
+ --ptk-text-color: var(--pst-color-text-base, var(--md-default-fg-color, #1f2937));
+ --ptk-code-bg: var(--pst-color-surface, var(--md-code-bg-color, #fafafa));
+}
+
/* Side-by-side interactive 3D viewer iframes */
.mesh-viewer-row {
display: flex;
@@ -10,7 +18,7 @@
flex: 1 1 48%;
min-width: 300px;
height: 450px;
- border: 1px solid var(--md-default-fg-color--lightest);
+ border: 1px solid var(--ptk-border-color);
border-radius: 8px;
}
@@ -18,7 +26,7 @@
width: 100%;
text-align: center;
font-style: italic;
- color: var(--md-default-fg-color--light);
+ color: var(--ptk-muted-text-color);
margin-top: 0.25rem;
}
@@ -37,25 +45,35 @@
max-height: calc(var(--ptk-output-visible-lines, 10) * var(--ptk-output-line-height, 1.35) * 1em);
overflow: auto;
padding: 0.75rem;
- border: 1px solid var(--md-default-fg-color--lightest);
+ border: 1px solid var(--ptk-border-color);
border-radius: 8px;
- background: var(--md-code-bg-color, #fafafa);
+ background: var(--ptk-code-bg);
line-height: var(--ptk-output-line-height, 1.35);
white-space: pre;
}
-/* mkdocs-jupyter text outputs: clamp to ~10 lines and scroll vertically. */
-.jupyter-wrapper .jp-OutputArea .jp-RenderedText.jp-OutputArea-output > pre {
+/* Notebook text outputs: clamp to ~10 lines and scroll vertically. */
+.jupyter-wrapper .jp-OutputArea .jp-RenderedText.jp-OutputArea-output > pre,
+.nboutput .output_area .output pre,
+.nboutput .output_area pre,
+.cell_output .output.stream pre,
+.cell_output .output.stderr pre,
+.cell_output .output.text_plain pre,
+.cell-output .output.stream pre,
+.cell-output .output.stderr pre,
+.cell-output .output.text_plain pre,
+.cell_output pre[id^="codecell"],
+.cell-output pre[id^="codecell"] {
max-height: calc(var(--ptk-notebook-output-lines, 10) * 1.35em) !important;
overflow-y: auto !important;
overflow-x: auto;
display: block;
line-height: 1.35;
box-sizing: border-box;
- border: 1px solid var(--md-default-fg-color--lightest);
+ border: 1px solid var(--ptk-border-color);
border-radius: 6px;
background: #ffffff !important;
- color: var(--md-default-fg-color, #1f2937) !important;
+ color: var(--ptk-text-color) !important;
padding: 0.75rem;
margin: 0;
white-space: pre;
@@ -63,10 +81,111 @@
/* Keep HTML/interactive outputs full-size with no clipping by default. */
.jupyter-wrapper .jp-OutputArea .jp-RenderedHTMLCommon.jp-OutputArea-output,
-.jupyter-wrapper .jp-OutputArea .jp-RenderedHTMLCommon.jp-OutputArea-output * {
+.jupyter-wrapper .jp-OutputArea .jp-RenderedHTMLCommon.jp-OutputArea-output *,
+.nboutput .output_area .output_html,
+.nboutput .output_area .output_html *,
+.cell_output .output.text_html,
+.cell_output .output.text_html *,
+.cell-output .output.text_html,
+.cell-output .output.text_html * {
max-height: none !important;
}
-.jupyter-wrapper .jp-OutputArea .jp-RenderedHTMLCommon.jp-OutputArea-output {
+.jupyter-wrapper .jp-OutputArea .jp-RenderedHTMLCommon.jp-OutputArea-output,
+.nboutput .output_area .output_html,
+.cell_output .output.text_html,
+.cell-output .output.text_html {
overflow: visible !important;
}
+
+.ptk-cta-button {
+ display: inline-block;
+ border-radius: 999px;
+ border: 1px solid var(--ptk-text-color);
+ color: var(--ptk-text-color);
+ text-decoration: none;
+ font-weight: 600;
+}
+
+.ptk-cta-button:hover {
+ text-decoration: none;
+ opacity: 0.9;
+}
+
+.ptk-gallery-card {
+ height: 100%;
+ border: 1px solid var(--ptk-border-color);
+ border-radius: 10px;
+ background: #ffffff;
+ overflow: hidden;
+ transition: transform 0.16s ease, box-shadow 0.16s ease;
+}
+
+.ptk-gallery-link {
+ text-decoration: none;
+ color: inherit;
+}
+
+.ptk-gallery-link:hover {
+ text-decoration: none;
+}
+
+.ptk-gallery-link:hover .ptk-gallery-card {
+ transform: translateY(-2px);
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
+}
+
+.ptk-gallery-grid {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 1rem;
+ margin: 0.5rem 0 1.5rem;
+}
+
+@media (max-width: 1100px) {
+ .ptk-gallery-grid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+}
+
+@media (max-width: 700px) {
+ .ptk-gallery-grid {
+ grid-template-columns: 1fr;
+ }
+}
+
+.ptk-gallery-card .sd-card-img-top {
+ height: 140px;
+ object-fit: contain;
+ padding: 0.75rem;
+ background: var(--ptk-code-bg);
+ border-bottom: 1px solid var(--ptk-border-color);
+}
+
+.ptk-gallery-card .sd-card-title {
+ min-height: 2.6em;
+}
+
+.ptk-gallery-card img {
+ display: block;
+ width: 100%;
+ height: 96px;
+ object-fit: contain;
+ padding: 0.5rem;
+ background: var(--ptk-code-bg);
+ border-bottom: 1px solid var(--ptk-border-color);
+}
+
+.ptk-gallery-card h3 {
+ margin: 0;
+ padding: 0.6rem 0.7rem 0.25rem;
+ font-size: 0.95rem;
+}
+
+.ptk-gallery-card p {
+ margin: 0;
+ padding: 0 0.7rem 0.7rem;
+ color: var(--ptk-muted-text-color);
+ font-size: 0.88rem;
+ line-height: 1.4;
+}
diff --git a/docs/stylesheets/patch.png b/docs/stylesheets/patch.png
new file mode 100644
index 0000000..1800160
Binary files /dev/null and b/docs/stylesheets/patch.png differ
diff --git a/justfile b/justfile
index 5d8d817..b2f4379 100644
--- a/justfile
+++ b/justfile
@@ -14,13 +14,20 @@ nbrun: ipykernel
{{python}} -m papermill "$nb" "$nb" -k palacetoolkit --cwd {{examples}}; \
done
-# Step 2: Build MkDocs site (renders notebooks directly via mkdocs-jupyter)
+# Step 2: Build Sphinx site (renders notebooks via myst-nb)
nbdocs:
- @echo "Notebook conversion is not required; MkDocs renders .ipynb directly."
+ @echo "Notebook conversion is not required; Sphinx renders .ipynb directly."
-# Step 3: Build MkDocs site
+# Step 3: Build Sphinx site
docs:
- {{python}} -m mkdocs build
+ rm -rf site
+ {{python}} -m sphinx -W --keep-going -b html docs site
+
+# Alias used by contributors coming from MkDocs-style workflows
+build: docs
+
+# Explicit docs build alias for CI/local parity
+docs-build: docs
# All three steps in sequence
docs-full: nbrun nbdocs docs
@@ -36,7 +43,15 @@ install-local:
# Dev server
serve:
- {{python}} -m mkdocs serve -a localhost:8080
+ {{python}} -m sphinx_autobuild docs site --host localhost --port 8080 \
+ --ignore "site/*" \
+ --ignore "jupyter_execute/*" \
+ --ignore ".jupyter_cache/*" \
+ --re-ignore "docs/examples/postpro/.*" \
+ --re-ignore "docs/examples/.*\\.(msh|json|config|conf)$"
+
+# Explicit docs serve alias
+docs-serve: serve
# Strip outputs from notebooks before committing
nbclean:
diff --git a/mkdocs.yml b/mkdocs.yml
deleted file mode 100644
index df87776..0000000
--- a/mkdocs.yml
+++ /dev/null
@@ -1,79 +0,0 @@
-site_name: PalaceToolkit
-site_description: Electromagnetic simulation with Palace and Gmsh.
-site_url: https://www.epsilonforge.com/palace-toolkit/
-
-theme:
- name: material
- logo: PalaceToolkit.png
- favicon: PalaceToolkit.png
- features:
- - content.code.copy
- - navigation.instant
- - navigation.tabs
- - navigation.top
- palette:
- - scheme: default
- primary: indigo
- accent: deep orange
-
-markdown_extensions:
- - admonition
- - pymdownx.superfences
- - pymdownx.highlight:
- anchor_linenums: true
- - pymdownx.arithmatex:
- generic: true
- - attr_list
- - md_in_html
- - tables
- - toc:
- permalink: true
-
-plugins:
- - search
- - mkdocs-jupyter:
- execute: false
- include_source: true
- ignore_h1_titles: true
-
-# Prevent MkDocs from warning about .htm viewer files not in nav
-not_in_nav: |
- examples/img/**
-
-extra_javascript:
- - https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js
- - javascripts/mathjax.js
- - https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js
-
-extra_css:
- - stylesheets/interactive.css
-
-nav:
- - Home: index.md
- - Getting Started:
- - getting-started/index.md
- - Geometry & Meshing: getting-started/geometry-and-meshing.md
- - Simulation Setup: getting-started/simulation-setup.md
- - Post-processing: getting-started/post-processing.md
- - Examples:
- - Overview: examples/index.md
- - Antennas:
- - Horn Antenna: examples/horn_antenna.ipynb
- - Dipole Antenna Mesh: examples/dipole_antenna_mesh.ipynb
- - Monopole Antenna: examples/monopole_antenna.ipynb
- - L Antenna: examples/l_antenna.ipynb
- - Patch Antenna: examples/patch_antenna.ipynb
- - Vivaldi Antenna: examples/vivaldi_antenna.ipynb
- - Structures and Components:
- - Coax: examples/coax.ipynb
- - Coax to Waveguide Transition: examples/coax_to_waveguide.ipynb
- - Open-ended Stub: examples/open_ended_stub.ipynb
- - Step in Width: examples/step_in_width.ipynb
- - Waveguide Box: examples/waveguide_box.ipynb
- - 2D Mode solver:
- - Hollow Rectangular Waveguide Modes: examples/hollow_waveguide_modes.ipynb
- - Dielectric Waveguide Modes: examples/dielectric_waveguide_modes.ipynb
- - Microstrip Modes: examples/microstrip_modes.ipynb
- - Slotline Modes: examples/slotline_modes.ipynb
- - Differential Microstrip Modes: examples/differential_microstrip_modes.ipynb
- - Full Course: full-course.md
diff --git a/pyproject.toml b/pyproject.toml
index 4abcec5..2562404 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -18,9 +18,14 @@ dependencies = [
plot = ["pandas", "matplotlib"]
palace-cpu = []
docs = [
- "mkdocs",
- "mkdocs-material",
- "mkdocs-jupyter",
+ "sphinx",
+ "pydata-sphinx-theme",
+ "myst-parser",
+ "myst-nb",
+ "sphinx-copybutton",
+ "sphinx-design",
+ "sphinx-autobuild",
+ "linkify-it-py",
"pyvista[jupyter]",
"nbconvert",
"ipykernel",
diff --git a/sst.config.ts b/sst.config.ts
index 2763fca..0e36084 100644
--- a/sst.config.ts
+++ b/sst.config.ts
@@ -35,7 +35,7 @@ export default $config({
const docs = new sst.aws.StaticSite("PalaceToolkitDocs", {
path: ".",
build: {
- command: "mkdocs build",
+ command: "python -m sphinx -W --keep-going -b html docs site",
output: "site",
},
router: {
diff --git a/tests/test_docs_build.py b/tests/test_docs_build.py
index 450feed..ceb2492 100644
--- a/tests/test_docs_build.py
+++ b/tests/test_docs_build.py
@@ -19,7 +19,17 @@ def test_docs_build_has_no_errors() -> None:
env["DOCS_BUILD"] = "1"
result = subprocess.run(
- [sys.executable, "-m", "mkdocs", "build", "--strict"],
+ [
+ sys.executable,
+ "-m",
+ "sphinx",
+ "-W",
+ "--keep-going",
+ "-b",
+ "html",
+ "docs",
+ "site",
+ ],
cwd=ROOT,
env=env,
capture_output=True,
@@ -30,7 +40,7 @@ def test_docs_build_has_no_errors() -> None:
if result.returncode != 0:
output = "\n".join([result.stdout.strip(), result.stderr.strip()]).strip()
pytest.fail(
- "mkdocs build failed in strict mode.\n"
+ "sphinx-build failed in strict mode.\n"
f"exit_code={result.returncode}\n"
f"{output}"
)
\ No newline at end of file