Skip to content

Commit 01ca355

Browse files
authored
📚 DOCS: Add live preview (w/ pyscript) (#679)
1 parent 8daa00b commit 01ca355

File tree

6 files changed

+216
-2
lines changed

6 files changed

+216
-2
lines changed

docs/_static/custom.css

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,31 @@ h3::before {
2222
.admonition > .admonition-title, div.admonition.no-icon > .admonition-title {
2323
padding-left: .6rem;
2424
}
25+
26+
/* Live preview page */
27+
iframe.pyscript, textarea.pyscript {
28+
width: 100%;
29+
height: 400px;
30+
}
31+
iframe.pyscript {
32+
padding: 4px;
33+
}
34+
textarea.pyscript {
35+
padding: 30px 20px 20px;
36+
border-radius: 8px;
37+
resize: vertical;
38+
font-size: 16px;
39+
font-family: monospace;
40+
}
41+
.display-flex {
42+
display: flex;
43+
}
44+
.display-inline-block {
45+
display: inline-block;
46+
margin-right: 1rem;
47+
margin-bottom: 0;
48+
}
49+
span.label {
50+
/* pyscript changes this and it messes up footnote labels */
51+
all: unset;
52+
}

docs/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"sphinxext.rediraffe",
3636
"sphinxcontrib.mermaid",
3737
"sphinxext.opengraph",
38+
"sphinx_pyscript",
3839
]
3940

4041
# Add any paths that contain templates here, relative to this directory.

docs/index.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,24 @@ sd_hide_title: true
3030
A Sphinx and Docutils extension to parse MyST,
3131
a rich and extensible flavour of Markdown for authoring technical and scientific documentation.
3232

33+
````{div} sd-d-flex-row
3334
```{button-ref} intro
3435
:ref-type: doc
3536
:color: primary
36-
:class: sd-rounded-pill
37+
:class: sd-rounded-pill sd-mr-3
3738
3839
Get Started
3940
```
4041
42+
```{button-ref} live-preview
43+
:ref-type: doc
44+
:color: secondary
45+
:class: sd-rounded-pill
46+
47+
Live Demo
48+
```
49+
````
50+
4151
:::
4252

4353
::::
@@ -115,6 +125,7 @@ The MyST markdown language and MyST parser are both supported by the open commun
115125
```{toctree}
116126
:hidden:
117127
intro.md
128+
live-preview.md
118129
```
119130

120131
```{toctree}

docs/live-preview.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
---
2+
py-config:
3+
splashscreen:
4+
autoclose: true
5+
packages:
6+
- myst-docutils
7+
- docutils==0.19
8+
- pygments
9+
---
10+
11+
# Live Preview
12+
13+
This is a live preview of the MyST Markdown [docutils renderer](docutils.md).
14+
You can edit the text/configuration below and see the live output.[^note]
15+
16+
[^note]: Additional styling is usually provided by Sphinx themes.
17+
18+
```{py-script}
19+
:file: live_preview.py
20+
```
21+
22+
::::::::{grid} 1 1 1 2
23+
24+
:::::::{grid-item}
25+
:child-align: end
26+
27+
```{raw} html
28+
<div><u><span id="myst-version"></span></u></div>
29+
```
30+
31+
:::::{tab-set}
32+
::::{tab-item} Input text
33+
````{raw} html
34+
<textarea class="pyscript" id="input_myst">
35+
# Heading 1
36+
37+
Hallo world!
38+
39+
```{note}
40+
An admonition note!
41+
```
42+
43+
term
44+
: definition
45+
46+
$$\pi = 3.14159$$
47+
48+
```{list-table}
49+
:header-rows: 1
50+
:align: center
51+
52+
* - Header 1
53+
- Header 2
54+
* - Item 1
55+
- Item 2
56+
```
57+
58+
```{figure} https://via.placeholder.com/150
59+
:width: 100px
60+
:align: center
61+
62+
Figure caption
63+
```
64+
</textarea>
65+
````
66+
67+
::::
68+
::::{tab-item} Configuration (YAML)
69+
<textarea class="pyscript" id="input_config">
70+
# see: https://docutils.sourceforge.io/docs/user/config.html
71+
myst_enable_extensions:
72+
- colon_fence
73+
- deflist
74+
- dollarmath
75+
myst_highlight_code_blocks: false
76+
embed_stylesheet: true
77+
stylesheet_path:
78+
- minimal.css
79+
</textarea>
80+
::::
81+
:::::
82+
83+
:::::::
84+
:::::::{grid-item}
85+
:child-align: end
86+
87+
```{raw} html
88+
<div class="display-flex">
89+
<label for="output_format" class="display-inline-block">Output Format:</label>
90+
<select id="output_format" class="display-inline-block">
91+
<option value="pseudoxml">AST</option>
92+
<option value="html5" selected>HTML</option>
93+
<option value="latex">LaTeX</option>
94+
</select>
95+
</div>
96+
```
97+
98+
::::{tab-set}
99+
:::{tab-item} HTML Render
100+
<iframe class="pyscript" id="output_html" readonly="true"></iframe>
101+
:::
102+
:::{tab-item} Raw Output
103+
<textarea class="pyscript" id="output_raw" readonly="true"></textarea>
104+
:::
105+
:::{tab-item} Warnings
106+
<textarea class="pyscript" id="output_warnings" readonly="true"></textarea>
107+
:::
108+
::::
109+
:::::::
110+
::::::::

docs/live_preview.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from io import StringIO
2+
3+
import yaml
4+
from docutils.core import publish_string
5+
from js import document
6+
7+
from myst_parser import __version__
8+
from myst_parser.parsers.docutils_ import Parser
9+
10+
11+
def convert(input_config: str, input_myst: str, writer_name: str) -> dict:
12+
warning_stream = StringIO()
13+
try:
14+
settings = yaml.safe_load(input_config) if input_config else {}
15+
assert isinstance(settings, dict), "not a dictionary"
16+
except Exception as exc:
17+
warning_stream.write(f"ERROR: config load: {exc}\n")
18+
settings = {}
19+
settings.update(
20+
{
21+
"output_encoding": "unicode",
22+
"warning_stream": warning_stream,
23+
}
24+
)
25+
try:
26+
output = publish_string(
27+
input_myst,
28+
parser=Parser(),
29+
writer_name=writer_name,
30+
settings_overrides=settings,
31+
)
32+
except Exception as exc:
33+
output = f"ERROR: conversion:\n{exc}"
34+
return {"output": output, "warnings": warning_stream.getvalue()}
35+
36+
37+
version_label = document.querySelector("span#myst-version")
38+
config_textarea = document.querySelector("textarea#input_config")
39+
input_textarea = document.querySelector("textarea#input_myst")
40+
output_iframe = document.querySelector("iframe#output_html")
41+
output_raw = document.querySelector("textarea#output_raw")
42+
warnings_textarea = document.querySelector("textarea#output_warnings")
43+
oformat_select = document.querySelector("select#output_format")
44+
45+
46+
def do_convert(event=None):
47+
result = convert(config_textarea.value, input_textarea.value, oformat_select.value)
48+
output_raw.value = result["output"]
49+
if "html" in oformat_select.value:
50+
output_iframe.contentDocument.body.innerHTML = result["output"]
51+
else:
52+
output_iframe.contentDocument.body.innerHTML = (
53+
"Change output format to HTML to see output"
54+
)
55+
warnings_textarea.value = result["warnings"]
56+
57+
58+
version_label.textContent = f"myst-parser v{__version__}"
59+
config_textarea.oninput = do_convert
60+
input_textarea.oninput = do_convert
61+
oformat_select.onchange = do_convert
62+
63+
do_convert()

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,12 @@ linkify = ["linkify-it-py~=1.0"]
5555
rtd = [
5656
"ipython",
5757
# currently required to get sphinx v5
58-
"sphinx-book-theme @ git+https://github.com/executablebooks/sphinx-book-theme.git@8da268fce3159755041e8db93e132221a0b0def5#egg=sphinx-book-theme",
58+
"sphinx-book-theme==0.4.0rc1",
5959
"sphinx-design",
6060
"sphinxext-rediraffe~=0.2.7",
6161
"sphinxcontrib.mermaid~=0.7.1",
6262
"sphinxext-opengraph~=0.6.3",
63+
"sphinx-pyscript",
6364
]
6465
testing = [
6566
"beautifulsoup4",

0 commit comments

Comments
 (0)