@@ -195,22 +231,39 @@ const total = parks.length;
data-fac={facTokens(park)}
data-search={searchIndex(park)}
>
-
{park["公園名"]} |
+
+ {mappedNames.has(park["公園名"]) ? (
+
+ ) : (
+ park["公園名"]
+ )}
+ {park["設置者"] && park["設置者"] !== "小平市" ? (
+ {ownerLabel(park["設置者"])}
+ ) : null}
+ |
{park["住所"]}
+ >{park["住所"] || EMPTY}
|
- {areaText(park["面積㎡"])}㎡
+ {park["面積㎡"] ? `${areaText(park["面積㎡"])}㎡` : EMPTY}
|
{park["種別"] ? (
@@ -357,6 +410,46 @@ const total = parks.length;
.parks .is-name {
font-weight: 600;
}
+ .parks-owner {
+ display: inline-block;
+ margin-left: 0.35rem;
+ padding: 0.02rem 0.35rem;
+ border: 1px solid currentColor;
+ border-radius: 999px;
+ font-size: 0.7rem;
+ font-weight: 600;
+ line-height: 1.5;
+ vertical-align: 0.08em;
+ white-space: nowrap;
+ }
+ .parks-owner--tokyo {
+ color: #2e7d32;
+ }
+ .parks-owner--other {
+ color: #6d4c41;
+ }
+ .parks-owner--unknown {
+ color: #757575;
+ }
+ .park-name-link {
+ padding: 0;
+ border: 0;
+ background: none;
+ color: inherit;
+ font: inherit;
+ font-weight: 600;
+ text-align: left;
+ cursor: pointer;
+ text-decoration: underline;
+ text-decoration-color: var(--sl-color-gray-4);
+ text-underline-offset: 2px;
+ }
+ .park-name-link:hover {
+ color: var(--sl-color-accent);
+ }
+ .parks tbody tr.is-highlighted td {
+ background: #fff59d !important;
+ }
.parks .is-address {
font-size: 0.8em;
white-space: normal;
@@ -417,6 +510,15 @@ const total = parks.length;
.parks-type--sports {
--type-color: #e8862a;
}
+ .parks-type--wide {
+ --type-color: #7b1fa2;
+ }
+ .parks-type--open {
+ --type-color: #8d6e63;
+ }
+ .parks-type--green {
+ --type-color: #43a047;
+ }
.parks .is-facility {
white-space: normal;
min-width: 12rem;
@@ -463,54 +565,14 @@ const total = parks.length;
opacity: 0.85;
}
- /* スマートフォンでは1件ずつカードで表示する。 */
+ /* スマートフォンでも表形式を維持し、横スクロールで見られるようにする。 */
@media (max-width: 640px) {
- .parks-scroll {
- overflow-x: visible;
- border: none;
- border-radius: 0;
- }
- .parks table,
- .parks tbody,
- .parks tr,
- .parks td {
- display: block;
- width: auto;
- }
- .parks thead {
- display: none;
- }
- .parks tbody tr {
- margin-bottom: 0.6rem;
- padding: 0.4rem 0.6rem;
- border: 1px solid var(--sl-color-hairline, #ddd);
- border-radius: 0.4rem;
- }
- .parks tbody tr:nth-child(even) td {
- background: transparent;
+ .parks table {
+ font-size: 0.75rem;
}
+ .parks th,
.parks td {
- border: none;
- padding: 0.1rem 0;
- white-space: normal;
- max-width: none;
- }
- .parks td::before {
- content: attr(data-label) ":";
- display: inline-block;
- min-width: 4.5em;
- font-size: 0.85em;
- opacity: 0.7;
- }
- .parks td.is-name {
- font-size: 1rem;
- }
- .parks td.is-name::before {
- content: none;
- }
- .parks td.is-num,
- .parks td.is-type {
- text-align: left;
+ padding: 0.3rem 0.4rem;
}
}
@@ -520,17 +582,26 @@ const total = parks.length;
const select = root.querySelector("[data-parks-town]");
const search = root.querySelector("[data-parks-search]");
const count = root.querySelector("[data-parks-count]");
- const none = root.querySelector("[data-parks-none]");
+ const none = root.querySelector("[data-parks-none]");
const tbody = root.querySelector("tbody");
const checks = Array.from(root.querySelectorAll("[data-fac-filter]"));
const sortButtons = Array.from(root.querySelectorAll("[data-sort]"));
if (!tbody) return;
+ root.querySelectorAll("[data-focus-park]").forEach((btn) => {
+ btn.addEventListener("click", () => {
+ const name = btn.dataset.focusPark;
+ if (!name) return;
+ document.dispatchEvent(new CustomEvent("park:focus", { detail: { name } }));
+ });
+ });
+
const allRows = () => Array.from(tbody.querySelectorAll("tr"));
const total = allRows().length;
let sortKey: string | null = null;
let sortDir = 1;
+ let selectedName = "";
const applyFilter = () => {
const town = select ? select.value : "";
@@ -542,12 +613,28 @@ const total = parks.length;
const okTown = !town || row.dataset.town === town;
const okText = !query || (row.dataset.search || "").includes(query);
const okFac = wanted.every((token) => facs.includes(token));
- const ok = okTown && okText && okFac;
+ const okSelected = !selectedName || row.dataset.name === selectedName;
+ const ok = okTown && okText && okFac && okSelected;
row.classList.toggle("is-hidden", !ok);
if (ok) shown += 1;
});
if (count) count.textContent = `${shown} / ${total}件`;
if (none) none.hidden = shown !== 0;
+ // 地図側に絞り込み結果を通知する。
+ const visibleNames = allRows()
+ .filter((row) => !row.classList.contains("is-hidden"))
+ .map((row) => row.dataset.name || "")
+ .filter(Boolean);
+ const fromMap = Boolean(selectedName && search?.value === selectedName);
+ document.dispatchEvent(
+ new CustomEvent("park:filter", {
+ detail: {
+ names: visibleNames,
+ active: Boolean(town || query || wanted.length || selectedName),
+ fromMap,
+ },
+ }),
+ );
};
const applySort = () => {
@@ -572,9 +659,45 @@ const total = parks.length;
sorted.forEach((row) => tbody.appendChild(row));
};
- select?.addEventListener("change", applyFilter);
- search?.addEventListener("input", applyFilter);
- checks.forEach((c) => c.addEventListener("change", applyFilter));
+ const clearSelected = () => {
+ selectedName = "";
+ };
+ select?.addEventListener("change", () => {
+ clearSelected();
+ applyFilter();
+ });
+ search?.addEventListener("input", () => {
+ clearSelected();
+ applyFilter();
+ });
+ checks.forEach((c) =>
+ c.addEventListener("change", () => {
+ clearSelected();
+ applyFilter();
+ }),
+ );
+
+ // 地図のポリゴンクリックなどから、公園名で1件だけ絞り込む。
+ document.addEventListener("park:filter-name", (e: Event) => {
+ const detail = (e as CustomEvent).detail || {};
+ const name = detail.name;
+ if (!name) return;
+ selectedName = name;
+ if (search) search.value = name;
+ if (select) select.value = "";
+ checks.forEach((c) => {
+ c.checked = false;
+ });
+ applyFilter();
+ const row = allRows().find((r) => r.dataset.name === name);
+ if (row) {
+ row.classList.add("is-highlighted");
+ window.setTimeout(() => row.classList.remove("is-highlighted"), 2000);
+ if (detail.scroll) {
+ row.scrollIntoView({ behavior: "smooth", block: "center" });
+ }
+ }
+ });
sortButtons.forEach((btn) => {
btn.addEventListener("click", () => {
const key = btn.dataset.sort;
--
cgit v1.3.1
|