aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/ScheduleInteractive.astro14
-rw-r--r--src/components/ScheduleMonthLinks.astro16
-rw-r--r--src/components/ScheduleTable.astro6
-rw-r--r--src/content/docs/kodaira-data/events.mdx7
-rw-r--r--src/data/updates.json14
-rw-r--r--src/lib/schedule-dates.ts20
-rw-r--r--src/lib/schedule-months.ts44
-rw-r--r--src/pages/kodaira-data/events/[month].astro72
-rw-r--r--src/styles/custom.css23
9 files changed, 195 insertions, 21 deletions
diff --git a/src/components/ScheduleInteractive.astro b/src/components/ScheduleInteractive.astro
index 3dd6048..424b453 100644
--- a/src/components/ScheduleInteractive.astro
+++ b/src/components/ScheduleInteractive.astro
@@ -1,7 +1,7 @@
<script>
// URLは src/data/schedule/config.ts で一元管理している(ページ移転時はそこだけ変える)
import { scheduleAbsoluteUrl } from '@/data/schedule/config';
- import { parseDates, applyExclusions, toKey, keyToDate } from '@/lib/schedule-dates';
+ import { parseDates, applyExclusions, toKey, keyToDate, entryDates } from '@/lib/schedule-dates';
const CATEGORY_DEFS = [
{ icon: '👶', label: '子育て' },
@@ -63,17 +63,7 @@
}
row.dataset.category = category;
- const dates = new Set(parseDates(dateText));
- // 審議会の「毎月1回(11月12日、…も開催)」のように、
- // 時間・会場欄に追加の開催日が書かれている場合がある。
- if (type === 'meeting') {
- for (const key of parseDates(timeText)) dates.add(key);
- }
- // イベントの「(11月4日を除く)」を反映する。
- if (type === 'event') {
- // 時間欄の「(11月4日を除く)」を日付セル側の集合に反映する。
- applyExclusions(dates, timeText);
- }
+ const dates = new Set(entryDates(type, dateText, timeText));
entries.push({
type,
diff --git a/src/components/ScheduleMonthLinks.astro b/src/components/ScheduleMonthLinks.astro
new file mode 100644
index 0000000..8628998
--- /dev/null
+++ b/src/components/ScheduleMonthLinks.astro
@@ -0,0 +1,16 @@
+---
+// 月別アーカイブのリンク一覧。行事予定ページの下部に置く。
+import { monthCounts, monthKeys, monthLabel } from '@/lib/schedule-months';
+import { scheduleUrl } from '@/data/schedule/config';
+---
+
+<ul class="schedule-month-archive">
+ {
+ monthKeys.map((key) => (
+ <li>
+ <a href={scheduleUrl(`${key}/`)}>{monthLabel(key)}の予定</a>
+ <span class="schedule-month-count">{monthCounts[key]}件</span>
+ </li>
+ ))
+ }
+</ul>
diff --git a/src/components/ScheduleTable.astro b/src/components/ScheduleTable.astro
index 2f4b370..ff13827 100644
--- a/src/components/ScheduleTable.astro
+++ b/src/components/ScheduleTable.astro
@@ -7,8 +7,10 @@ import events from '@/data/schedule/events.json';
type Row = { date: string; title: string; place: string; note: string; source: string };
type TableData = { columns: string[]; rows: Row[] };
-const { variant } = Astro.props as { variant: 'meeting' | 'event' };
-const data: TableData = (variant === 'meeting' ? meetings : events) as TableData;
+const { variant, rows } = Astro.props as { variant: 'meeting' | 'event'; rows?: Row[] };
+const base: TableData = (variant === 'meeting' ? meetings : events) as TableData;
+// rows を渡された場合はその行だけを表示する(月別アーカイブ用)
+const data: TableData = rows ? { columns: base.columns, rows } : base;
---
<table>
diff --git a/src/content/docs/kodaira-data/events.mdx b/src/content/docs/kodaira-data/events.mdx
index a97f7c1..3455427 100644
--- a/src/content/docs/kodaira-data/events.mdx
+++ b/src/content/docs/kodaira-data/events.mdx
@@ -8,6 +8,7 @@ import ScheduleInteractive from '../../../components/ScheduleInteractive.astro';
import ScheduleMap from '../../../components/ScheduleMap.astro';
import ScheduleSeo from '../../../components/ScheduleSeo.astro';
import ScheduleTable from '../../../components/ScheduleTable.astro';
+import ScheduleMonthLinks from '../../../components/ScheduleMonthLinks.astro';
<ScheduleSeo />
@@ -87,6 +88,12 @@ import ScheduleTable from '../../../components/ScheduleTable.astro';
{/* <!-- textlint-enable --> */}
+## 月別のアーカイブ
+
+過去の月の予定は、月ごとのページで見られます。
+
+<ScheduleMonthLinks />
+
## ご注意
イベントの内容・日程は変更になることがあります。最新の情報は、各問い合わせ先または市公式Xでご確認ください。
diff --git a/src/data/updates.json b/src/data/updates.json
index 8a245b4..64cd370 100644
--- a/src/data/updates.json
+++ b/src/data/updates.json
@@ -1,5 +1,12 @@
[
{
+ "title": "小平市ホームページのアーカイブ(暫定)と市の案内",
+ "url": "/kodaira-data/hp-archive/",
+ "group": "",
+ "date": "2026-11-05",
+ "kind": "update"
+ },
+ {
"title": "行政不服審査会の問題追及の軌跡",
"url": "/gyosei-fufuku-sinsa/",
"group": "",
@@ -21,13 +28,6 @@
"kind": "update"
},
{
- "title": "小平市ホームページのアーカイブ(暫定)と市の案内",
- "url": "/kodaira-data/hp-archive/",
- "group": "",
- "date": "2026-11-04",
- "kind": "update"
- },
- {
"title": "こだいら 公園さんぽマップ",
"url": "/kodaira-data/parks/",
"group": "",
diff --git a/src/lib/schedule-dates.ts b/src/lib/schedule-dates.ts
index 5f0900b..719a9c6 100644
--- a/src/lib/schedule-dates.ts
+++ b/src/lib/schedule-dates.ts
@@ -128,3 +128,23 @@ export function parseDates(raw: string): string[] {
return [...dates].sort();
}
+
+/**
+ * 行事予定1行分の開催日を求める。
+ * - 会議:日付セルに加えて、時間・会場セル内の日付も拾う(「毎月1回(11月12日も開催)」など)
+ * - イベント:時間セルの「(11月4日を除く)」を反映する
+ * カレンダー(ブラウザ)と月別アーカイブ(ビルド時)で同じ結果になるよう、ここに集約する。
+ */
+export function entryDates(
+ type: 'meeting' | 'event',
+ dateText: string,
+ placeText: string,
+): string[] {
+ const dates = new Set(parseDates(dateText));
+ if (type === 'meeting') {
+ for (const key of parseDates(placeText)) dates.add(key);
+ } else {
+ applyExclusions(dates, placeText);
+ }
+ return [...dates].sort();
+}
diff --git a/src/lib/schedule-months.ts b/src/lib/schedule-months.ts
new file mode 100644
index 0000000..cd109b7
--- /dev/null
+++ b/src/lib/schedule-months.ts
@@ -0,0 +1,44 @@
+// 行事予定データを月ごとに集計する(ビルド時専用)。
+//
+// 注意: このモジュールは JSON を import するため、ブラウザ用スクリプトからは読み込まないこと。
+// (カレンダー側が必要とする日付計算は src/lib/schedule-dates.ts にある)
+import meetings from '@/data/schedule/meetings.json';
+import events from '@/data/schedule/events.json';
+import { entryDates } from './schedule-dates';
+
+export type Row = { date: string; title: string; place: string; note: string; source: string };
+export type Item = { type: 'meeting' | 'event'; row: Row };
+
+export const items: Item[] = [
+ ...(meetings.rows as Row[]).map((row) => ({ type: 'meeting' as const, row })),
+ ...(events.rows as Row[]).map((row) => ({ type: 'event' as const, row })),
+];
+
+const datesOf = (item: Item) => entryDates(item.type, item.row.date, item.row.place);
+
+/** 月ごとの件数(会議・イベントの合計) */
+export const monthCounts: Record<string, number> = (() => {
+ const counts: Record<string, number> = {};
+ for (const item of items) {
+ for (const date of new Set(datesOf(item).map((d) => d.slice(0, 7)))) {
+ counts[date] = (counts[date] ?? 0) + 1;
+ }
+ }
+ return counts;
+})();
+
+/** データに存在する月(YYYY-MM、昇順) */
+export const monthKeys: string[] = Object.keys(monthCounts).sort();
+
+/** 指定した月に開催される行だけを返す */
+export function rowsInMonth(month: string, type: 'meeting' | 'event'): Row[] {
+ return items
+ .filter((item) => item.type === type && datesOf(item).some((d) => d.startsWith(month)))
+ .map((item) => item.row);
+}
+
+/** 年月の表示(2026-11 → 2026年11月) */
+export function monthLabel(key: string): string {
+ const [y, m] = key.split('-').map(Number);
+ return `${y}年${m}月`;
+}
diff --git a/src/pages/kodaira-data/events/[month].astro b/src/pages/kodaira-data/events/[month].astro
new file mode 100644
index 0000000..1969cee
--- /dev/null
+++ b/src/pages/kodaira-data/events/[month].astro
@@ -0,0 +1,72 @@
+---
+// 月別アーカイブ(/kodaira-data/events/2026-11/ など)。
+// 行事予定のデータ(src/data/schedule/*.json)から、その月の予定だけを静的に生成する。
+import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
+import ScheduleTable from '@/components/ScheduleTable.astro';
+import { monthKeys, monthLabel, rowsInMonth } from '@/lib/schedule-months';
+import { SCHEDULE_BASE_PATH } from '@/data/schedule/config';
+
+export function getStaticPaths() {
+ return monthKeys.map((month, i) => ({
+ params: { month },
+ props: {
+ month,
+ prev: monthKeys[i - 1] ?? null,
+ next: monthKeys[i + 1] ?? null,
+ },
+ }));
+}
+
+const { month, prev, next } = Astro.props as {
+ month: string;
+ prev: string | null;
+ next: string | null;
+};
+
+const label = monthLabel(month);
+const meetingRows = rowsInMonth(month, 'meeting');
+const eventRows = rowsInMonth(month, 'event');
+
+const url = (key: string) => `${SCHEDULE_BASE_PATH}${key}/`;
+---
+
+<StarlightPage
+ frontmatter={{
+ title: `小平市のイベント・行事予定(${label})`,
+ description: `${label}の小平市のイベントと、審議会・市議会の開催予定の一覧です。日程・会場・申込期限を確認できます。`,
+ }}
+>
+ <p><a href={SCHEDULE_BASE_PATH}>← 小平市のイベント・行事予定カレンダー(今後)に戻る</a></p>
+
+ <p>
+ {label}の小平市のイベントと、審議会等・市議会の開催予定です。開催日が過ぎたものも記録として掲載しています。
+ 変更になることがありますので、各問い合わせ先へご確認ください。
+ </p>
+
+ {
+ meetingRows.length > 0 && (
+ <>
+ <h2>審議会等・市議会の開催予定</h2>
+ <div class="schedule-table schedule-table--date-nowrap">
+ <ScheduleTable variant="meeting" rows={meetingRows} />
+ </div>
+ </>
+ )
+ }
+
+ {
+ eventRows.length > 0 && (
+ <>
+ <h2>イベント</h2>
+ <div class="schedule-table">
+ <ScheduleTable variant="event" rows={eventRows} />
+ </div>
+ </>
+ )
+ }
+
+ <nav class="schedule-month-nav" aria-label="月の移動">
+ {prev ? <a href={url(prev)}>← {monthLabel(prev)}</a> : <span />}
+ {next ? <a href={url(next)}>{monthLabel(next)} →</a> : <span />}
+ </nav>
+</StarlightPage>
diff --git a/src/styles/custom.css b/src/styles/custom.css
index 8a27700..82b5c9f 100644
--- a/src/styles/custom.css
+++ b/src/styles/custom.css
@@ -2254,6 +2254,29 @@ td.sanpi-open .sanpi-title {
font-size: 0.88rem;
line-height: 1.7;
}
+.schedule-month-archive {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.4rem 1.2rem;
+ margin: 0.6rem 0 1.2rem;
+ padding: 0;
+ list-style: none;
+}
+.schedule-month-archive li {
+ display: flex;
+ align-items: baseline;
+ gap: 0.35rem;
+}
+.schedule-month-count {
+ color: var(--sl-color-gray-3);
+ font-size: 0.8rem;
+}
+.schedule-month-nav {
+ display: flex;
+ justify-content: space-between;
+ gap: 1rem;
+ margin: 1.5rem 0 0.5rem;
+}
.schedule-updated {
margin: 0.2rem 0 1rem;
color: var(--sl-color-gray-3);