Spaces:
Sleeping
Sleeping
| """ | |
| layout/page/page_callbacks.py | |
| ------------------------------ | |
| 頁面級 Dash callback。 | |
| callback 定義在 module 層級,import 即生效。 | |
| register_page_callbacks() 保留為空殼供相容呼叫。 | |
| """ | |
| from __future__ import annotations | |
| import hashlib, json | |
| from dash import callback, Input, Output, State, ALL, ctx, no_update | |
| from ..renderer.renderer import render_doc | |
| from .sections import get_section_blocks | |
| from .loader import build_toc_titles | |
| from ..toc import make_toc | |
| # render_doc 結果快取(key = section blocks 的 hash) | |
| _render_cache: dict[str, object] = {} | |
| def _cached_render(blocks: list) -> object: | |
| """同樣的 blocks 只渲染一次。""" | |
| try: | |
| key = hashlib.md5( | |
| json.dumps(blocks, ensure_ascii=False, sort_keys=True).encode() | |
| ).hexdigest() | |
| except Exception: | |
| return render_doc(blocks) | |
| if key not in _render_cache: | |
| _render_cache[key] = render_doc(blocks) | |
| return _render_cache[key] | |
| # ------------------------------------------------------------------ | |
| # Callback 1:切換 section → 更新內容 + TOC + Grid 欄寬 | |
| # ------------------------------------------------------------------ | |
| def _cb_switch_section(_, sections, raw_toc): | |
| if not sections: | |
| return (no_update,) * 6 | |
| trig = ctx.triggered_id | |
| if not trig: | |
| return (no_update,) * 6 | |
| section_id = trig.get("sid") | |
| current_blocks = get_section_blocks(sections, section_id) | |
| content = _cached_render(current_blocks) | |
| if section_id == "sec-all": | |
| toc_titles = build_toc_titles(current_blocks, raw_toc or []) | |
| toc_component = ( | |
| make_toc( | |
| titles=toc_titles, | |
| top_offset=90, | |
| col_span={"xs": 0, "sm": 0, "md": 3, "lg": 3, "xl": 3}, | |
| visible_from="md", | |
| ) | |
| if toc_titles | |
| else None | |
| ) | |
| return ( | |
| content, | |
| toc_component, | |
| {"base": 12, "md": 9}, | |
| {"base": 12, "md": 3}, | |
| {"display": "block"}, | |
| section_id, | |
| ) | |
| return ( | |
| content, | |
| None, | |
| {"base": 12, "md": 12}, | |
| {"base": 12, "md": 0}, | |
| {"display": "none"}, | |
| section_id, | |
| ) | |
| # ------------------------------------------------------------------ | |
| # Callback 2:同步 section 按鈕的 active 樣式 | |
| # ------------------------------------------------------------------ | |
| def _cb_highlight_section_buttons(active_sid, sections): | |
| if not sections: | |
| return [], [] | |
| variants, colors = [], [] | |
| for s in sections: | |
| sid = s.get("id") or "" | |
| is_active = sid == active_sid | |
| variants.append("filled" if is_active else "light") | |
| colors.append("blue" if is_active else "gray") | |
| return variants, colors | |
| # ------------------------------------------------------------------ | |
| # 相容 shim:讓舊的 register_page_callbacks() 呼叫不報錯 | |
| # ------------------------------------------------------------------ | |
| def register_page_callbacks() -> None: | |
| """Callbacks 在 import 時已全部掛載,此函式保留供舊版呼叫。""" | |
| pass | |