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.
Files changed (56) hide show
  1. {decktile-0.2.0 → decktile-0.2.1}/PKG-INFO +8 -3
  2. {decktile-0.2.0 → decktile-0.2.1}/README.md +6 -1
  3. {decktile-0.2.0 → decktile-0.2.1}/pyproject.toml +2 -2
  4. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/html.py +6 -2
  5. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/ir.py +9 -3
  6. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/pdg.py +4 -2
  7. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/templates/base.css +14 -1
  8. {decktile-0.2.0 → decktile-0.2.1}/tests/test_pdg.py +15 -0
  9. {decktile-0.2.0 → decktile-0.2.1}/LICENSE +0 -0
  10. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/__init__.py +0 -0
  11. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/__main__.py +0 -0
  12. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/assets/lucide/VENDORED.md +0 -0
  13. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/assets/lucide/lucide.css +0 -0
  14. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/assets/lucide/lucide.ttf +0 -0
  15. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/cli.py +0 -0
  16. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/parser/__init__.py +0 -0
  17. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/parser/ast.py +0 -0
  18. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/parser/markdown.py +0 -0
  19. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/plugins/cards.py +0 -0
  20. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/plugins/directives.py +0 -0
  21. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/plugins/fenced.py +0 -0
  22. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/plugins/layouts.py +0 -0
  23. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/plugins/lucide.py +0 -0
  24. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/plugins/lucide_font.py +0 -0
  25. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/__init__.py +0 -0
  26. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/odf/__init__.py +0 -0
  27. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/odf/geometry.py +0 -0
  28. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/odf/shapes.py +0 -0
  29. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/odf/styles.py +0 -0
  30. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/odp.py +0 -0
  31. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/pdf.py +0 -0
  32. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/seaborn.py +0 -0
  33. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/templates/decktile.js +0 -0
  34. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/render/templates/shell.html +0 -0
  35. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/seaborn_styles/__init__.py +0 -0
  36. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/seaborn_styles/ossummit_europe.py +0 -0
  37. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/theme/__init__.py +0 -0
  38. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/theme/colors.py +0 -0
  39. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/theme/loader.py +0 -0
  40. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/theme/parser.py +0 -0
  41. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/themes/default.css +0 -0
  42. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/themes/kcd_vietnam.css +0 -0
  43. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/themes/kubecon_china.css +0 -0
  44. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/themes/kubecon_japan.css +0 -0
  45. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/themes/ossummit_europe.css +0 -0
  46. {decktile-0.2.0 → decktile-0.2.1}/src/decktile/themes/ossummit_korea.css +0 -0
  47. {decktile-0.2.0 → decktile-0.2.1}/tests/__init__.py +0 -0
  48. {decktile-0.2.0 → decktile-0.2.1}/tests/test_cli.py +0 -0
  49. {decktile-0.2.0 → decktile-0.2.1}/tests/test_geometry.py +0 -0
  50. {decktile-0.2.0 → decktile-0.2.1}/tests/test_html.py +0 -0
  51. {decktile-0.2.0 → decktile-0.2.1}/tests/test_ir.py +0 -0
  52. {decktile-0.2.0 → decktile-0.2.1}/tests/test_odf_shapes.py +0 -0
  53. {decktile-0.2.0 → decktile-0.2.1}/tests/test_odp.py +0 -0
  54. {decktile-0.2.0 → decktile-0.2.1}/tests/test_parser.py +0 -0
  55. {decktile-0.2.0 → decktile-0.2.1}/tests/test_seaborn_styles.py +0 -0
  56. {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.0
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.0
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
- # Decktile
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
- # Decktile
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.0",
22
+ "predictygraph>=0.1.1",
23
23
  ]
24
24
  requires-python = ">=3.11"
25
25
  readme = "README.md"
26
- version = "0.2.0"
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
- svg = render_pdg_svg(node.content, font_family=fam, font_size=size,
387
- tag_colors=tags,
388
- blueprint=styles.get("pdg_blueprint", False)) or ""
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, .pdg-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