aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/ParksTable.astro222
1 files changed, 0 insertions, 222 deletions
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;