decktile 0.2.0__tar.gz → 0.2.1__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.
- {decktile-0.2.0 → decktile-0.2.1}/PKG-INFO +8 -3
- {decktile-0.2.0 → decktile-0.2.1}/README.md +6 -1
- {decktile-0.2.0 → decktile-0.2.1}/pyproject.toml +2 -2
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/html.py +6 -2
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/ir.py +9 -3
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/pdg.py +4 -2
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/templates/base.css +14 -1
- {decktile-0.2.0 → decktile-0.2.1}/tests/test_pdg.py +15 -0
- {decktile-0.2.0 → decktile-0.2.1}/LICENSE +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/__init__.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/__main__.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/assets/lucide/VENDORED.md +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/assets/lucide/lucide.css +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/assets/lucide/lucide.ttf +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/cli.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/parser/__init__.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/parser/ast.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/parser/markdown.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/plugins/cards.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/plugins/directives.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/plugins/fenced.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/plugins/layouts.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/plugins/lucide.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/plugins/lucide_font.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/__init__.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/odf/__init__.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/odf/geometry.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/odf/shapes.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/odf/styles.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/odp.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/pdf.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/seaborn.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/templates/decktile.js +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/templates/shell.html +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/seaborn_styles/__init__.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/seaborn_styles/ossummit_europe.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/theme/__init__.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/theme/colors.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/theme/loader.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/theme/parser.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/themes/default.css +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/themes/kcd_vietnam.css +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/themes/kubecon_china.css +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/themes/kubecon_japan.css +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/themes/ossummit_europe.css +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/src/decktile/themes/ossummit_korea.css +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/tests/__init__.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/tests/test_cli.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/tests/test_geometry.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/tests/test_html.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/tests/test_ir.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/tests/test_odf_shapes.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/tests/test_odp.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/tests/test_parser.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/tests/test_seaborn_styles.py +0 -0
- {decktile-0.2.0 → decktile-0.2.1}/tests/test_video.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: decktile
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Markdown to designed slides: HTML, PDF and editable ODP
|
|
5
5
|
Author-Email: Reza Jelveh <git@jelveh.me>
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -20,14 +20,19 @@ Requires-Dist: pygments-styles>=0.3.0
|
|
|
20
20
|
Requires-Dist: odfdo>=3.27.2
|
|
21
21
|
Requires-Dist: mermaidx>=0.8.1
|
|
22
22
|
Requires-Dist: python-lucide>=0.5.0
|
|
23
|
-
Requires-Dist: predictygraph>=0.1.
|
|
23
|
+
Requires-Dist: predictygraph>=0.1.1
|
|
24
24
|
Provides-Extra: docs
|
|
25
25
|
Requires-Dist: sphinx>=9.0.4; extra == "docs"
|
|
26
26
|
Requires-Dist: furo>=2025.12.19; extra == "docs"
|
|
27
27
|
Requires-Dist: myst-parser>=5.1.0; extra == "docs"
|
|
28
28
|
Description-Content-Type: text/markdown
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
<p align="center">
|
|
31
|
+
<picture>
|
|
32
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/logo/decktile-logo-dark.svg">
|
|
33
|
+
<img src="assets/logo/decktile-logo.svg" alt="decktile" width="360">
|
|
34
|
+
</picture>
|
|
35
|
+
</p>
|
|
31
36
|
|
|
32
37
|
Markdown to styled HTML slides with PDF and ODP output.
|
|
33
38
|
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/logo/decktile-logo-dark.svg">
|
|
4
|
+
<img src="assets/logo/decktile-logo.svg" alt="decktile" width="360">
|
|
5
|
+
</picture>
|
|
6
|
+
</p>
|
|
2
7
|
|
|
3
8
|
Markdown to styled HTML slides with PDF and ODP output.
|
|
4
9
|
|
|
@@ -19,11 +19,11 @@ dependencies = [
|
|
|
19
19
|
"odfdo>=3.27.2",
|
|
20
20
|
"mermaidx>=0.8.1",
|
|
21
21
|
"python-lucide>=0.5.0",
|
|
22
|
-
"predictygraph>=0.1.
|
|
22
|
+
"predictygraph>=0.1.1",
|
|
23
23
|
]
|
|
24
24
|
requires-python = ">=3.11"
|
|
25
25
|
readme = "README.md"
|
|
26
|
-
version = "0.2.
|
|
26
|
+
version = "0.2.1"
|
|
27
27
|
|
|
28
28
|
[project.license]
|
|
29
29
|
text = "GPL-3.0-or-later"
|
|
@@ -126,7 +126,7 @@ def _render_elem(e: Elem) -> str:
|
|
|
126
126
|
if e.language == "seaborn":
|
|
127
127
|
return _render_seaborn_html(e.content, e.svg, sid)
|
|
128
128
|
if e.language == "pdg":
|
|
129
|
-
return _render_pdg_html(e.content, e.svg, sid)
|
|
129
|
+
return _render_pdg_html(e.content, e.svg, sid, e.svg_live)
|
|
130
130
|
return _highlight_code(e.content, e.language, sid)
|
|
131
131
|
elif e.kind == "list":
|
|
132
132
|
s = f"<ul{sid}>\n"
|
|
@@ -260,7 +260,11 @@ def _render_mermaid(content: str, svg: str = "", sid: str = "") -> str:
|
|
|
260
260
|
return f'<pre class="mermaid-fallback"{sid}><code>{_escape(content)}</code></pre>'
|
|
261
261
|
|
|
262
262
|
|
|
263
|
-
def _render_pdg_html(content: str, svg: str = "", sid: str = "") -> str:
|
|
263
|
+
def _render_pdg_html(content: str, svg: str = "", sid: str = "", live: str = "") -> str:
|
|
264
|
+
if svg and live:
|
|
265
|
+
# animated on screen, still frame in print/PDF (and for the ODP geometry pass)
|
|
266
|
+
return (f'<div class="pdg-plot pdg-animated"{sid}>\n'
|
|
267
|
+
f'<div class="pdg-live">{live}</div>\n<div class="pdg-still">{svg}</div>\n</div>')
|
|
264
268
|
if svg:
|
|
265
269
|
return f'<div class="pdg-plot"{sid}>\n{svg}\n</div>'
|
|
266
270
|
return f'<pre class="pdg-fallback"{sid}><code>{_escape(content)}</code></pre>'
|
|
@@ -107,6 +107,7 @@ class Elem:
|
|
|
107
107
|
inlines: list[Any] = field(default_factory=list)
|
|
108
108
|
item_inlines: list[list] = field(default_factory=list)
|
|
109
109
|
svg: str = ""
|
|
110
|
+
svg_live: str = "" # animated variant for HTML only (PDF/ODP use svg)
|
|
110
111
|
pdf: bytes = b""
|
|
111
112
|
id: str = "" # data-decktile-id, assigned in build_ir
|
|
112
113
|
box: BoxGeometry | None = None # filled by render/odf/geometry.py for ODP
|
|
@@ -383,9 +384,14 @@ def _convert_node(node, styles: dict) -> Elem:
|
|
|
383
384
|
fam = styles.get("font_body_family", "")
|
|
384
385
|
size = styles.get("font_body", 18)
|
|
385
386
|
tags = styles.get("tag_colors", {})
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
387
|
+
opts = dict(font_family=fam, font_size=size, tag_colors=tags,
|
|
388
|
+
blueprint=styles.get("pdg_blueprint", False))
|
|
389
|
+
svg = render_pdg_svg(node.content, **opts) or ""
|
|
390
|
+
live = render_pdg_svg(node.content, animated=True, **opts) or ""
|
|
391
|
+
# only keep the animated copy when the diagram actually moves
|
|
392
|
+
svg_live = live if svg and "<animate" in live else ""
|
|
393
|
+
return Elem(kind="code", content=node.content, text=node.content,
|
|
394
|
+
language=node.language, font_size=fs, svg=svg, svg_live=svg_live)
|
|
389
395
|
return Elem(kind="code", content=node.content, text=node.content,
|
|
390
396
|
language=node.language, font_size=fs, svg=svg, pdf=pdf)
|
|
391
397
|
elif isinstance(node, ListNode):
|
|
@@ -49,10 +49,12 @@ def theme_css(font_family: str = "", font_size: int = 0,
|
|
|
49
49
|
|
|
50
50
|
def render_pdg_svg(content: str, font_family: str = "", font_size: int = 0,
|
|
51
51
|
tag_colors: dict[str, tuple[str, str]] | None = None,
|
|
52
|
-
blueprint: bool = False) -> str | None:
|
|
52
|
+
blueprint: bool = False, animated: bool = False) -> str | None:
|
|
53
53
|
"""Render a predictygraph diagram to SVG, or None if it fails to parse.
|
|
54
54
|
|
|
55
55
|
blueprint: palette for ``::: card {blueprint}`` (light lines, translucent fills).
|
|
56
|
+
animated: keep predictygraph's SMIL animation (flow=, border=) for HTML.
|
|
57
|
+
The default is a still frame, which PDF and ODP need.
|
|
56
58
|
"""
|
|
57
59
|
import predictygraph
|
|
58
60
|
|
|
@@ -62,7 +64,7 @@ def render_pdg_svg(content: str, font_family: str = "", font_size: int = 0,
|
|
|
62
64
|
# Theme goes first so css inside the block overrides it.
|
|
63
65
|
text = "css {\n" + css + "\n}\n" + content
|
|
64
66
|
try:
|
|
65
|
-
svg = predictygraph.render(text, t=0)
|
|
67
|
+
svg = predictygraph.render(text, t=None if animated else 0)
|
|
66
68
|
except Exception:
|
|
67
69
|
return None
|
|
68
70
|
return _strip_xml_decl(svg)
|
|
@@ -241,10 +241,23 @@ LOGO_CSS
|
|
|
241
241
|
overflow: hidden;
|
|
242
242
|
text-align: center;
|
|
243
243
|
}
|
|
244
|
-
.mermaid svg, .seaborn-plot svg
|
|
244
|
+
.mermaid svg, .seaborn-plot svg {
|
|
245
245
|
max-width: 100%;
|
|
246
246
|
height: auto;
|
|
247
247
|
}
|
|
248
|
+
/* predictygraph sets width/height to its natural size; scale up to the column
|
|
249
|
+
(aspect kept by viewBox) but never past the space the slide gives it */
|
|
250
|
+
.pdg-plot svg {
|
|
251
|
+
width: 100%;
|
|
252
|
+
height: auto;
|
|
253
|
+
max-height: IMG_MAX_Hpx;
|
|
254
|
+
}
|
|
255
|
+
/* animated diagram on screen, still frame in print/PDF */
|
|
256
|
+
.pdg-animated .pdg-still { display: none; }
|
|
257
|
+
@media print {
|
|
258
|
+
.pdg-animated .pdg-live { display: none; }
|
|
259
|
+
.pdg-animated .pdg-still { display: block; }
|
|
260
|
+
}
|
|
248
261
|
|
|
249
262
|
/* ---- ::: card {blueprint}: engineering-drawing panel for diagrams ----
|
|
250
263
|
Theme-independent on purpose (same blue on light and dark slides); a
|
|
@@ -40,3 +40,18 @@ def test_theme_css_maps_default_tag_to_plain_nodes():
|
|
|
40
40
|
css = theme_css(tag_colors={"default": ("#fafafa", "#ddd"), "red": ("#fee", "")})
|
|
41
41
|
assert "node { fill: #fafafa; stroke: #ddd; }" in css
|
|
42
42
|
assert "node.red { fill: #fee; }" in css
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_animated_pdg_moves_in_html_and_stays_still_in_print():
|
|
46
|
+
from decktile.parser.markdown import parse
|
|
47
|
+
from decktile.render.html import _render_elem, base_css, load_theme
|
|
48
|
+
from decktile.render.ir import build_ir
|
|
49
|
+
|
|
50
|
+
md = "## S\n\n```pdg\na -> b flow=forward\n```\n\n```pdg\nc -> d\n```\n"
|
|
51
|
+
elems = [e for e in build_ir(parse(md), base_css(), load_theme("default"))[0].elements
|
|
52
|
+
if e.kind == "code"]
|
|
53
|
+
moving, still = elems
|
|
54
|
+
assert "<animate" in moving.svg_live and "<animate" not in moving.svg
|
|
55
|
+
assert still.svg_live == "" # no animation, no second copy
|
|
56
|
+
html = _render_elem(moving)
|
|
57
|
+
assert 'class="pdg-live"' in html and 'class="pdg-still"' in html
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|