Spaces:
Sleeping
Sleeping
| """ | |
| components/render_utils.py | |
| -------------------------- | |
| 純渲染工具函式,不依賴任何 Dash callback 或 app 狀態。 | |
| 供 cards.py、dashTest.py(未來統一後)等元件共用。 | |
| 公開 API: | |
| _inline_math(latex, style=None) → Dash element | |
| _block_math(latex, style=None) → Dash element | |
| _runs_to_children(runs) → List[Dash element] | |
| """ | |
| from __future__ import annotations | |
| from typing import Any | |
| from dash import html, dcc | |
| import dash_mantine_components as dmc | |
| try: | |
| from dash_latex import DashLatex | |
| except Exception: | |
| DashLatex = None | |
| # --------------------------------------------------------------------------- | |
| # 數學渲染 | |
| # --------------------------------------------------------------------------- | |
| def _inline_math(latex: str, style: dict | None = None) -> Any: | |
| """行內數學式。優先使用 DashLatex(KaTeX),退回 dcc.Markdown MathJax。""" | |
| merged = {"display": "inline-block", "margin": "0 2px", **(style or {})} | |
| if DashLatex: | |
| return html.Span(DashLatex(latex, displayMode=False), style=merged) | |
| src = latex if latex.strip().startswith("$") else f"${latex}$" | |
| return dcc.Markdown(src, mathjax=True, style=merged) | |
| def _block_math(latex: str, style: dict | None = None) -> Any: | |
| """區塊數學式。優先使用 DashLatex(KaTeX),退回 dcc.Markdown MathJax。""" | |
| merged = {"margin": "8px 0", **(style or {})} | |
| if DashLatex: | |
| return html.Div(DashLatex(latex, displayMode=True), style=merged) | |
| src = latex.strip() | |
| if not (src.startswith("$$") and src.endswith("$$")): | |
| src = f"$$\n{src}\n$$" | |
| return dcc.Markdown(src, mathjax=True, style=merged) | |
| # --------------------------------------------------------------------------- | |
| # Run 列表轉 Dash 元素 | |
| # --------------------------------------------------------------------------- | |
| def _runs_to_children(runs: list[dict] | None) -> list[Any]: | |
| """ | |
| 把 JSON block 中的 runs 陣列轉成 Dash 子元素清單。 | |
| Run 格式: | |
| {"kind": "math", "latex": "..."} → 行內數學 | |
| {"text": "...", "style": "bold|italic|bold-italic", | |
| "color_light": "#xxx", "color_dark": "#xxx"} → 文字 span | |
| """ | |
| out: list[Any] = [] | |
| for r in runs or []: | |
| # 數學 run | |
| if r.get("kind") == "math" and "latex" in r: | |
| out.append(_inline_math(r["latex"])) | |
| continue | |
| # 文字 run | |
| sty: dict[str, Any] = {} | |
| s = r.get("style", "") | |
| if s == "bold": | |
| sty["fontWeight"] = 700 | |
| elif s == "italic": | |
| sty["fontStyle"] = "italic" | |
| elif s == "bold-italic": | |
| sty.update({"fontWeight": 700, "fontStyle": "italic"}) | |
| # 主題雙色(light / dark) | |
| cls = None | |
| if r.get("color_light") or r.get("color_dark"): | |
| if r.get("color_light"): | |
| sty["--tc-light"] = r["color_light"] | |
| if r.get("color_dark"): | |
| sty["--tc-dark"] = r["color_dark"] | |
| sty["color"] = "var(--tc, var(--tc-light))" | |
| cls = "themed-color" | |
| out.append(html.Span(r.get("text", ""), style=sty, className=cls)) | |
| return out | |