diff options
| author | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-10-19 11:01:55 +0900 |
|---|---|---|
| committer | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-10-19 11:01:55 +0900 |
| commit | 9228e0a428cfa446aed6eda9b56243ed66b4a1ba (patch) | |
| tree | f70f786d45f6a9fd6eff342a97aaab0d513350b6 | |
| parent | 42c0308bd508b48a6c85e682485824b0d6bc370b (diff) | |
parks: 画像保存ボタンの追加を取り消す
| -rw-r--r-- | package-lock.json | 7 | ||||
| -rw-r--r-- | package.json | 1 | ||||
| -rw-r--r-- | src/components/ParksTable.astro | 222 |
3 files changed, 0 insertions, 230 deletions
diff --git a/package-lock.json b/package-lock.json index 07802f6..3962026 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,6 @@ "@fontsource/noto-sans-jp": "^5.2.9", "@resvg/resvg-js": "^2.6.2", "astro": "^7.3.5", - "html-to-image": "^1.11.13", "leaflet": "^1.9.4", "mammoth": "^1.12.0", "playwright": "^1.60.0", @@ -8010,12 +8009,6 @@ "dev": true, "license": "ISC" }, - "node_modules/html-to-image": { - "version": "1.11.13", - "resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-1.11.13.tgz", - "integrity": "sha512-cuOPoI7WApyhBElTTb9oqsawRvZ0rHhaHwghRLlTuffoD1B2aDemlCruLeZrUIIdvG7gs9xeELEPm6PhuASqrg==", - "license": "MIT" - }, "node_modules/html-void-elements": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", diff --git a/package.json b/package.json index 3d29c41..4cd1a43 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,6 @@ "@fontsource/noto-sans-jp": "^5.2.9", "@resvg/resvg-js": "^2.6.2", "astro": "^7.3.5", - "html-to-image": "^1.11.13", "leaflet": "^1.9.4", "mammoth": "^1.12.0", "playwright": "^1.60.0", diff --git a/src/components/ParksTable.astro b/src/components/ParksTable.astro index e5def82..6f8fdbd 100644 --- a/src/components/ParksTable.astro +++ b/src/components/ParksTable.astro @@ -204,11 +204,9 @@ const total = parks.length; <label><input type="checkbox" data-fac-filter value="ball" />ボール遊び</label> <label><input type="checkbox" data-fac-filter value="cm" />指定管理</label> </fieldset> - <button type="button" class="parks-save" data-parks-save-image>画像で保存</button> <span class="parks-count" data-parks-count aria-live="polite">{total}件</span> </div> <p class="parks-hint">設備の情報は、市の資料などに基づきます。設備で絞ると、この情報がある公園だけが対象になります。</p> - <p class="parks-save-status" data-parks-save-status aria-live="polite"></p> <p class="parks-none" data-parks-none hidden>条件に合う公園が見つかりませんでした。</p> <div class="parks-scroll"> @@ -347,85 +345,6 @@ const total = parks.length; font-size: 0.9rem; opacity: 0.75; } - .parks-save { - padding: 0.35rem 0.7rem; - border: 1px solid var(--sl-color-hairline, #ccc); - border-radius: 0.35rem; - background: var(--sl-color-bg, #fff); - color: var(--sl-color-text, inherit); - font: inherit; - font-size: 0.85rem; - cursor: pointer; - } - .parks-save:hover { - border-color: var(--sl-color-text-accent, #4c8); - } - .parks-save:disabled { - opacity: 0.6; - cursor: wait; - } - .parks-save-status { - margin: 0 0 0.6rem; - font-size: 0.8rem; - opacity: 0.8; - } - .parks-save-status:empty { - display: none; - } - /* 画像保存用のオフスクリーン領域。サイトの表スタイルをそのまま使う。 */ - .parks-capture { - position: fixed; - left: 0; - top: 0; - z-index: -1; - pointer-events: none; - width: max-content; - padding: 24px 28px; - background: #fff; - color: #1a1a1a; - color-scheme: light; - --sl-color-text: #1a1a1a; - --sl-color-bg: #ffffff; - --sl-color-hairline: #dddddd; - --sl-color-gray-4: #888888; - --sl-color-gray-6: #eef1f3; - --sl-color-white: #1a1a1a; - --sl-color-text-accent: #0b7a4b; - } - .parks-capture-head { - display: flex; - align-items: baseline; - gap: 0.8rem; - margin-bottom: 0.2rem; - } - .parks-capture-head strong { - font-size: 1.35rem; - } - .parks-capture-head span { - font-size: 0.9rem; - opacity: 0.75; - } - .parks-capture-meta { - margin-bottom: 0.7rem; - font-size: 0.8rem; - opacity: 0.75; - } - .parks-capture table { - width: max-content; - } - .parks-capture thead th { - position: static; - background: #eef1f3; - color: #1a1a1a; - } - .parks-capture tbody td { - color: #1a1a1a; - } - .parks-capture-foot { - margin-top: 0.7rem; - font-size: 0.72rem; - opacity: 0.65; - } .parks-hint, .parks-none { margin: 0 0 0.6rem; @@ -674,8 +593,6 @@ const total = parks.length; </style> <script> - import { toPng } from "html-to-image"; - document.querySelectorAll("[data-parks]").forEach((root) => { const select = root.querySelector<HTMLSelectElement>("[data-parks-town]"); const search = root.querySelector<HTMLInputElement>("[data-parks-search]"); @@ -696,145 +613,6 @@ const total = parks.length; const allRows = () => Array.from(tbody.querySelectorAll<HTMLTableRowElement>("tr")); const total = allRows().length; - const saveButton = root.querySelector<HTMLButtonElement>("[data-parks-save-image]"); - const saveStatus = root.querySelector<HTMLElement>("[data-parks-save-status]"); - const MAX_IMAGE_ROWS = 30; - // AstroのスコープCSSを動的生成要素にも当てる(ダークテーマの色を上書きするため)。 - const scopeClass = Array.from(root.classList).find((cls) => cls.startsWith("astro-")); - const withScope = <T extends HTMLElement>(el: T): T => { - if (scopeClass) el.classList.add(scopeClass); - return el; - }; - - const saveTableImage = async () => { - if (!saveButton) return; - const visible = allRows().filter((row) => !row.classList.contains("is-hidden")); - if (!visible.length) { - if (saveStatus) saveStatus.textContent = "表示中の公園がありません。"; - return; - } - const table = root.querySelector("table"); - if (!table) return; - - saveButton.disabled = true; - if (saveStatus) saveStatus.textContent = "画像を作成中…"; - let wrap: HTMLDivElement | null = null; - try { - const limited = visible.slice(0, MAX_IMAGE_ROWS); - const clone = table.cloneNode(true) as HTMLTableElement; - const cloneBody = clone.querySelector("tbody"); - if (cloneBody) { - cloneBody.innerHTML = ""; - limited.forEach((row) => cloneBody.appendChild(row.cloneNode(true))); - } - - // ボタン・リンクは画像内では文字だけにする。 - clone.querySelectorAll("button").forEach((btn) => { - const span = document.createElement("span"); - span.textContent = (btn.textContent || "").trim(); - btn.replaceWith(span); - }); - clone.querySelectorAll("a").forEach((link) => { - const span = document.createElement("span"); - span.textContent = (link.textContent || "").trim(); - link.replaceWith(span); - }); - - // 設備アイコンはCSSの擬似要素なので、画像では絵文字を直接入れる。 - const icons: Record<string, string> = { - toilet: "🚻", - water: "🚰", - toy: "🎠", - ball: "⚽", - cm: "🏛", - pergola: "🌿", - azumaya: "🛖", - }; - clone.querySelectorAll<HTMLElement>(".fac-badge").forEach((badge) => { - for (const [kind, icon] of Object.entries(icons)) { - if (badge.classList.contains(`fac-${kind}`)) { - badge.textContent = icon; - break; - } - } - }); - - wrap = document.createElement("div"); - wrap.className = "parks parks-capture"; - withScope(wrap); - const head = document.createElement("div"); - head.className = "parks-capture-head"; - withScope(head); - const title = document.createElement("strong"); - title.textContent = "小平市の公園一覧"; - withScope(title); - const countLabel = document.createElement("span"); - countLabel.textContent = `${limited.length}件${ - visible.length > MAX_IMAGE_ROWS - ? `(表示中${visible.length}件の先頭${MAX_IMAGE_ROWS}件)` - : "" - }`; - withScope(countLabel); - head.append(title, countLabel); - - const meta = document.createElement("div"); - meta.className = "parks-capture-meta"; - withScope(meta); - const parts: string[] = []; - if (select?.value) parts.push(`町名: ${select.value}`); - if (search?.value.trim()) parts.push(`キーワード: ${search.value.trim()}`); - const facLabels = checks - .filter((c) => c.checked) - .map((c) => (c.parentElement?.textContent || "").trim()) - .filter(Boolean); - if (facLabels.length) parts.push(`設備: ${facLabels.join("・")}`); - if (sortKey) { - parts.push( - `並べ替え: ${sortKey === "area" ? "面積" : "公園名"} ${ - sortDir === 1 ? "昇順" : "降順" - }`, - ); - } - meta.textContent = parts.length ? parts.join(" / ") : "すべての公園"; - - const foot = document.createElement("div"); - foot.className = "parks-capture-foot"; - withScope(foot); - foot.textContent = `yasutakeyohei.com/kodaira-data/parks/ ・ ${new Date().toLocaleDateString( - "ja-JP", - )}時点`; - - wrap.append(head, meta, clone, foot); - document.body.appendChild(wrap); - - const dataUrl = await toPng(wrap, { - pixelRatio: 2, - backgroundColor: "#ffffff", - cacheBust: true, - }); - - const link = document.createElement("a"); - link.download = `kodaira-parks-${new Date().toISOString().slice(0, 10)}.png`; - link.href = dataUrl; - link.click(); - if (saveStatus) - saveStatus.textContent = - visible.length > MAX_IMAGE_ROWS - ? `画像を保存しました(表示中${visible.length}件の先頭${MAX_IMAGE_ROWS}件)。` - : "画像を保存しました。"; - } catch (error) { - console.error(error); - if (saveStatus) saveStatus.textContent = "画像の作成に失敗しました。"; - } finally { - wrap?.remove(); - saveButton.disabled = false; - window.setTimeout(() => { - if (saveStatus) saveStatus.textContent = ""; - }, 5000); - } - }; - - saveButton?.addEventListener("click", saveTableImage); let sortKey: string | null = null; let sortDir = 1; |
