aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-06 14:24:46 +0900
committerYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-06 14:24:46 +0900
commit688b74a658a217a0e4dac67bf95a859ebb793e07 (patch)
treec604e24194855ce6a2685f00a0203164366ea3d0
parentb02772f108fc9cf5271b9625ec89ec89323fe7b5 (diff)
ParksTable: 公園一覧に設備フィルタ・並べ替え・カード表示を追加
設備(トイレ・水飲み場・遊具・ボール遊び)で絞り込めるようにする。 公園名・面積の見出しで並べ替え、0件時は案内を表示する。 スマホはカード表示にし、面積に小・中・大の目安を付ける。 設備はアイコンバッジで示し、地図リンクは住所ではなく公園名 (+小平市)で検索するようにする。 updates.json を再生成(公園一覧を追加、上限40件)。
-rw-r--r--src/components/ParksTable.astro479
-rw-r--r--src/content/docs/kodaira-data/parks.mdx14
-rw-r--r--src/data/updates.json14
3 files changed, 434 insertions, 73 deletions
diff --git a/src/components/ParksTable.astro b/src/components/ParksTable.astro
index 268bdfe..8d7f648 100644
--- a/src/components/ParksTable.astro
+++ b/src/components/ParksTable.astro
@@ -1,7 +1,8 @@
---
// 小平市の公園一覧(/kodaira-data/parks/)を表示する。
// データは src/data/kodaira-parks.json(321件、市の公開資料から作成)。
-// 町名セレクトとキーワード入力で絞り込む(絞り込みは利用者の端末で実行)。
+// DOM を抑えるため、設備は1セルにまとめ、アイコンは CSS の擬似要素で描く。
+// 絞り込み・並べ替え・カード表示は利用者の端末で実行する。
import parksData from "@/data/kodaira-parks.json";
type Park = Record<string, string>;
@@ -9,42 +10,110 @@ const parks = parksData as Park[];
const EMPTY = "—";
-const columns: { key: string; label: string; numeric?: boolean; wide?: boolean }[] = [
- { key: "公園名", label: "公園名" },
- { key: "住所", label: "住所" },
- { key: "面積㎡", label: "面積(㎡)", numeric: true },
- { key: "500㎡以上", label: "500㎡以上" },
- { key: "種別", label: "種別" },
- { key: "南西部指定管理", label: "南西部指定管理" },
- { key: "トイレ", label: "トイレ", wide: true },
- { key: "水飲み場", label: "水飲み場" },
- { key: "ベンチ・椅子", label: "ベンチ・椅子", wide: true },
- { key: "テーブル", label: "テーブル", wide: true },
- { key: "防災用具", label: "防災用具", wide: true },
- { key: "ボール遊び", label: "ボール遊び", wide: true },
- { key: "遊具", label: "遊具", wide: true },
- { key: "備考", label: "備考", wide: true },
-];
+// 種別の表示(色付きの丸+区分名。正式名は title / aria-label で補う)。
+const TYPE_LABEL: Record<string, string> = {
+ 街区: "街区公園",
+ 近隣: "近隣公園",
+ 運動: "運動公園",
+};
+const TYPE_CLASS: Record<string, string> = {
+ 街区: "parks-type--block",
+ 近隣: "parks-type--neighbor",
+ 運動: "parks-type--sports",
+};
+
+// 設備バッジ(アイコンは 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: "toy", label: "遊具", title: `遊具: ${p["遊具"]}` });
+ }
+ const ball = p["ボール遊び"];
+ if (ball && ball !== "禁止") {
+ const label = ball.includes("一部") ? "ボール遊び一部可" : "ボール遊び可";
+ badges.push({ kind: "ball", label, title: `ボール遊び: ${ball}` });
+ }
+ return badges;
+}
-function display(key: string, value: string): string {
- if (value === "" || value == null) return EMPTY;
- if (key === "面積㎡") {
- const n = Number(value);
- if (Number.isFinite(n)) return n.toLocaleString("ja-JP");
+// 設備フィルタ用のトークン(data-fac)。
+function facTokens(p: Park): string {
+ const tokens: string[] = [];
+ if (p["トイレ"]) tokens.push("toilet");
+ if (p["水飲み場"]) tokens.push("water");
+ if (p["遊具"]) tokens.push("toy");
+ const ball = p["ボール遊び"];
+ if (ball && ball !== "禁止") tokens.push("ball");
+ return tokens.join(" ");
+}
+
+// 設備セルの補足テキスト(バッジで示した項目の詳細と、その他の項目)。
+const DETAIL_FIELDS: { key: string; label: string }[] = [
+ { key: "ベンチ・椅子", label: "ベンチ・椅子" },
+ { key: "テーブル", label: "テーブル" },
+ { key: "防災用具", label: "防災用具" },
+ { key: "遊具", label: "遊具" },
+ { key: "備考", label: "備考" },
+];
+function detailText(p: Park): string {
+ const parts: string[] = [];
+ if (p["南西部指定管理"]) parts.push("南西部指定管理");
+ for (const { key, label } of DETAIL_FIELDS) {
+ const value = p[key];
+ if (!value) continue;
+ parts.push(key === "備考" ? value : `${label}: ${value}`);
}
- return value;
+ const ball = p["ボール遊び"];
+ if (ball && ball !== "禁止" && ball !== "可") parts.push(`ボール遊び: ${ball}`);
+ return parts.join(" / ");
}
-// 検索対象(公園名・住所・町名・種別・ボール遊び・遊具・備考)。
+// 面積(数値)
+function areaNumber(value: string): number {
+ const n = Number(value);
+ return Number.isFinite(n) ? n : 0;
+}
+function areaText(value: string): string {
+ const n = areaNumber(value);
+ return n ? n.toLocaleString("ja-JP") : value;
+}
+// 面積の目安(小・中・大)。しきい値はページの注記に合わせる。
+function sizeLabel(area: number): string {
+ if (area < 1000) return "小";
+ if (area < 10000) return "中";
+ return "大";
+}
+function sizeTitle(area: number): string {
+ if (area < 1000) return "目安: 1,000㎡未満(小さめ)";
+ if (area < 10000) return "目安: 1,000〜10,000㎡(ふつう)";
+ return "目安: 10,000㎡以上(広め)";
+}
+
+// 住所ではなく公園名で検索する(地番は地図側で正しく解決されないため)。
+// 「小平市」を付けないと別の自治体の同名公園に飛ぶので必ず付ける。
+function mapsUrl(name: string): string {
+ const query = encodeURIComponent(`小平市${name}`);
+ return `https://www.google.com/maps/search/?api=1&query=${query}`;
+}
+
+// 検索対象(公園名・住所・町名・種別・設備・備考)。
function searchIndex(p: Park): string {
return [
p["公園名"],
p["住所"],
p["町名"],
p["種別"],
+ p["トイレ"],
+ p["水飲み場"],
p["ボール遊び"],
- p["遊具"],
- p["備考"],
+ ...DETAIL_FIELDS.map((f) => p[f.key]),
]
.join(" ")
.toLowerCase();
@@ -71,32 +140,85 @@ const total = parks.length;
<span>キーワード</span>
<input type="search" data-parks-search placeholder="公園名・住所・遊具など" />
</label>
+ <fieldset class="parks-facilities">
+ <legend>設備で絞る</legend>
+ <label><input type="checkbox" data-fac-filter value="toilet" />トイレ</label>
+ <label><input type="checkbox" data-fac-filter value="water" />水飲み場</label>
+ <label><input type="checkbox" data-fac-filter value="toy" />遊具</label>
+ <label><input type="checkbox" data-fac-filter value="ball" />ボール遊び</label>
+ </fieldset>
<span class="parks-count" data-parks-count aria-live="polite">{total}件</span>
</div>
+ <p class="parks-hint">設備の情報は市の南西部地域の公園のみです。設備で絞ると、この情報がある公園だけが対象になります。</p>
+ <p class="parks-none" data-parks-none hidden>条件に合う公園が見つかりませんでした。</p>
<div class="parks-scroll">
<table>
<thead>
<tr>
- {columns.map((col) => (
- <th scope="col">{col.label}</th>
- ))}
+ <th scope="col" aria-sort="none">
+ <button type="button" class="parks-sort" data-sort="name">
+ 公園名<span class="parks-sort-mark" aria-hidden="true"></span>
+ </button>
+ </th>
+ <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>
+ </button>
+ </th>
+ <th scope="col">種別</th>
+ <th scope="col">施設・備考</th>
</tr>
</thead>
<tbody>
{parks.map((park) => (
- <tr data-town={park["町名"]} data-search={searchIndex(park)}>
- {columns.map((col) => (
- <td
- class:list={[
- col.numeric && "is-num",
- col.wide && "is-wide",
- park[col.key] === "" && "is-empty",
- ]}
- >
- {display(col.key, park[col.key])}
- </td>
- ))}
+ <tr
+ data-town={park["町名"]}
+ data-area={park["面積㎡"]}
+ data-name={park["公園名"]}
+ data-fac={facTokens(park)}
+ data-search={searchIndex(park)}
+ >
+ <td class="is-name" data-label="公園名">{park["公園名"]}</td>
+ <td class="is-address" data-label="住所">
+ <a
+ href={mapsUrl(park["公園名"])}
+ target="_blank"
+ rel="noopener"
+ title={`Googleマップで「${park["公園名"]}」を開く`}
+ >{park["住所"]}</a>
+ </td>
+ <td
+ class="is-num"
+ data-label="面積"
+ data-size={sizeLabel(areaNumber(park["面積㎡"]))}
+ title={sizeTitle(areaNumber(park["面積㎡"]))}
+ >
+ {areaText(park["面積㎡"])}㎡
+ </td>
+ <td class="is-type" data-label="種別">
+ {park["種別"] ? (
+ <span
+ class:list={["parks-type", TYPE_CLASS[park["種別"]]]}
+ title={TYPE_LABEL[park["種別"]]}
+ aria-label={TYPE_LABEL[park["種別"]]}
+ >
+ {park["種別"]}
+ </span>
+ ) : (
+ EMPTY
+ )}
+ </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}>
+ {b.label}
+ </span>
+ ))}
+ {detailText(park) ? <span class="fac-detail">{detailText(park)}</span> : null}
+ {facilityBadges(park).length === 0 && !detailText(park) ? EMPTY : null}
+ </td>
</tr>
))}
</tbody>
@@ -108,9 +230,9 @@ const total = parks.length;
.parks-controls {
display: flex;
flex-wrap: wrap;
- gap: 0.75rem 1rem;
+ gap: 0.6rem 1rem;
align-items: center;
- margin: 1rem 0;
+ margin: 1rem 0 0.4rem;
}
.parks-controls label {
display: inline-flex;
@@ -119,7 +241,7 @@ const total = parks.length;
font-size: 0.9rem;
}
.parks-controls select,
- .parks-controls input {
+ .parks-controls input[type="search"] {
padding: 0.3rem 0.5rem;
border: 1px solid var(--sl-color-hairline, #ccc);
border-radius: 0.3rem;
@@ -127,10 +249,41 @@ const total = parks.length;
color: var(--sl-color-text, inherit);
font: inherit;
}
+ .parks-facilities {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.3rem 0.8rem;
+ align-items: center;
+ margin: 0;
+ padding: 0.2rem 0.6rem;
+ border: 1px solid var(--sl-color-hairline, #ccc);
+ border-radius: 0.3rem;
+ }
+ .parks-facilities legend {
+ padding: 0 0.2rem;
+ font-size: 0.8em;
+ color: inherit;
+ opacity: 0.7;
+ }
+ .parks-facilities label {
+ font-size: 0.85rem;
+ }
.parks-count {
margin-left: auto;
font-size: 0.9rem;
- color: var(--sl-color-gray-3, #666);
+ opacity: 0.75;
+ }
+ .parks-hint,
+ .parks-none {
+ margin: 0 0 0.6rem;
+ font-size: 0.8rem;
+ opacity: 0.75;
+ }
+ .parks-none {
+ padding: 0.6rem;
+ border: 1px dashed var(--sl-color-hairline, #ccc);
+ border-radius: 0.3rem;
+ opacity: 1;
}
.parks-scroll {
overflow-x: auto;
@@ -166,19 +319,177 @@ const total = parks.length;
.parks tbody tr:nth-child(even) td {
background: color-mix(in srgb, var(--sl-color-text, #333) 5%, transparent);
}
+ .parks tr.is-hidden {
+ display: none;
+ }
+ .parks-sort {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25rem;
+ padding: 0;
+ border: none;
+ background: none;
+ color: inherit;
+ font: inherit;
+ cursor: pointer;
+ }
+ .parks-sort:hover .parks-sort-mark {
+ color: var(--sl-color-text-accent, #4c8);
+ }
+ .parks-sort-mark {
+ display: inline-block;
+ min-width: 1em;
+ text-align: center;
+ }
+ .parks .is-name {
+ font-weight: 600;
+ }
+ .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 .is-num {
text-align: right;
font-variant-numeric: tabular-nums;
+ white-space: nowrap;
}
- .parks .is-wide {
- white-space: normal;
- min-width: 11rem;
- max-width: 20rem;
+ .parks .is-num::after {
+ content: attr(data-size);
+ display: inline-block;
+ margin-left: 0.4em;
+ padding: 0 0.45em;
+ border-radius: 0.7em;
+ font-size: 0.75em;
+ line-height: 1.7;
+ vertical-align: middle;
+ background: color-mix(in srgb, currentColor 14%, transparent);
+ }
+ .parks .is-num[data-size="中"]::after {
+ background: color-mix(in srgb, #2e9e4f 22%, transparent);
+ }
+ .parks .is-num[data-size="大"]::after {
+ background: color-mix(in srgb, #2f7fe0 24%, transparent);
}
- .parks .is-empty {
- color: var(--sl-color-gray-4, #aaa);
+ .parks .is-type {
text-align: center;
}
+ .parks-type {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.3em;
+ font-size: 0.9em;
+ }
+ .parks-type::before {
+ content: "";
+ width: 0.7em;
+ height: 0.7em;
+ border-radius: 50%;
+ background: var(--type-color, #888);
+ flex: none;
+ }
+ .parks-type--block {
+ --type-color: #2e9e4f;
+ }
+ .parks-type--neighbor {
+ --type-color: #2f7fe0;
+ }
+ .parks-type--sports {
+ --type-color: #e8862a;
+ }
+ .parks .is-facility {
+ white-space: normal;
+ min-width: 12rem;
+ max-width: 26rem;
+ }
+ .parks .fac-badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25em;
+ margin: 0 0.3em 0.2em 0;
+ padding: 0 0.5em;
+ border-radius: 1em;
+ font-size: 0.8em;
+ line-height: 1.8;
+ white-space: nowrap;
+ background: color-mix(in srgb, currentColor 10%, transparent);
+ }
+ .parks .fac-toilet::before {
+ content: "🚻";
+ }
+ .parks .fac-water::before {
+ content: "🚰";
+ }
+ .parks .fac-toy::before {
+ content: "🎠";
+ }
+ .parks .fac-ball::before {
+ content: "⚽";
+ }
+ .parks .fac-detail {
+ display: block;
+ margin-top: 0.25em;
+ font-size: 0.8em;
+ 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 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;
+ }
+ }
</style>
<script>
@@ -186,25 +497,73 @@ const total = parks.length;
const select = root.querySelector<HTMLSelectElement>("[data-parks-town]");
const search = root.querySelector<HTMLInputElement>("[data-parks-search]");
const count = root.querySelector("[data-parks-count]");
- const rows = Array.from(root.querySelectorAll<HTMLTableRowElement>("tbody tr"));
- const total = rows.length;
+ const none = root.querySelector("[data-parks-none]");
+ const tbody = root.querySelector("tbody");
+ const checks = Array.from(root.querySelectorAll<HTMLInputElement>("[data-fac-filter]"));
+ const sortButtons = Array.from(root.querySelectorAll<HTMLButtonElement>("[data-sort]"));
+ if (!tbody) return;
+
+ const allRows = () => Array.from(tbody.querySelectorAll<HTMLTableRowElement>("tr"));
+ const total = allRows().length;
- const apply = () => {
+ let sortKey: string | null = null;
+ let sortDir = 1;
+
+ const applyFilter = () => {
const town = select ? select.value : "";
const query = search ? search.value.trim().toLowerCase() : "";
+ const wanted = checks.filter((c) => c.checked).map((c) => c.value);
let shown = 0;
- rows.forEach((row) => {
+ allRows().forEach((row) => {
+ const facs = (row.dataset.fac || "").split(" ");
const okTown = !town || row.dataset.town === town;
const okText = !query || (row.dataset.search || "").includes(query);
- const ok = okTown && okText;
- row.hidden = !ok;
+ const okFac = wanted.every((token) => facs.includes(token));
+ const ok = okTown && okText && okFac;
+ row.classList.toggle("is-hidden", !ok);
if (ok) shown += 1;
});
if (count) count.textContent = `${shown} / ${total}件`;
+ if (none) none.hidden = shown !== 0;
};
- select?.addEventListener("change", apply);
- search?.addEventListener("input", apply);
- apply();
+ const applySort = () => {
+ sortButtons.forEach((btn) => {
+ const th = btn.closest("th");
+ const active = btn.dataset.sort === sortKey;
+ if (th) {
+ th.setAttribute("aria-sort", active ? (sortDir === 1 ? "ascending" : "descending") : "none");
+ }
+ const mark = btn.querySelector(".parks-sort-mark");
+ if (mark) mark.textContent = active ? (sortDir === 1 ? "▲" : "▼") : "";
+ });
+ if (!sortKey) return;
+ const sorted = allRows().sort((a, b) => {
+ if (sortKey === "area") {
+ const av = Number.parseFloat(a.dataset.area || "") || 0;
+ const bv = Number.parseFloat(b.dataset.area || "") || 0;
+ return (av - bv) * sortDir;
+ }
+ return (a.dataset.name || "").localeCompare(b.dataset.name || "", "ja") * sortDir;
+ });
+ sorted.forEach((row) => tbody.appendChild(row));
+ };
+
+ select?.addEventListener("change", applyFilter);
+ search?.addEventListener("input", applyFilter);
+ checks.forEach((c) => c.addEventListener("change", applyFilter));
+ sortButtons.forEach((btn) => {
+ btn.addEventListener("click", () => {
+ const key = btn.dataset.sort;
+ if (sortKey === key) {
+ sortDir = -sortDir;
+ } else {
+ sortKey = key ?? null;
+ sortDir = 1;
+ }
+ applySort();
+ });
+ });
+ applyFilter();
});
</script>
diff --git a/src/content/docs/kodaira-data/parks.mdx b/src/content/docs/kodaira-data/parks.mdx
index 6cf9576..6887653 100644
--- a/src/content/docs/kodaira-data/parks.mdx
+++ b/src/content/docs/kodaira-data/parks.mdx
@@ -1,11 +1,11 @@
---
title: 小平市の公園一覧
-description: 小平市内の公園321件を、町名やキーワードで検索できる一覧にまとめました。
+description: 小平市内の公園321件を、町名・キーワード・設備で検索できる一覧にまとめました。
---
import ParksTable from '@/components/ParksTable.astro';
-小平市内の公園の一覧です。町名で絞り込んだり、公園名や住所、遊具などのキーワードで検索したりできます。スマートフォンでは表を横にスクロールできます。
+小平市内の公園の一覧です。町名や設備で絞り込んだり、公園名や住所、遊具などのキーワードで検索したりできます。公園名と面積の見出しを押すと、並べ替えられます。住所を押すと、公園名で地図を検索します。スマートフォンでは1件ずつカードで表示します。
<ParksTable />
@@ -13,12 +13,14 @@ import ParksTable from '@/components/ParksTable.astro';
出典は、小平市が公開している次の資料です。
-- 公園名・住所・面積・500㎡以上・ボール遊び:「500㎡以上・未満の小平市立公園一覧(住所順)」(令和6年1月1日現在)
+- 公園名・住所・面積・ボール遊び:「500㎡以上・未満の小平市立公園一覧(住所順)」(令和6年1月1日現在)
- 種別・南西部指定管理:「別紙7 公園一覧」(令和6年度 指定管理者公募)
- トイレ・水飲み場・ベンチ・テーブル・防災用具・遊具:「参考資料7 公園施設一覧(市南西部地域)」(令和6年度 指定管理者公募、公園台帳より)
:::note
-- 施設の情報(トイレ・水飲み場・ベンチ・テーブル・防災用具・遊具)は、市の南西部地域の公園のみです。全市分は公開されていません。
-- 施設の情報は「竣工時のデータが基」との注記があります。現在と異なる場合があります。
-- 空欄は「—」で示しています。出典に記載がないという意味であり、施設がないという意味ではありません。
+- 「種別」は、市の資料にある公園の区分です。街区は街区公園、近隣は近隣公園、運動は運動公園を指します。
+- 面積の「小・中・大」は目安です。小は1000㎡未満、中は1000〜10000㎡、大は10000㎡以上としています。
+- 「種別」と設備(トイレ・水飲み場・遊具など)の情報は、市の南西部地域の公園のみです。全市分は公開されていません。設備の絞り込みは、この情報がある公園だけが対象です。
+- 設備の情報は「竣工時のデータが基」との注記があります。現在と異なる場合があります。
+- 空欄は「—」で示しています。出典に記載がないという意味であり、設備がないという意味ではありません。
:::
diff --git a/src/data/updates.json b/src/data/updates.json
index fc72608..2eabc28 100644
--- a/src/data/updates.json
+++ b/src/data/updates.json
@@ -1,5 +1,12 @@
[
{
+ "title": "小平市の公園一覧",
+ "url": "/kodaira-data/parks/",
+ "group": "",
+ "date": "2026-10-06",
+ "kind": "new"
+ },
+ {
"title": "(1)カーボンニュートラルの虚実を、まず科学的に捉えよ",
"url": "/ippan-situmon/r2d/3gatu/1-carbon-neutral-giman/",
"group": "令和2年3月定例会",
@@ -271,12 +278,5 @@
"group": "令和8年9月定例会",
"date": "2026-09-15",
"kind": "new"
- },
- {
- "title": "(3)いじめ対策委員会記録がほぼ皆無だった件に絡む矛盾について",
- "url": "/ippan-situmon/r8d/9gatu/3-ijime-taisaku-kiroku-mujun/",
- "group": "令和8年9月定例会",
- "date": "2026-09-15",
- "kind": "new"
}
]