1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
// 行事予定データを月ごとに集計する(ビルド時専用)。
//
// 注意: このモジュールは JSON を import するため、ブラウザ用スクリプトからは読み込まないこと。
// (カレンダー側が必要とする日付計算は src/lib/schedule-dates.ts にある)
import meetings from '@/data/schedule/meetings.json';
import events from '@/data/schedule/events.json';
import { archiveEndMonth, 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}月`;
}
/** 月キー → 年度キー(令和8年度は r8。4月〜翌年3月) */
export function fiscalYearOf(month: string): string {
const [y, m] = month.split('-').map(Number);
const startYear = m >= 4 ? y : y - 1;
return `r${startYear - 2018}`;
}
/** データに存在する年度(昇順) */
export const fiscalYearKeys: string[] = [...new Set(monthKeys.map(fiscalYearOf))].sort();
/** 年度に含まれる月キー(データにある月だけ) */
export function monthsInFiscalYear(fy: string): string[] {
return monthKeys.filter((month) => fiscalYearOf(month) === fy);
}
/** 年度の表示(r8 → 令和8年度) */
export function fiscalYearLabel(fy: string): string {
return `令和${Number(fy.slice(1))}年度`;
}
/** 複数の月のいずれかに開催される行を返す */
export function rowsInMonths(months: string[], type: 'meeting' | 'event'): Row[] {
const inMonths = (item: Item) =>
datesOf(item).some((date) => months.includes(date.slice(0, 7)));
return items
.filter((item) => item.type === type && inMonths(item))
.map((item) => item.row);
}
/** 年度に開催される行を返す */
export function rowsInFiscalYear(fy: string, type: 'meeting' | 'event'): Row[] {
return rowsInMonths(monthsInFiscalYear(fy), type);
}
/**
* アーカイブ(月別・年度別ページ)に移す月。前々月以前。
* 前月と当月以降はメインページに残すので、ここには含めない。
*/
export const archiveMonthKeys: string[] = monthKeys.filter(
(month) => month <= archiveEndMonth(),
);
/** アーカイブに移す年度(その年度の最後の月が前々月以前のもの) */
export const archiveFiscalYearKeys: string[] = fiscalYearKeys.filter((fy) => {
const months = monthsInFiscalYear(fy);
return months.length > 0 && months[months.length - 1] <= archiveEndMonth();
});
|