diff options
| author | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-10-03 14:55:04 +0900 |
|---|---|---|
| committer | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-10-03 14:55:04 +0900 |
| commit | 27483644d7ba9e819dbb5f64844270dd499f45ff (patch) | |
| tree | 9a82bfc89df4a8be267e3dd06e602e8b98fd6090 /src/components/SanpiTable.astro | |
| parent | c23c8fb5c547540c0705bef900340c9a6e358126 (diff) | |
sanpi.mdx: 賛否一覧表の列を整理し、スマホで読みやすくする
安竹洋平・伊藤央・石津はるかの列を議決結果の右にまとめ、水口かずえ・中倉茂和・岡田しんぺいの氏名は外して会派名だけにした。安竹の列はセル全体に色を付ける。スマホでは表を横スクロールにし、議案名は省略表示+ホバー/タップで全文表示とした。生成側の scripts/parse-sanpi-hyo.py も同じ並び・氏名なしで出力するよう修正した。
Diffstat (limited to 'src/components/SanpiTable.astro')
| -rw-r--r-- | src/components/SanpiTable.astro | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/src/components/SanpiTable.astro b/src/components/SanpiTable.astro new file mode 100644 index 0000000..31c8678 --- /dev/null +++ b/src/components/SanpiTable.astro @@ -0,0 +1,96 @@ +--- +// 賛否一覧(/sanpi/)の表をスマートフォンでも読みやすくする。 +// 表そのものは Markdown で書かれているため、ここでは目印の要素と、 +// 実行時に表を加工するスクリプトだけを提供する(見た目は custom.css)。 +--- + +<div class="sanpi-marker" hidden aria-hidden="true"></div> + +<script> + // マウスがある環境でのみホバー表示を有効にする(タップ端末では + // タップがホバーとして扱われ、ツールチップが残るのを避けるため)。 + const CAN_HOVER = window.matchMedia("(hover: hover) and (pointer: fine)").matches; + + function enhanceSanpiTables() { + const marker = document.querySelector(".sanpi-marker"); + if (!marker) return; + const content = marker.closest(".sl-markdown-content"); + if (!content) return; + + let tip = null; + const hideTip = () => { + if (tip) tip.hidden = true; + }; + const showTip = (el) => { + if (!tip) { + tip = document.createElement("div"); + tip.className = "sanpi-tip"; + tip.setAttribute("role", "tooltip"); + document.body.appendChild(tip); + } + tip.textContent = el.dataset.full || el.textContent.trim(); + tip.hidden = false; + tip.style.left = "0px"; + tip.style.top = "0px"; + const r = el.getBoundingClientRect(); + const tr = tip.getBoundingClientRect(); + const left = Math.min( + Math.max(8, r.left), + Math.max(8, window.innerWidth - tr.width - 8), + ); + let top = r.top - tr.height - 8; + if (top < 8) top = r.bottom + 8; + tip.style.left = `${left}px`; + tip.style.top = `${top}px`; + }; + + content.querySelectorAll("table").forEach((table) => { + // 各行の先頭セル(議案名)を、省略表示できるようにくるむ。 + table.querySelectorAll("tbody tr").forEach((tr) => { + const cell = tr.querySelector("td"); + if (!cell || cell.querySelector(".sanpi-title")) return; + + const span = document.createElement("span"); + span.className = "sanpi-title"; + while (cell.firstChild) span.appendChild(cell.firstChild); + cell.appendChild(span); + + const full = span.textContent.trim(); + span.dataset.full = full; + span.tabIndex = 0; + span.setAttribute("role", "button"); + span.setAttribute("aria-expanded", "false"); + span.setAttribute("aria-label", `${full}(タップで全文を表示)`); + + const toggle = () => { + hideTip(); + const open = cell.classList.toggle("sanpi-open"); + span.setAttribute("aria-expanded", String(open)); + }; + + if (CAN_HOVER) { + span.addEventListener("mouseenter", () => showTip(span)); + span.addEventListener("mouseleave", hideTip); + span.addEventListener("focus", () => showTip(span)); + span.addEventListener("blur", hideTip); + } + span.addEventListener("click", toggle); + span.addEventListener("keydown", (event) => { + if (event.key === "Enter" || event.key === " ") { + event.preventDefault(); + toggle(); + } + }); + }); + }); + + window.addEventListener("scroll", hideTip, { passive: true }); + window.addEventListener("resize", hideTip); + } + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", enhanceSanpiTables); + } else { + enhanceSanpiTables(); + } +</script> |
