simplex-web 0.2.1__tar.gz → 0.2.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.
- {simplex_web-0.2.1 → simplex_web-0.2.2}/.gitignore +2 -2
- {simplex_web-0.2.1 → simplex_web-0.2.2}/PKG-INFO +5 -2
- {simplex_web-0.2.1 → simplex_web-0.2.2}/README.md +3 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/pyproject.toml +4 -4
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/builder.py +30 -4
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/sidenotes.py +3 -1
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/site_config.py +12 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/README.md +8 -3
- simplex_web-0.2.2/src/simplex/web/static/notes.js +183 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/simplex.css +145 -15
- simplex_web-0.2.2/src/simplex/web/static/tailwind.input.css +16 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/viewer.js +1 -1
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/templates/base.html +27 -12
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/templates/deck.html +1 -1
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/templates/revealjs.html.j2 +11 -6
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/vendor.py +106 -7
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/web/test_builder.py +35 -1
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/web/test_sidenotes.py +2 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/web/test_site_config.py +8 -0
- simplex_web-0.2.1/src/simplex/web/static/notes.js +0 -68
- simplex_web-0.2.1/src/simplex/web/static/tailwind.js +0 -64
- {simplex_web-0.2.1 → simplex_web-0.2.2}/LICENSE +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/cli/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/cli/__init__.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/cli/commands.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/deck/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/deck/__init__.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/deck/_template/assets/.gitkeep +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/deck/_template/assets/code/.gitkeep +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/deck/_template/assets/figures/.gitkeep +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/deck/_template/deck.toml +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/deck/_template/manim.cfg +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/deck/_template/notes.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/deck/_template/refs.bib +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/deck/_template/slides/__init__.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/deck/_template/slides/intro.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/deck/config.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/deck/registry.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/deck/scaffold.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/deck/section.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/engine/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/render/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/render/__init__.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/render/html.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/render/pdf.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/render/pptx.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/render/reconcile.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/render/runner.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/render/thumbnail.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/slides/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/slides/components/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/theme/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/__init__.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/bibliography.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/bibtex.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/callouts.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/citations.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/equations.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/notes.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/refs.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/slide_ref.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/.gitkeep +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/fonts/lato/lato-latin-400-italic.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/fonts/lato/lato-latin-400-normal.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/fonts/lato/lato-latin-700-italic.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/fonts/lato/lato-latin-700-normal.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/fonts/lato/lato-latin-900-normal.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/fonts/merriweather/merriweather-latin-400-italic.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/fonts/merriweather/merriweather-latin-400-normal.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/fonts/merriweather/merriweather-latin-700-italic.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/fonts/merriweather/merriweather-latin-700-normal.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/fonts/merriweather/merriweather-latin-900-normal.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/htmx.min.js +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/katex/auto-render.min.js +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/katex/katex.min.css +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/katex/katex.min.js +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/lucide/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/lucide/lucide.min.js +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/reveal.js/reset.css +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/reveal.js/reveal.css +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/static/reveal.js/reveal.js +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/templates/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/templates/_carousel.html +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/templates/index.html +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/src/simplex/web/templates/section.html +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/__init__.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/cli/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/cli/__init__.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/cli/test_help.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/cli/test_new.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/cli/test_render.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/deck/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/deck/__init__.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/deck/test_config.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/deck/test_registry.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/deck/test_scaffold.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/deck/test_section.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/engine/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/render/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/render/__init__.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/render/test_html.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/render/test_reconcile.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/render/test_runner.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/render/test_thumbnail.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/theme/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/web/README.md +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/web/__init__.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/web/test_bibliography.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/web/test_callouts.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/web/test_citations.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/web/test_equations.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/web/test_notes.py +0 -0
- {simplex_web-0.2.1 → simplex_web-0.2.2}/tests/web/test_slide_ref.py +0 -0
|
@@ -27,8 +27,8 @@ decks/**/slides/files/
|
|
|
27
27
|
# Generated site
|
|
28
28
|
site/
|
|
29
29
|
|
|
30
|
-
# Vendored web runtime assets (fetched on demand by simplex.web.vendor)
|
|
31
|
-
src/simplex/web/static/tailwind.
|
|
30
|
+
# Vendored web runtime assets (fetched/compiled on demand by simplex.web.vendor)
|
|
31
|
+
src/simplex/web/static/tailwind.css
|
|
32
32
|
src/simplex/web/static/htmx.min.js
|
|
33
33
|
src/simplex/web/static/katex/
|
|
34
34
|
src/simplex/web/static/reveal.js/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simplex-web
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Manim-slides presentation framework with a generated web portal.
|
|
5
5
|
Project-URL: Homepage, https://github.com/shlomi-perles/simplex
|
|
6
6
|
Project-URL: Issues, https://github.com/shlomi-perles/simplex/issues
|
|
@@ -27,7 +27,7 @@ Classifier: Typing :: Typed
|
|
|
27
27
|
Requires-Python: >=3.13
|
|
28
28
|
Requires-Dist: av>=15.0
|
|
29
29
|
Requires-Dist: jinja2>=3.1
|
|
30
|
-
Requires-Dist: manim-simplex>=0.2.
|
|
30
|
+
Requires-Dist: manim-simplex>=0.2.1
|
|
31
31
|
Requires-Dist: manim-slides>=5.1.7
|
|
32
32
|
Requires-Dist: markdown-it-py>=3.0
|
|
33
33
|
Requires-Dist: mdit-py-plugins>=0.4
|
|
@@ -233,6 +233,9 @@ nav = [
|
|
|
233
233
|
]
|
|
234
234
|
```
|
|
235
235
|
|
|
236
|
+
Links labeled `GitHub` are shown as the footer GitHub icon, next to the
|
|
237
|
+
`Built with Simplex` mark.
|
|
238
|
+
|
|
236
239
|
Deployment-only settings are read from environment variables:
|
|
237
240
|
|
|
238
241
|
- `SIMPLEX_BASE_URL`
|
|
@@ -32,7 +32,7 @@ classifiers = [
|
|
|
32
32
|
"Typing :: Typed",
|
|
33
33
|
]
|
|
34
34
|
dependencies = [
|
|
35
|
-
"manim-simplex>=0.2.
|
|
35
|
+
"manim-simplex>=0.2.1",
|
|
36
36
|
"manim-slides>=5.1.7",
|
|
37
37
|
"pydantic>=2.7",
|
|
38
38
|
"pydantic-settings>=2.3",
|
|
@@ -72,7 +72,7 @@ license-files = ["LICENSE"]
|
|
|
72
72
|
name = "simplex-web"
|
|
73
73
|
readme = "README.md"
|
|
74
74
|
requires-python = ">=3.13"
|
|
75
|
-
version = "0.2.
|
|
75
|
+
version = "0.2.2"
|
|
76
76
|
|
|
77
77
|
[project.scripts]
|
|
78
78
|
simplex = "simplex.cli.commands:app"
|
|
@@ -109,7 +109,7 @@ artifacts = [
|
|
|
109
109
|
"src/simplex/web/static/htmx.min.js",
|
|
110
110
|
"src/simplex/web/static/katex/**/*",
|
|
111
111
|
"src/simplex/web/static/reveal.js/**/*",
|
|
112
|
-
"src/simplex/web/static/tailwind.
|
|
112
|
+
"src/simplex/web/static/tailwind.input.css",
|
|
113
113
|
]
|
|
114
114
|
only-include = [
|
|
115
115
|
"LICENSE",
|
|
@@ -130,7 +130,7 @@ artifacts = [
|
|
|
130
130
|
"src/simplex/web/static/htmx.min.js",
|
|
131
131
|
"src/simplex/web/static/katex/**/*",
|
|
132
132
|
"src/simplex/web/static/reveal.js/**/*",
|
|
133
|
-
"src/simplex/web/static/tailwind.
|
|
133
|
+
"src/simplex/web/static/tailwind.input.css",
|
|
134
134
|
]
|
|
135
135
|
packages = ["src/simplex"]
|
|
136
136
|
|
|
@@ -18,6 +18,7 @@ No render cache. Manim's per-animation cache + ``save_sections=True``
|
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
import contextlib
|
|
21
|
+
import hashlib
|
|
21
22
|
import shutil
|
|
22
23
|
import subprocess
|
|
23
24
|
from datetime import UTC, datetime, time
|
|
@@ -36,6 +37,28 @@ from simplex.web.bibliography import Bibliography
|
|
|
36
37
|
from simplex.web.site_config import SiteConfig
|
|
37
38
|
|
|
38
39
|
|
|
40
|
+
def _static_source_dir() -> Path:
|
|
41
|
+
return Path(__file__).parent / "static"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _file_version(path: Path) -> str:
|
|
45
|
+
"""Short content hash for cache-busting generated asset URLs."""
|
|
46
|
+
if not path.exists() or not path.is_file():
|
|
47
|
+
return ""
|
|
48
|
+
digest = hashlib.blake2s(digest_size=6)
|
|
49
|
+
with path.open("rb") as f:
|
|
50
|
+
for chunk in iter(lambda: f.read(1024 * 1024), b""):
|
|
51
|
+
digest.update(chunk)
|
|
52
|
+
return digest.hexdigest()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _with_version(url: str, version: str) -> str:
|
|
56
|
+
if not version:
|
|
57
|
+
return url
|
|
58
|
+
separator = "&" if "?" in url else "?"
|
|
59
|
+
return f"{url}{separator}v={version}"
|
|
60
|
+
|
|
61
|
+
|
|
39
62
|
def _jinja(site_cfg: SiteConfig) -> Environment:
|
|
40
63
|
env = Environment(
|
|
41
64
|
loader=PackageLoader("simplex.web", "templates"),
|
|
@@ -45,7 +68,9 @@ def _jinja(site_cfg: SiteConfig) -> Environment:
|
|
|
45
68
|
)
|
|
46
69
|
|
|
47
70
|
def static(path: str) -> str:
|
|
48
|
-
|
|
71
|
+
clean = path.lstrip("/")
|
|
72
|
+
url = site_cfg.url("static/" + clean)
|
|
73
|
+
return _with_version(url, _file_version(_static_source_dir() / clean))
|
|
49
74
|
|
|
50
75
|
globals_: dict[str, Any] = cast(dict[str, Any], env.globals)
|
|
51
76
|
globals_["static"] = static
|
|
@@ -55,13 +80,13 @@ def _jinja(site_cfg: SiteConfig) -> Environment:
|
|
|
55
80
|
|
|
56
81
|
def _copy_static(site_dir: Path) -> None:
|
|
57
82
|
"""Copy bundled static assets into ``site/static/``."""
|
|
58
|
-
src =
|
|
83
|
+
src = _static_source_dir()
|
|
59
84
|
src.mkdir(parents=True, exist_ok=True)
|
|
60
85
|
vendor.ensure(src)
|
|
61
86
|
dst = site_dir / "static"
|
|
62
87
|
dst.mkdir(parents=True, exist_ok=True)
|
|
63
88
|
for entry in src.iterdir():
|
|
64
|
-
if entry.name in {"README.md", ".gitkeep"}:
|
|
89
|
+
if entry.name in {"README.md", ".gitkeep", "tailwind.input.css"}:
|
|
65
90
|
continue
|
|
66
91
|
target = dst / entry.name
|
|
67
92
|
if entry.is_dir():
|
|
@@ -178,7 +203,7 @@ def _build_deck(
|
|
|
178
203
|
for main in manifest.main_slides
|
|
179
204
|
)
|
|
180
205
|
|
|
181
|
-
html.render_html(
|
|
206
|
+
slides_html = html.render_html(
|
|
182
207
|
deck,
|
|
183
208
|
manifest.model_copy(update={"main_slides": enriched}),
|
|
184
209
|
output_dir=deck_out,
|
|
@@ -206,6 +231,7 @@ def _build_deck(
|
|
|
206
231
|
has_notes_pdf=_has_notes_pdf(deck_out),
|
|
207
232
|
notes_html=notes_html,
|
|
208
233
|
palette_css=render_web_css(deck.resolved_web_palette()),
|
|
234
|
+
slides_version=_file_version(slides_html),
|
|
209
235
|
)
|
|
210
236
|
(deck_out / "index.html").write_text(page, encoding="utf-8")
|
|
211
237
|
return (
|
|
@@ -69,7 +69,9 @@ def _extract_bodies(html: str) -> dict[str, str]:
|
|
|
69
69
|
|
|
70
70
|
def _render_sidenote(n: str, num: str, body: str) -> str:
|
|
71
71
|
return (
|
|
72
|
-
f'<label for="sn-toggle-{n}" class="sidenote-ref" id="snref-{n}"
|
|
72
|
+
f'<label for="sn-toggle-{n}" class="sidenote-ref" id="snref-{n}" '
|
|
73
|
+
f'role="button" tabindex="0" aria-controls="sn-{n}" aria-expanded="false">'
|
|
74
|
+
f"{num}</label>"
|
|
73
75
|
f'<input type="checkbox" id="sn-toggle-{n}" class="sidenote-toggle" '
|
|
74
76
|
'aria-hidden="true" />'
|
|
75
77
|
f'<aside class="sidenote" id="sn-{n}" role="note">{body}</aside>'
|
|
@@ -9,6 +9,7 @@ import os
|
|
|
9
9
|
import tomllib
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import Any, Self
|
|
12
|
+
from urllib.parse import urlparse
|
|
12
13
|
|
|
13
14
|
from pydantic import BaseModel, ConfigDict
|
|
14
15
|
|
|
@@ -44,6 +45,17 @@ class SiteConfig(BaseModel):
|
|
|
44
45
|
return f"/{clean}"
|
|
45
46
|
return f"{base}/{clean}"
|
|
46
47
|
|
|
48
|
+
def is_external_url(self, href: str) -> bool:
|
|
49
|
+
"""Return true for links that should not be prefixed by `base_url`."""
|
|
50
|
+
parsed = urlparse(href)
|
|
51
|
+
return bool(parsed.scheme or parsed.netloc)
|
|
52
|
+
|
|
53
|
+
def nav_url(self, href: str) -> str:
|
|
54
|
+
"""Resolve a committed nav href without breaking external links."""
|
|
55
|
+
if self.is_external_url(href) or href.startswith("#"):
|
|
56
|
+
return href
|
|
57
|
+
return self.url(href)
|
|
58
|
+
|
|
47
59
|
@classmethod
|
|
48
60
|
def load(cls, repo_root: Path | None = None) -> Self:
|
|
49
61
|
repo_root = repo_root or Path.cwd()
|
|
@@ -6,11 +6,15 @@ Vendored runtime assets, copied verbatim to `site/static/` at build time.
|
|
|
6
6
|
|
|
7
7
|
- `simplex.css` -- site-specific styles (carousel, deck page, academic
|
|
8
8
|
notes typography, Tufte sidenotes, citations, bibliography).
|
|
9
|
-
- `
|
|
9
|
+
- `tailwind.input.css` -- Tailwind v4 source (CSS-first config + `@source`
|
|
10
|
+
globs). Compiled to `tailwind.css` by `simplex.web.vendor`.
|
|
11
|
+
- `viewer.js`, `notes.js` -- parent-page bridge for the deck iframe + carousel
|
|
12
|
+
arrows, and the standalone notes view.
|
|
10
13
|
|
|
11
14
|
## Vendored for builds (not committed)
|
|
12
15
|
|
|
13
|
-
- `tailwind.
|
|
16
|
+
- `tailwind.css` (compiled from `tailwind.input.css` by the Tailwind v4
|
|
17
|
+
standalone CLI; binary cached per-user, not shipped in the wheel)
|
|
14
18
|
- `katex/` (CSS + fonts + JS + auto-render)
|
|
15
19
|
- `reveal.js/` (`reveal.js`, `reveal.css`, `reset.css`)
|
|
16
20
|
- `htmx.min.js` (optional, kept for future progressive enhancement)
|
|
@@ -20,4 +24,5 @@ Vendored runtime assets, copied verbatim to `site/static/` at build time.
|
|
|
20
24
|
## Don't
|
|
21
25
|
|
|
22
26
|
- Don't load these via CDN -- vendoring keeps Pages offline-safe.
|
|
23
|
-
- Don't edit the vendored files;
|
|
27
|
+
- Don't edit the vendored files; bump pinned versions in
|
|
28
|
+
`simplex/web/vendor.py` and let the next build refetch.
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/* Auto-fit display math + viewer plumbing for the notes pane.
|
|
2
|
+
*
|
|
3
|
+
* KaTeX renders display equations at their natural width; long lines
|
|
4
|
+
* overflow the .deck-notes column and force a horizontal scroll bar.
|
|
5
|
+
* We measure each `.katex-display` against its container and apply a
|
|
6
|
+
* `transform: scale(...)` to shrink it just enough to fit -- so the
|
|
7
|
+
* reader never has to scroll for math that's only a little too wide.
|
|
8
|
+
*
|
|
9
|
+
* Equations narrower than the column are untouched. Equations that
|
|
10
|
+
* would have to shrink past `MIN_SCALE` keep their scroll bar (we
|
|
11
|
+
* don't want to render math at unreadable sizes).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
(function () {
|
|
15
|
+
"use strict";
|
|
16
|
+
|
|
17
|
+
var MIN_SCALE = 0.55;
|
|
18
|
+
|
|
19
|
+
function fitOne(host) {
|
|
20
|
+
var inner = host.querySelector(".katex");
|
|
21
|
+
if (!inner) return;
|
|
22
|
+
|
|
23
|
+
// Reset state from prior runs so resize re-measures naturally.
|
|
24
|
+
inner.style.removeProperty("transform");
|
|
25
|
+
inner.style.removeProperty("transform-origin");
|
|
26
|
+
inner.style.removeProperty("display");
|
|
27
|
+
host.style.removeProperty("min-height");
|
|
28
|
+
host.classList.remove("katex-fitted");
|
|
29
|
+
|
|
30
|
+
var available = host.clientWidth;
|
|
31
|
+
var natural = inner.scrollWidth;
|
|
32
|
+
if (!available || !natural || natural <= available) return;
|
|
33
|
+
|
|
34
|
+
var scale = available / natural;
|
|
35
|
+
if (scale < MIN_SCALE) return; // leave scrollbar -- too wide to scale.
|
|
36
|
+
|
|
37
|
+
inner.style.transformOrigin = "left top";
|
|
38
|
+
inner.style.transform = "scale(" + scale + ")";
|
|
39
|
+
inner.style.display = "block";
|
|
40
|
+
// `transform` doesn't affect layout, so we reclaim the height the
|
|
41
|
+
// scaled equation would have used; otherwise an empty band appears
|
|
42
|
+
// below the math.
|
|
43
|
+
var scaledHeight = inner.offsetHeight * scale;
|
|
44
|
+
host.style.minHeight = scaledHeight + "px";
|
|
45
|
+
host.classList.add("katex-fitted");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function fitAll() {
|
|
49
|
+
var hosts = document.querySelectorAll(".deck-notes .katex-display");
|
|
50
|
+
for (var i = 0; i < hosts.length; i++) fitOne(hosts[i]);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function initSidenotePopovers() {
|
|
54
|
+
var refs = document.querySelectorAll(".sidenote-ref[for]");
|
|
55
|
+
if (!refs.length) return;
|
|
56
|
+
|
|
57
|
+
var narrow = window.matchMedia ? window.matchMedia("(max-width: 1279px)") : null;
|
|
58
|
+
var popover = null;
|
|
59
|
+
var activeRef = null;
|
|
60
|
+
|
|
61
|
+
function isNarrow() {
|
|
62
|
+
return !narrow || narrow.matches;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function noteFor(ref) {
|
|
66
|
+
var input = document.getElementById(ref.getAttribute("for") || "");
|
|
67
|
+
var note = input && input.nextElementSibling;
|
|
68
|
+
if (!note || !note.classList || !note.classList.contains("sidenote")) return null;
|
|
69
|
+
return note;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function ensurePopover() {
|
|
73
|
+
if (popover) return popover;
|
|
74
|
+
popover = document.createElement("div");
|
|
75
|
+
popover.className = "sidenote-popover";
|
|
76
|
+
popover.setAttribute("role", "dialog");
|
|
77
|
+
popover.setAttribute("aria-modal", "true");
|
|
78
|
+
popover.setAttribute("aria-hidden", "true");
|
|
79
|
+
popover.innerHTML =
|
|
80
|
+
'<button type="button" class="sidenote-popover-backdrop" data-sidenote-close aria-label="Close note"></button>' +
|
|
81
|
+
'<div class="sidenote-popover-sheet">' +
|
|
82
|
+
'<div class="sidenote-popover-header">' +
|
|
83
|
+
'<span data-sidenote-title>Note</span>' +
|
|
84
|
+
'<button type="button" class="sidenote-popover-close" data-sidenote-close aria-label="Close note">x</button>' +
|
|
85
|
+
"</div>" +
|
|
86
|
+
'<div class="sidenote-popover-content" data-sidenote-content></div>' +
|
|
87
|
+
"</div>";
|
|
88
|
+
document.body.appendChild(popover);
|
|
89
|
+
popover.querySelectorAll("[data-sidenote-close]").forEach(function (btn) {
|
|
90
|
+
btn.addEventListener("click", close);
|
|
91
|
+
});
|
|
92
|
+
return popover;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function close() {
|
|
96
|
+
if (!popover) return;
|
|
97
|
+
popover.classList.remove("is-open");
|
|
98
|
+
popover.setAttribute("aria-hidden", "true");
|
|
99
|
+
document.body.classList.remove("sidenote-popover-open");
|
|
100
|
+
if (activeRef) {
|
|
101
|
+
activeRef.setAttribute("aria-expanded", "false");
|
|
102
|
+
try { activeRef.focus({ preventScroll: true }); } catch (_) { activeRef.focus(); }
|
|
103
|
+
}
|
|
104
|
+
activeRef = null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function open(ref) {
|
|
108
|
+
var note = noteFor(ref);
|
|
109
|
+
if (!note) return;
|
|
110
|
+
var sheet = ensurePopover();
|
|
111
|
+
var content = sheet.querySelector("[data-sidenote-content]");
|
|
112
|
+
var title = sheet.querySelector("[data-sidenote-title]");
|
|
113
|
+
var closeBtn = sheet.querySelector(".sidenote-popover-close");
|
|
114
|
+
if (content) content.innerHTML = note.innerHTML;
|
|
115
|
+
if (title) title.textContent = "Note " + ref.textContent.trim();
|
|
116
|
+
activeRef = ref;
|
|
117
|
+
ref.setAttribute("aria-expanded", "true");
|
|
118
|
+
sheet.classList.add("is-open");
|
|
119
|
+
sheet.setAttribute("aria-hidden", "false");
|
|
120
|
+
document.body.classList.add("sidenote-popover-open");
|
|
121
|
+
if (content && window.renderMathInElement) {
|
|
122
|
+
try {
|
|
123
|
+
window.renderMathInElement(content, {
|
|
124
|
+
delimiters: [
|
|
125
|
+
{ left: "\\[", right: "\\]", display: true },
|
|
126
|
+
{ left: "\\(", right: "\\)", display: false },
|
|
127
|
+
],
|
|
128
|
+
throwOnError: false,
|
|
129
|
+
ignoredTags: ["script", "noscript", "style", "textarea", "pre", "code"],
|
|
130
|
+
});
|
|
131
|
+
} catch (_) {}
|
|
132
|
+
}
|
|
133
|
+
if (closeBtn) {
|
|
134
|
+
try { closeBtn.focus({ preventScroll: true }); } catch (_) { closeBtn.focus(); }
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
refs.forEach(function (ref) {
|
|
139
|
+
ref.addEventListener("click", function (e) {
|
|
140
|
+
if (!isNarrow()) return;
|
|
141
|
+
e.preventDefault();
|
|
142
|
+
open(ref);
|
|
143
|
+
});
|
|
144
|
+
ref.addEventListener("keydown", function (e) {
|
|
145
|
+
if (!isNarrow()) return;
|
|
146
|
+
if (e.key !== "Enter" && e.key !== " ") return;
|
|
147
|
+
e.preventDefault();
|
|
148
|
+
open(ref);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
document.addEventListener("keydown", function (e) {
|
|
153
|
+
if (e.key === "Escape") close();
|
|
154
|
+
});
|
|
155
|
+
if (narrow && typeof narrow.addEventListener === "function") {
|
|
156
|
+
narrow.addEventListener("change", function () {
|
|
157
|
+
if (!isNarrow()) close();
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Expose for the KaTeX onload hook in base.html to call once math is
|
|
163
|
+
// typeset.
|
|
164
|
+
window.simplexFitMath = fitAll;
|
|
165
|
+
|
|
166
|
+
// Re-fit on viewport changes (debounced via rAF).
|
|
167
|
+
var pending = null;
|
|
168
|
+
function schedule() {
|
|
169
|
+
if (pending !== null) cancelAnimationFrame(pending);
|
|
170
|
+
pending = requestAnimationFrame(function () {
|
|
171
|
+
pending = null;
|
|
172
|
+
fitAll();
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
window.addEventListener("resize", schedule);
|
|
176
|
+
window.addEventListener("load", schedule);
|
|
177
|
+
|
|
178
|
+
if (document.readyState === "loading") {
|
|
179
|
+
document.addEventListener("DOMContentLoaded", initSidenotePopovers);
|
|
180
|
+
} else {
|
|
181
|
+
initSidenotePopovers();
|
|
182
|
+
}
|
|
183
|
+
})();
|
|
@@ -390,13 +390,38 @@ body {
|
|
|
390
390
|
text-decoration: none;
|
|
391
391
|
}
|
|
392
392
|
.site-footer a:hover { color: var(--canvas-text); }
|
|
393
|
+
.site-footer a.site-footer-simplex,
|
|
394
|
+
.site-footer a.site-footer-simplex:hover {
|
|
395
|
+
color: #e50914;
|
|
396
|
+
font-weight: 900;
|
|
397
|
+
text-decoration: underline;
|
|
398
|
+
text-decoration-thickness: 2px;
|
|
399
|
+
text-underline-offset: 0.16em;
|
|
400
|
+
}
|
|
401
|
+
.site-footer-github {
|
|
402
|
+
width: 2.2rem;
|
|
403
|
+
height: 2.2rem;
|
|
404
|
+
justify-content: center;
|
|
405
|
+
border-radius: 999px;
|
|
406
|
+
color: var(--canvas-muted);
|
|
407
|
+
}
|
|
408
|
+
.site-footer-github:hover {
|
|
409
|
+
background: var(--site-surface-hover);
|
|
410
|
+
color: var(--canvas-text);
|
|
411
|
+
}
|
|
412
|
+
.site-footer-github .github-square-icon {
|
|
413
|
+
width: 1.45rem;
|
|
414
|
+
height: 1.45rem;
|
|
415
|
+
}
|
|
393
416
|
@media (max-width: 760px) {
|
|
394
417
|
.site-nav-wrap {
|
|
395
|
-
width:
|
|
418
|
+
width: auto;
|
|
419
|
+
max-width: 100%;
|
|
396
420
|
box-sizing: border-box;
|
|
397
421
|
padding: 0.75rem 0.5rem 0.45rem;
|
|
398
422
|
}
|
|
399
423
|
.site-navbar {
|
|
424
|
+
position: relative;
|
|
400
425
|
display: flex;
|
|
401
426
|
flex-wrap: nowrap;
|
|
402
427
|
width: 100%;
|
|
@@ -406,24 +431,32 @@ body {
|
|
|
406
431
|
align-items: center;
|
|
407
432
|
gap: 0.25rem;
|
|
408
433
|
padding: 0.35rem;
|
|
434
|
+
overflow: visible;
|
|
409
435
|
}
|
|
410
436
|
.site-brand {
|
|
411
437
|
flex: 0 1 auto;
|
|
412
438
|
min-width: 0;
|
|
439
|
+
max-width: calc(100% - 5.45rem);
|
|
413
440
|
padding: 0 0.65rem;
|
|
414
441
|
justify-content: flex-start;
|
|
415
442
|
}
|
|
443
|
+
.site-brand > span {
|
|
444
|
+
min-width: 0;
|
|
445
|
+
overflow: hidden;
|
|
446
|
+
text-overflow: ellipsis;
|
|
447
|
+
}
|
|
416
448
|
.site-nav-links {
|
|
417
|
-
|
|
418
|
-
width: auto;
|
|
419
|
-
overflow: visible;
|
|
420
|
-
padding: 0;
|
|
449
|
+
display: none;
|
|
421
450
|
}
|
|
422
451
|
.site-nav-actions {
|
|
452
|
+
position: static;
|
|
453
|
+
transform: none;
|
|
423
454
|
flex: 0 0 auto;
|
|
424
455
|
width: auto;
|
|
456
|
+
min-width: 0;
|
|
425
457
|
justify-content: flex-end;
|
|
426
|
-
margin-left:
|
|
458
|
+
margin-left: auto;
|
|
459
|
+
z-index: auto;
|
|
427
460
|
}
|
|
428
461
|
.site-resource-link {
|
|
429
462
|
width: 2.45rem;
|
|
@@ -725,6 +758,8 @@ body {
|
|
|
725
758
|
border-radius: var(--radius-card);
|
|
726
759
|
border: 1px solid var(--border);
|
|
727
760
|
padding: 0.9rem;
|
|
761
|
+
scrollbar-width: none;
|
|
762
|
+
-ms-overflow-style: none;
|
|
728
763
|
}
|
|
729
764
|
@media (min-width: 1024px) {
|
|
730
765
|
.deck-sidebar {
|
|
@@ -750,6 +785,12 @@ body {
|
|
|
750
785
|
display: flex;
|
|
751
786
|
flex-direction: column;
|
|
752
787
|
gap: 0.6rem;
|
|
788
|
+
scrollbar-width: none;
|
|
789
|
+
-ms-overflow-style: none;
|
|
790
|
+
}
|
|
791
|
+
.deck-sidebar::-webkit-scrollbar,
|
|
792
|
+
.deck-slide-list::-webkit-scrollbar {
|
|
793
|
+
display: none;
|
|
753
794
|
}
|
|
754
795
|
@media (max-width: 1023px) {
|
|
755
796
|
.deck-slide-list {
|
|
@@ -760,11 +801,6 @@ body {
|
|
|
760
801
|
padding-bottom: 0.4rem;
|
|
761
802
|
scrollbar-color: var(--fg-dim) transparent;
|
|
762
803
|
}
|
|
763
|
-
.deck-slide-list::-webkit-scrollbar { height: 6px; }
|
|
764
|
-
.deck-slide-list::-webkit-scrollbar-thumb {
|
|
765
|
-
background: var(--fg-dim);
|
|
766
|
-
border-radius: 4px;
|
|
767
|
-
}
|
|
768
804
|
.deck-slide-list > li {
|
|
769
805
|
flex: 0 0 220px;
|
|
770
806
|
scroll-snap-align: start;
|
|
@@ -1329,6 +1365,10 @@ body {
|
|
|
1329
1365
|
.sidenote-ref::before { content: "["; }
|
|
1330
1366
|
.sidenote-ref::after { content: "]"; }
|
|
1331
1367
|
.sidenote-ref:hover { background: rgba(138, 90, 0, 0.12); }
|
|
1368
|
+
.sidenote-ref[role="button"]:focus-visible {
|
|
1369
|
+
outline: 2px solid var(--notes-accent);
|
|
1370
|
+
outline-offset: 2px;
|
|
1371
|
+
}
|
|
1332
1372
|
|
|
1333
1373
|
.sidenote {
|
|
1334
1374
|
display: block;
|
|
@@ -1372,6 +1412,91 @@ body {
|
|
|
1372
1412
|
}
|
|
1373
1413
|
}
|
|
1374
1414
|
|
|
1415
|
+
.sidenote-popover {
|
|
1416
|
+
position: fixed;
|
|
1417
|
+
inset: 0;
|
|
1418
|
+
z-index: 120;
|
|
1419
|
+
opacity: 0;
|
|
1420
|
+
pointer-events: none;
|
|
1421
|
+
transition: opacity 170ms ease;
|
|
1422
|
+
}
|
|
1423
|
+
.sidenote-popover.is-open {
|
|
1424
|
+
opacity: 1;
|
|
1425
|
+
pointer-events: auto;
|
|
1426
|
+
}
|
|
1427
|
+
.sidenote-popover-backdrop {
|
|
1428
|
+
position: absolute;
|
|
1429
|
+
inset: 0;
|
|
1430
|
+
border: 0;
|
|
1431
|
+
background: rgba(8, 10, 12, 0.58);
|
|
1432
|
+
backdrop-filter: blur(8px);
|
|
1433
|
+
}
|
|
1434
|
+
.sidenote-popover-sheet {
|
|
1435
|
+
position: absolute;
|
|
1436
|
+
left: max(0.75rem, env(safe-area-inset-left));
|
|
1437
|
+
right: max(0.75rem, env(safe-area-inset-right));
|
|
1438
|
+
bottom: max(0.75rem, env(safe-area-inset-bottom));
|
|
1439
|
+
max-height: min(70vh, 32rem);
|
|
1440
|
+
display: flex;
|
|
1441
|
+
flex-direction: column;
|
|
1442
|
+
overflow: hidden;
|
|
1443
|
+
border: 1px solid var(--notes-rule);
|
|
1444
|
+
border-radius: 8px;
|
|
1445
|
+
background: var(--notes-bg);
|
|
1446
|
+
color: var(--notes-fg);
|
|
1447
|
+
box-shadow: 0 26px 80px -32px rgba(0, 0, 0, 0.65);
|
|
1448
|
+
transform: translateY(1rem);
|
|
1449
|
+
transition: transform 190ms ease;
|
|
1450
|
+
}
|
|
1451
|
+
.sidenote-popover.is-open .sidenote-popover-sheet {
|
|
1452
|
+
transform: translateY(0);
|
|
1453
|
+
}
|
|
1454
|
+
.sidenote-popover-header {
|
|
1455
|
+
display: flex;
|
|
1456
|
+
align-items: center;
|
|
1457
|
+
justify-content: space-between;
|
|
1458
|
+
gap: 0.75rem;
|
|
1459
|
+
padding: 0.75rem 0.9rem;
|
|
1460
|
+
border-bottom: 1px solid var(--notes-rule);
|
|
1461
|
+
font-family: var(--font-sans);
|
|
1462
|
+
color: var(--notes-accent);
|
|
1463
|
+
font-size: 0.78rem;
|
|
1464
|
+
font-weight: 900;
|
|
1465
|
+
text-transform: uppercase;
|
|
1466
|
+
letter-spacing: 0;
|
|
1467
|
+
}
|
|
1468
|
+
.sidenote-popover-close {
|
|
1469
|
+
width: 2rem;
|
|
1470
|
+
height: 2rem;
|
|
1471
|
+
display: inline-flex;
|
|
1472
|
+
align-items: center;
|
|
1473
|
+
justify-content: center;
|
|
1474
|
+
border: 1px solid var(--notes-rule);
|
|
1475
|
+
border-radius: 999px;
|
|
1476
|
+
background: var(--notes-sidenote-bg);
|
|
1477
|
+
color: var(--notes-fg);
|
|
1478
|
+
font-family: var(--font-sans);
|
|
1479
|
+
font-size: 1rem;
|
|
1480
|
+
font-weight: 900;
|
|
1481
|
+
line-height: 1;
|
|
1482
|
+
cursor: pointer;
|
|
1483
|
+
}
|
|
1484
|
+
.sidenote-popover-content {
|
|
1485
|
+
overflow: auto;
|
|
1486
|
+
padding: 0.95rem 1rem 1.05rem;
|
|
1487
|
+
font-family: var(--font-sans);
|
|
1488
|
+
font-size: 0.95rem;
|
|
1489
|
+
line-height: 1.55;
|
|
1490
|
+
color: var(--notes-fg-soft);
|
|
1491
|
+
text-align: left;
|
|
1492
|
+
hyphens: manual;
|
|
1493
|
+
}
|
|
1494
|
+
.sidenote-popover-content > :first-child { margin-top: 0; }
|
|
1495
|
+
.sidenote-popover-content > :last-child { margin-bottom: 0; }
|
|
1496
|
+
body.sidenote-popover-open {
|
|
1497
|
+
overflow: hidden;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1375
1500
|
/* ------------------------------------------------------------------ */
|
|
1376
1501
|
/* Facelift overrides */
|
|
1377
1502
|
/* ------------------------------------------------------------------ */
|
|
@@ -1615,9 +1740,13 @@ body {
|
|
|
1615
1740
|
background: var(--site-bg);
|
|
1616
1741
|
transition: filter 180ms ease;
|
|
1617
1742
|
}
|
|
1618
|
-
.deck-grid.is-
|
|
1619
|
-
.deck-grid.is-
|
|
1620
|
-
|
|
1743
|
+
.deck-grid.is-light-preview .deck-viewer-frame,
|
|
1744
|
+
.deck-grid.is-light-preview .deck-slide-thumb {
|
|
1745
|
+
background: #f4f4f4;
|
|
1746
|
+
}
|
|
1747
|
+
.deck-grid.is-light-preview .deck-iframe,
|
|
1748
|
+
.deck-grid.is-light-preview .deck-slide-thumb img {
|
|
1749
|
+
filter: invert(1) hue-rotate(180deg) saturate(0.9) contrast(0.96) brightness(1.08);
|
|
1621
1750
|
}
|
|
1622
1751
|
.deck-controls {
|
|
1623
1752
|
justify-content: space-between;
|
|
@@ -1698,7 +1827,7 @@ body {
|
|
|
1698
1827
|
.deck-settings-panel {
|
|
1699
1828
|
position: absolute;
|
|
1700
1829
|
right: 0;
|
|
1701
|
-
|
|
1830
|
+
bottom: calc(100% + 0.45rem);
|
|
1702
1831
|
z-index: 50;
|
|
1703
1832
|
width: 15rem;
|
|
1704
1833
|
padding: 0.45rem;
|
|
@@ -1706,6 +1835,7 @@ body {
|
|
|
1706
1835
|
border-radius: 8px;
|
|
1707
1836
|
background: var(--site-surface-solid);
|
|
1708
1837
|
box-shadow: var(--shadow-card);
|
|
1838
|
+
transform-origin: bottom right;
|
|
1709
1839
|
}
|
|
1710
1840
|
.deck-setting-row {
|
|
1711
1841
|
display: flex;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* Tailwind CSS v4 source for the Simplex portal.
|
|
2
|
+
*
|
|
3
|
+
* Compiled to `tailwind.css` (gitignored) by `simplex.web.vendor` at build
|
|
4
|
+
* time using the v4 standalone CLI. Sources below are scanned for class
|
|
5
|
+
* names; only the utilities actually used in the templates end up in the
|
|
6
|
+
* output, so the shipped stylesheet stays tiny.
|
|
7
|
+
*
|
|
8
|
+
* To add new sources (e.g. user-deck HTML), append more `@source` lines.
|
|
9
|
+
* Theme tweaks belong in a `@theme { ... }` block here -- not in a
|
|
10
|
+
* `tailwind.config.js`, which v4 has replaced with CSS-first config.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
@import "tailwindcss";
|
|
14
|
+
|
|
15
|
+
@source "../templates/**/*.html";
|
|
16
|
+
@source "../templates/**/*.j2";
|