Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pixi.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 35 additions & 8 deletions src/ewoksdraw/svg/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,42 @@
from xml.etree.ElementTree import Element

CSS_DIR = Path(__file__).parent.parent / "css_styles"
ROOT_CSS_PATH = CSS_DIR / "root.css"


def generate_style_element(css_file_name: str) -> None | Element:
css_file_path = CSS_DIR / css_file_name
if not css_file_path.exists():
return None

with open(css_file_path, "r") as css_file:
css_content = css_file.read()
def generate_style_element(css_file_name: str) -> Element:
css = (CSS_DIR / css_file_name).read_text()
css_with_fallback = _add_css_variable_fallback(css)
style = Element("style")
style.text = f"<![CDATA[\n{css_content}\n]]>"
style.text = f"<![CDATA[\n{css_with_fallback}\n]]>"
return style


def _add_css_variable_fallback(css: str) -> str:

if "var(" not in css:
return css

theme_values = _read_theme_values()
css_with_plain_values = _replace_css_variables(css, theme_values)
original_css_if_supported = f"@supports (--css: variables) {{\n{css}\n}}"
return f"{css_with_plain_values}\n{original_css_if_supported}"


def _read_theme_values() -> dict[str, str]:
"""Read root.css into {"--link-color": "rgb(176, 147, 255)", ...}."""
root_css = ROOT_CSS_PATH.read_text()
theme_values: dict[str, str] = {}
for line in root_css.splitlines():
declaration = line.strip().removesuffix(";")
if declaration.startswith("--"):
name, value = declaration.split(": ")
theme_values[name] = value
return theme_values


def _replace_css_variables(css: str, theme_values: dict[str, str]) -> str:
"""Replace each "var(--link-color)" by its value, e.g. "rgb(176, 147, 255)"."""
for name, value in theme_values.items():
css = css.replace(f"var({name})", value)
return css
Comment on lines +27 to +43

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure all of that can be done with a combination of regex/lambda functions and other Python chicanery in 3 lines of code.
This version I understand.

63 changes: 63 additions & 0 deletions src/ewoksdraw/tests/test_svg_css_variables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from pathlib import Path

import pytest

from ewoksdraw.svg import utils


@pytest.fixture
def css_dir(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
(tmp_path / "root.css").write_text(
".ewoksdraw {\n"
" --link-color: #b093ff;\n"
" --stroke-color: #ffffff;\n"
" --error: #ff0000;\n"
"}\n"
)
monkeypatch.setattr(utils, "ROOT_CSS_PATH", tmp_path / "root.css")
return tmp_path


def test_variable_generates_fallback_and_supports(css_dir: Path) -> None:
result = utils._add_css_variable_fallback(".anchor { fill: var(--link-color); }")

assert " ".join(result.split()) == (
".anchor { fill: #b093ff; } "
"@supports (--css: variables) { "
".anchor { fill: var(--link-color); } }"
)


def test_css_without_variables_is_unchanged(css_dir: Path) -> None:
css = ".anchor {\n fill: purple;\n stroke-width: 2;\n}\n"

assert utils._add_css_variable_fallback(css) == css


def test_multiple_variables_are_replaced(css_dir: Path) -> None:
result = utils._add_css_variable_fallback(
".anchor { fill: var(--link-color); "
"stroke: var(--stroke-color); stroke-width: 2; }"
)

assert " ".join(result.split()) == (
".anchor { fill: #b093ff; stroke: #ffffff; stroke-width: 2; } "
"@supports (--css: variables) { "
".anchor { fill: var(--link-color); "
"stroke: var(--stroke-color); stroke-width: 2; } }"
)


def test_import_error_rule_stays_after_normal_rule(css_dir: Path) -> None:
result = utils._add_css_variable_fallback(
".task_box { stroke: var(--stroke-color); }\n"
".task_box[data-import-error=''] { stroke: var(--error); }"
)

assert " ".join(result.split()) == (
".task_box { stroke: #ffffff; } "
".task_box[data-import-error=''] { stroke: #ff0000; } "
"@supports (--css: variables) { "
".task_box { stroke: var(--stroke-color); } "
".task_box[data-import-error=''] { stroke: var(--error); } }"
)
4 changes: 2 additions & 2 deletions src/ewoksdraw/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
from ..utils import get_task_id_from_target_id


def test_edge_source_task_id_roundtrip():
def test_edge_source_task_id_roundtrip() -> None:
task_id = "pipeline.output.normalize"
output_name = "value"

source_id = get_edge_source_id(task_id, output_name)
assert get_task_id_from_source_id(source_id) == task_id


def test_edge_target_task_id_roundtrip():
def test_edge_target_task_id_roundtrip() -> None:
task_id = "pipeline.input.normalize"
output_name = "value"

Expand Down
Loading