diff options
Diffstat (limited to 'src/components/ParksTable.astro')
| -rw-r--r-- | src/components/ParksTable.astro | 558 |
1 files changed, 364 insertions, 194 deletions
diff --git a/src/components/ParksTable.astro b/src/components/ParksTable.astro index 5b7f5ac..81a93e2 100644 --- a/src/components/ParksTable.astro +++ b/src/components/ParksTable.astro @@ -4,6 +4,7 @@ // DOM を抑えるため、設備は1セルにまとめ、アイコンは CSS の擬似要素で描く。 // 絞り込み・並べ替え・カード表示は利用者の端末で実行する。 import { parks, mappedNames, type Park } from "@/data/parks-rows"; +import { PARK_ICONS } from "@/data/park-icons"; const EMPTY = "—"; @@ -76,33 +77,6 @@ function ownerClass(owner: string): string { return "parks-owner--other"; } -// 設備バッジ(アイコンは CSS の ::before で描く)。 -type Badge = { kind: string; label: string; title: string }; -function facilityBadges(p: Park): Badge[] { - const badges: Badge[] = []; - if (p["トイレ"]) { - badges.push({ kind: "toilet", label: "トイレ", title: `トイレ: ${p["トイレ"]}` }); - } - if (p["水飲み場"]) { - badges.push({ kind: "water", label: "水飲み場", title: `水飲み場: ${p["水飲み場"]}` }); - } - if (p["給水"]) { - badges.push({ kind: "water", label: "給水", title: `給水: ${p["給水"]}` }); - } - if (p["遊具"]) { - badges.push({ kind: "toy", label: "遊具", title: `遊具: ${p["遊具"]}` }); - } - const ball = p["ボール遊び"]; - if (ball && ball !== "禁止") { - const label = ball.includes("一部") ? "ボール遊び一部可" : "ボール遊び可"; - badges.push({ kind: "ball", label, title: `ボール遊び: ${ball}` }); - } - if (p["南西部指定管理"]) { - badges.push({ kind: "cm", label: "指定管理", title: "南西部地域の指定管理公園" }); - } - return badges; -} - // スイング遊具・健康遊具の判定用 const SPRING_TOKENS = [ "スプリング", "スイング", "リトルポップ", "リンクミニ", "ルッキンロッキン", @@ -156,7 +130,11 @@ function facTokens(p: Park): string { if (play.includes("滑り台") || play.includes("滑台")) tokens.push("slide"); if (play.includes("複合遊具")) tokens.push("complex"); if (play.includes("バスケ")) tokens.push("basket"); - if ((p["シェルター等"] || "").trim()) tokens.push("shelter"); + // シェルター等の欄には、シェルター・東屋・パーゴラ・GTシェードが混在している。 + // 「東屋/シェルター」と「パーゴラ」を別々に絞れるよう、キーワードで分ける。 + const shelterText = (p["シェルター等"] || "").trim(); + if (/東屋|シェルター|シェード/.test(shelterText)) tokens.push("shelter"); + if (shelterText.includes("パーゴラ")) tokens.push("pergola"); if (HEALTH_TOKENS.some((token) => play.includes(token))) tokens.push("health"); if (hasSpecialToy(play)) tokens.push("special"); if (play.includes("幼児")) tokens.push("toddler"); @@ -167,26 +145,40 @@ function facTokens(p: Park): string { if (p["草地広場"]) tokens.push("picnic"); // 野外卓・縁台がある公園。 if ((p["野外卓"] || "").trim()) tokens.push("table"); + // 利用ルール(ボール遊び禁止の表示なし・犬禁止の表示なし)。 + // 「禁止」と記録されていない公園を対象にする(未記録も含む)。 + // 公共施設と市外の公園は利用ルールを調べていないので対象外。 + if (p["施設"] !== "1" && p["種別"] !== "市外") { + if (!/禁止/.test(p["ボール遊び"] || "")) tokens.push("ballok"); + if (!/禁止/.test(p["ペット"] || "")) tokens.push("dogok"); + } return tokens.join(" "); } -// 設備セルの補足テキスト(バッジで示した項目の詳細と、その他の項目)。 -// ラベル文字は使わず、アイコンで項目を示す。 -const DETAIL_FIELDS: { key: string; icon: string }[] = [ - { key: "ベンチ・椅子", icon: "🪑" }, - { key: "野外卓", icon: "🍽" }, - { key: "シェルター等", icon: "⛱" }, - { key: "草地広場", icon: "🌿" }, - { key: "多目的広場", icon: "🏟" }, - { key: "築山", icon: "⛰" }, - { key: "じゃぶじゃぶ池", icon: "💦" }, - { key: "防災用具", icon: "🛟" }, - { key: "遊具", icon: "🎠" }, - { key: "時計", icon: "⏰" }, - { key: "駐車場", icon: "🅿" }, - { key: "その他設備", icon: "🔧" }, - { key: "備考", icon: "" }, +// 一覧の施設・備考は、フキダシと同じ「アイコン+値」の行で表示する。 +const FACILITY_KEYS = [ + "ベンチ・椅子", "野外卓", "シェルター等", "草地広場", "多目的広場", + "築山", "じゃぶじゃぶ池", "防災用具", "遊具", "時計", "駐車場", + "その他設備", "備考", ]; +type FacilityRow = { icon: string; cls: string; value: string; banned?: boolean }; +const textOf = (value: unknown) => String(value ?? "").trim(); +const presenceText = (label: string, value: unknown) => { + const v = textOf(value); + if (!v) return ""; + return /^[○〇◯あり有1]+$/.test(v) ? `${label}あり` : v; +}; +const waterText = (value: string) => { + const text = textOf(value); + if (!text) return ""; + if (/[??]/.test(text)) return "水飲み場?"; + let total = 0; + for (const part of text.split(/[、,]/)) { + const nums = [...part.matchAll(/[x×](\d+)/g)].map((m) => Number(m[1])); + if (nums.length) total += nums.reduce((a, b) => a * b, 1); + } + return total > 0 ? `水飲み場x${total}` : "水飲み場"; +}; function disasterText(value: string): string { return value .split(/[、,]/) @@ -195,18 +187,82 @@ function disasterText(value: string): string { .filter((s) => /かまど|カマド|防災収納|レスキュー|防災器具|避難/.test(s)) .join("、"); } -function detailText(p: Park): string { - const parts: string[] = []; - for (const { key, icon } of DETAIL_FIELDS) { - const raw = p[key]; - if (!raw) continue; - const value = key === "防災用具" ? disasterText(raw) : raw; - if (!value) continue; - parts.push(icon ? `${icon} ${value}` : value); +function facilityRows(p: Park): FacilityRow[] { + const rows: FacilityRow[] = []; + // 遊具もフキダシと同じく「遊」の文字アイコンを付ける。 + if (textOf(p["遊具"])) { + rows.push({ icon: '<span class="fac-text">遊</span>', cls: "", value: textOf(p["遊具"]) }); + } + if (textOf(p["トイレ"])) { + rows.push({ + icon: '<span class="fac-text">WC</span>', + cls: "is-toilet", + value: textOf(p["トイレ"]), + }); + } + const water = textOf(p["水飲み場"]); + if (water) { + rows.push({ icon: PARK_ICONS.water.svg, cls: "is-water", value: waterText(water) }); + } + if (textOf(p["給水"])) { + rows.push({ icon: PARK_ICONS.water.svg, cls: "is-water", value: textOf(p["給水"]) }); } - const ball = p["ボール遊び"]; - if (ball && ball !== "禁止" && ball !== "可") parts.push(`⚽ ${ball}`); - return parts.join(" / "); + if (textOf(p["ベンチ・椅子"])) { + rows.push({ icon: PARK_ICONS.bench.svg, cls: "is-bench", value: textOf(p["ベンチ・椅子"]) }); + } + if (textOf(p["野外卓"])) { + rows.push({ icon: PARK_ICONS.picnic.svg, cls: "", value: textOf(p["野外卓"]) }); + } + if (textOf(p["シェルター等"])) { + rows.push({ icon: PARK_ICONS.shelter.svg, cls: "", value: textOf(p["シェルター等"]) }); + } + if (textOf(p["草地広場"])) { + rows.push({ icon: PARK_ICONS.grass.svg, cls: "is-grass", value: presenceText("草地広場", p["草地広場"]) }); + } + if (textOf(p["多目的広場"])) { + rows.push({ icon: '<span class="fac-text">広</span>', cls: "", value: presenceText("多目的広場", p["多目的広場"]) }); + } + if (textOf(p["築山"])) { + rows.push({ icon: PARK_ICONS.mountain.svg, cls: "", value: presenceText("築山", p["築山"]) }); + } + if (textOf(p["じゃぶじゃぶ池"])) { + rows.push({ icon: PARK_ICONS.pond.svg, cls: "is-pond", value: presenceText("じゃぶじゃぶ池", p["じゃぶじゃぶ池"]) }); + } + const ballText = textOf(p["ボール遊び"]); + const matchText = textOf(p["試合形式のボール遊び"]); + const ballBanned = /禁止/.test(ballText); + const ballValue = ballBanned + ? "ボール遊び禁止" + : /禁止/.test(matchText) + ? "試合形式禁止" + : ballText; + if (ballValue) { + rows.push({ icon: PARK_ICONS.ball.svg, cls: "is-ball", value: ballValue, banned: ballBanned }); + } + const pet = textOf(p["ペット"]); + if (pet) { + rows.push({ icon: PARK_ICONS.dog.svg, cls: "is-pet", value: pet, banned: /禁止/.test(pet) }); + } + if (textOf(p["時計"])) { + rows.push({ icon: PARK_ICONS.clock.svg, cls: "is-clock", value: presenceText("時計", p["時計"]) }); + } + const disaster = disasterText(textOf(p["防災用具"])); + if (disaster) { + rows.push({ icon: '<span class="fac-text">災</span>', cls: "", value: disaster }); + } + if (textOf(p["駐車場"])) { + rows.push({ icon: '<span class="fac-text">P</span>', cls: "", value: textOf(p["駐車場"]) }); + } + if (textOf(p["その他設備"])) { + rows.push({ icon: '<span class="fac-text">他</span>', cls: "", value: textOf(p["その他設備"]) }); + } + if (textOf(p["備考"])) { + rows.push({ icon: "", cls: "", value: textOf(p["備考"]) }); + } + if (p["南西部指定管理"]) { + rows.push({ icon: "", cls: "", value: "指定管理" }); + } + return rows; } // 面積(数値) @@ -261,21 +317,18 @@ function searchIndex(p: Park): string { p["築山"] ? "築山" : "", p["じゃぶじゃぶ池"] ? "じゃぶじゃぶ池" : "", p["ボール遊び"], - ...DETAIL_FIELDS.map((f) => p[f.key]), + ...FACILITY_KEYS.map((key) => p[key]), ] .join(" ") .toLowerCase(); } -// 名称・住所などが未確認の公園 +// 編集画面(park-editor)の確認チェックが「済」でないものを未確認とする。 +// 対象は市内公園(市内の公共施設・市外の公園は各タブで管理する)。 function isUnconfirmed(p: Park): boolean { if (p["施設"] === "1") return false; - return ( - (p["備考"] || "").includes("未確認") || - (p["住所"] || "").includes("未確認") || - (p["状態"] || "").includes("未確認") || - (p["公園名"] || "").includes("未確認") - ); + if (p["種別"] === "市外") return false; + return (p["確認"] || "") !== "済"; } --- @@ -301,7 +354,7 @@ function isUnconfirmed(p: Park): boolean { <th scope="col">住所</th> <th scope="col" aria-sort="none"> <button type="button" class="parks-sort" data-sort="area"> - 面積(㎡)<span class="parks-sort-mark" aria-hidden="true"></span> + 面積<span class="parks-sort-mark" aria-hidden="true"></span> </button> </th> <th scope="col">種別</th> @@ -327,7 +380,12 @@ function isUnconfirmed(p: Park): boolean { data-focus-park={park["公園名"]} data-focus-key={park["地図キー"] || ""} title="地図でこの公園の位置を表示" - >{park["公園名"]}</button> + > + {park["公園名"]} + <span class="park-focus-ico" aria-hidden="true"> + <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="6"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3"/></svg> + </span> + </button> ) : park["公式URL"] ? ( <a class="park-name-link" @@ -358,7 +416,7 @@ function isUnconfirmed(p: Park): boolean { target="_blank" rel="noopener" title={`Googleマップで「${park["公園名"]}」を開く`} - >{park["住所"] || EMPTY}</a> + ><span class="addr-google" set:html={PARK_ICONS.google.svg} />{park["住所"] || EMPTY}</a> </td> <td class="is-num" @@ -382,11 +440,22 @@ function isUnconfirmed(p: Park): boolean { )} </td> <td class="is-facility" data-label="施設・備考"> - {facilityBadges(park).map((b) => ( - <span class:list={["fac-badge", `fac-${b.kind}`]} title={b.title} aria-label={b.title}></span> - ))} - {detailText(park) ? <span class="fac-detail">{detailText(park)}</span> : null} - {facilityBadges(park).length === 0 && !detailText(park) ? EMPTY : null} + {facilityRows(park).length ? ( + <span class="fac-detail"> + {facilityRows(park).map((row) => ( + <span class="fac-detail-row"> + {row.icon ? ( + <span class:list={["fac-detail-ico", row.cls, row.banned ? "is-banned" : ""]} set:html={row.icon} /> + ) : ( + <span /> + )} + <span>{row.value}</span> + </span> + ))} + </span> + ) : ( + EMPTY + )} </td> </tr> ))} @@ -463,50 +532,113 @@ function isUnconfirmed(p: Park): boolean { border-radius: 0.3rem; } .parks table { + display: block; width: 100%; - min-width: 760px; - table-layout: fixed; + min-width: 0; + overflow: visible; border-collapse: collapse; font-size: 0.85rem; } - .parks col.col-name { - width: 24%; + .parks colgroup { + display: none; } - .parks col.col-address { - width: 18%; + /* 1行を「公園情報」「施設・備考」の2列で表示する(PC・スマホ共通) */ + .parks tbody, + .parks tbody tr, + .parks td { + display: block; } - .parks col.col-area { - width: 11%; + .parks tbody tr { + display: grid; + grid-template-columns: minmax(0, 0.48fr) minmax(0, 0.26fr) minmax(0, 1.26fr); + grid-template-areas: + "name name fac" + "addr addr fac" + "area type fac"; + gap: 0 0.6rem; + padding: 0.2rem 0.6rem; + border-bottom: 0; } - .parks col.col-type { - width: 7%; + .parks table tbody td { + border: 0; + margin: 0; + padding: 0; + text-align: left; + vertical-align: top; + white-space: normal; + overflow-wrap: anywhere; } - .parks col.col-facility { - width: 40%; + .parks .is-name { + grid-area: name; } - .parks th, - .parks td { - border-bottom: 1px solid var(--sl-color-hairline, #ddd); - border-right: 1px solid var(--sl-color-hairline, #ddd); - padding: 0.35rem 0.55rem; + .parks .is-address { + grid-area: addr; + min-width: 0; + } + .parks .is-num { + grid-area: area; text-align: left; - vertical-align: top; - white-space: nowrap; } - .parks th:last-child, - .parks td:last-child { - border-right: none; + .parks .is-type { + grid-area: type; + text-align: left; } - .parks thead th { + .parks .is-facility { + grid-area: fac; + min-width: 0; + max-width: none; + border-left: 1px solid var(--sl-color-hairline, #ddd); + padding-left: 0.65rem; + } + .parks thead { + display: block; position: sticky; top: 0; - z-index: 1; + z-index: 2; background: var(--sl-color-gray-6, #f2f2f2); + border-bottom: 1px solid var(--sl-color-hairline, #ddd); + } + .parks thead tr { + display: grid; + grid-template-columns: minmax(0, 0.48fr) minmax(0, 0.26fr) minmax(0, 1.26fr); + grid-template-areas: + "h-name h-name h-fac" + "h-area h-type h-fac"; + } + .parks thead th { + position: static; + border: 0; + background: transparent; + padding: 0.35rem 0.65rem; + text-align: left; + vertical-align: bottom; + white-space: normal; color: var(--sl-color-white, inherit); } + .parks thead th:nth-child(1) { + grid-area: h-name; + } + .parks thead th:nth-child(2) { + display: none; + } + .parks thead th:nth-child(3) { + grid-area: h-area; + } + .parks thead th:nth-child(4) { + grid-area: h-type; + } + .parks thead th:nth-child(5) { + grid-area: h-fac; + } .parks tbody tr:nth-child(even) td { + background: transparent; + } + .parks tbody tr:nth-child(even) { background: color-mix(in srgb, var(--sl-color-text, #333) 5%, transparent); } + .parks tbody tr.is-selected td:first-child { + box-shadow: none; + } .parks tr.is-hidden { display: none; } @@ -533,17 +665,22 @@ function isUnconfirmed(p: Park): boolean { font-weight: 600; white-space: normal; overflow-wrap: anywhere; - line-height: 1.5; + line-height: 1.3; + } + .parks .is-address, + .parks .is-num, + .parks .is-type { + line-height: 1.25; } .parks-owner { display: inline-block; - margin-left: 0.35rem; + margin: 0 0.35rem 0 0; padding: 0.02rem 0.35rem; border: 1px solid currentColor; border-radius: 999px; font-size: 0.7rem; font-weight: 600; - line-height: 1.5; + line-height: 1.2; vertical-align: 0.08em; white-space: nowrap; } @@ -561,7 +698,7 @@ function isUnconfirmed(p: Park): boolean { } .parks-status { display: inline-block; - margin-left: 0.35rem; + margin: 0 0.35rem 0 0; padding: 0.02rem 0.35rem; border: 1px solid #ef9a9a; border-radius: 999px; @@ -569,7 +706,7 @@ function isUnconfirmed(p: Park): boolean { color: #b71c1c; font-size: 0.7rem; font-weight: 700; - line-height: 1.5; + line-height: 1.2; vertical-align: 0.08em; white-space: nowrap; } @@ -579,7 +716,7 @@ function isUnconfirmed(p: Park): boolean { color: #424242; } .park-name-link { - display: inline-block; + display: block; max-width: 100%; padding: 0; border: 0; @@ -598,29 +735,56 @@ function isUnconfirmed(p: Park): boolean { .park-name-link:hover { color: var(--sl-color-accent); } - .parks tbody tr.is-highlighted td { + .park-focus-ico { + display: inline-flex; + width: 0.9em; + height: 0.9em; + margin-left: 0.2em; + color: #0277bd; + vertical-align: -0.08em; + } + .park-focus-ico svg { + display: block; + width: 100%; + height: 100%; + } + .parks tbody tr.is-highlighted { background: #fff59d !important; + outline: 2px solid #f9a825; + outline-offset: -2px; } - .parks tbody tr.is-selected td { + .parks tbody tr.is-highlighted td { + background: transparent !important; + } + .parks tbody tr.is-selected { background: #ffe0b2 !important; + outline: 2px solid #e65100; + outline-offset: -2px; } - .parks tbody tr.is-selected td:first-child { - box-shadow: inset 4px 0 0 #e65100; + .parks tbody tr.is-selected td { + background: transparent !important; } .parks .is-address { font-size: 0.8em; white-space: normal; - min-width: 9rem; } .parks .is-address a { color: var(--sl-color-text-accent, #357); } - .parks .is-address a::before { - content: "📍"; - margin-right: 0.2em; + .parks .addr-google { + display: inline-flex; + width: 1em; + height: 1em; + margin-right: 0.15em; + vertical-align: -0.12em; + } + .parks .addr-google :global(svg) { + display: block; + width: 100%; + height: 100%; } .parks .is-num { - text-align: right; + text-align: left; font-variant-numeric: tabular-nums; white-space: nowrap; } @@ -631,7 +795,7 @@ function isUnconfirmed(p: Park): boolean { padding: 0 0.45em; border-radius: 0.7em; font-size: 0.75em; - line-height: 1.7; + line-height: 1.2; vertical-align: middle; background: color-mix(in srgb, currentColor 14%, transparent); } @@ -687,111 +851,111 @@ function isUnconfirmed(p: Park): boolean { } .parks .is-facility { white-space: normal; - min-width: 12rem; - max-width: 26rem; } - .parks .fac-badge { + .parks .fac-detail { + display: grid; + gap: 0.1rem; + font-size: 0.8em; + opacity: 0.9; + } + .parks .fac-detail-row { + display: grid; + grid-template-columns: 18px minmax(0, 1fr); + gap: 0.35rem; + align-items: start; + } + .parks .fac-detail-ico { + position: relative; display: inline-flex; align-items: center; justify-content: center; - margin: 0 0.3em 0.2em 0; - padding: 0 0.4em; - border-radius: 1em; - font-size: 0.85em; - line-height: 1.9; - white-space: nowrap; - background: color-mix(in srgb, currentColor 10%, transparent); - cursor: help; + box-sizing: border-box; + width: 18px; + height: 18px; + border: 1px solid #c8e6c9; + border-radius: 4px; + background: #e8f5e9; + color: #2e7d32; + font-size: 11px; + font-weight: 700; + line-height: 1; } - .parks .fac-toilet::before { - content: "🚻"; + .parks .fac-detail-ico :global(svg) { + display: block; + width: 14px; + height: 14px; } - .parks .fac-water::before { - content: "💧"; + .parks .fac-detail-ico.is-toilet { + border-color: #263238; + background: #455a64; + color: #fff; + font-size: 8px; } - .parks .fac-toy::before { - content: "🎠"; + .parks .fac-detail-ico.is-water { + border-color: #90caf9; + background: #e3f2fd; + color: #0277bd; } - .parks .fac-ball::before { - content: "⚽"; + .parks .fac-detail-ico.is-bench { + border-color: #d7ccc8; + background: #efebe9; + color: #6d4c41; } - .parks .fac-cm::before { - content: "🏛"; + .parks .fac-detail-ico.is-pond { + border-color: #81d4fa; + background: #e1f5fe; + color: #29b6f6; } - .parks .fac-pergola::before { - content: "🌿"; + .parks .fac-detail-ico.is-clock { + border-color: #ffe082; + background: #fff8e1; + color: #f9a825; } - .parks .fac-azumaya::before { - content: "🛖"; + .parks .fac-detail-ico.is-ball { + color: #2e7d32; } - .parks .fac-detail { - display: block; - margin-top: 0.25em; - font-size: 0.8em; - opacity: 0.85; + .parks .fac-detail-ico.is-pet { + padding: 0; + border-color: #e0e0e0; + background: #fff; + color: #6d4c41; + } + .parks .fac-detail-ico.is-pet :global(svg) { + width: 100%; + height: 100%; + } + .parks .fac-detail-ico.is-banned { + overflow: hidden; + } + .parks .fac-detail-ico.is-banned::after { + content: ""; + position: absolute; + inset: 0; + background: + linear-gradient(45deg, transparent 47%, #d32f2f 47%, #d32f2f 53%, transparent 53%), + linear-gradient(-45deg, transparent 47%, #d32f2f 47%, #d32f2f 53%, transparent 53%); + } + .parks .fac-detail-ico :global(.fac-text) { + font-size: inherit; + font-weight: inherit; + line-height: inherit; + white-space: nowrap; } - /* スマートフォンでは表をカード状に組み替え、横スクロールなしで読めるようにする。 */ + /* スマートフォンではヘッダーを省き、余白を詰める(2列レイアウトは共通) */ @media (max-width: 700px) { .parks table { - display: block; - width: 100%; - min-width: 0; font-size: 0.8rem; } .parks thead { display: none; } - .parks tbody, - .parks tbody tr, - .parks td { - display: block; - } .parks tbody tr { - display: grid; - grid-template-columns: 1fr auto auto; - grid-template-areas: - "name name name" - "addr area type" - "fac fac fac"; - gap: 0.15rem 0.5rem; - padding: 0.45rem 0.55rem; - border-bottom: 1px solid var(--sl-color-hairline, #ddd); - } - .parks tbody tr:nth-child(even) td { - background: transparent; - } - .parks tbody tr:nth-child(even) { - background: color-mix(in srgb, var(--sl-color-text, #333) 5%, transparent); - } - .parks td { - border: 0; - padding: 0; - white-space: normal; - overflow-wrap: anywhere; - } - .parks .is-name { - grid-area: name; - } - .parks .is-address { - grid-area: addr; - min-width: 0; - } - .parks .is-num { - grid-area: area; - text-align: left; - } - .parks .is-type { - grid-area: type; - text-align: left; + gap: 0 0.45rem; + padding: 0.2rem 0.5rem; } .parks .is-facility { - grid-area: fac; - min-width: 0; - max-width: none; - } - .parks tbody tr.is-selected td:first-child { - box-shadow: none; + padding-left: 0.5rem; } } </style> @@ -868,8 +1032,13 @@ function isUnconfirmed(p: Park): boolean { if (count) count.textContent = `${shown} / ${total}件`; if (none) none.hidden = shown !== 0; // 地図側に絞り込み結果を通知する。 - const visibleNames = allRows() - .filter((row) => !row.classList.contains("is-hidden")) + const visibleRows = allRows().filter((row) => !row.classList.contains("is-hidden")); + const visibleNames = visibleRows + .map((row) => row.dataset.name || "") + .filter(Boolean); + // 市外の近い公園は名前が小平市内と重複することがあるため、別に渡す。 + const visibleNearbyNames = visibleRows + .filter((row) => row.dataset.town === "市外") .map((row) => row.dataset.name || "") .filter(Boolean); const fromMap = Boolean(selectedName && search?.value === selectedName); @@ -877,6 +1046,7 @@ function isUnconfirmed(p: Park): boolean { new CustomEvent("park:filter", { detail: { names: visibleNames, + nearbyNames: visibleNearbyNames, active: Boolean( kind || town || query || wanted.length || selectedName || onlyUnconfirmed, ), |
