diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/ScheduleInteractive.astro | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/src/components/ScheduleInteractive.astro b/src/components/ScheduleInteractive.astro index f0bd73c..8877d9d 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, entryDates, mainStartMonth } from '@/lib/schedule-dates'; + import { parseDates, applyExclusions, toKey, keyToDate, entryDates, mainStartMonth, normalizeDigits } from '@/lib/schedule-dates'; const CATEGORY_DEFS = [ { icon: '👶', label: '子育て' }, @@ -262,6 +262,26 @@ }); } + // 「午前9時から」「午後1時30分から」などの開始時刻を分にして返す。 + // 時刻の記載がないもの(「現地視察のあとに委員会」「予約制」「資料配布のみ」など)は null。 + // 終了時刻が先に出てくる文(「…午後5時まで。開館時間は…午前10時から」)があるため、 + // 「から」「開演」「開始」が続く時刻を優先する。 + function startMinutes(text: string): number | null { + const t = normalizeDigits(text); + const re = /(午前|午後)\s*(\d{1,2})\s*時\s*(?:(\d{1,2})\s*分)?/g; + const found: { minutes: number; end: number }[] = []; + let m: RegExpExecArray | null; + while ((m = re.exec(t)) !== null) { + let hour = Number(m[2]); + if (m[1] === '午後' && hour < 12) hour += 12; + if (m[1] === '午前' && hour === 12) hour = 0; + found.push({ minutes: hour * 60 + (m[3] ? Number(m[3]) : 0), end: m.index + m[0].length }); + } + if (found.length === 0) return /正午/.test(t) ? 12 * 60 : null; + const start = found.find((f) => /^\s*(から|開演|開始|受付)/.test(t.slice(f.end))); + return (start ?? found[0]).minutes; + } + function showDayDetails(key) { if (!key) return; const date = keyToDate(key); @@ -269,6 +289,13 @@ const list = visibleEntries(key) .slice() .sort((a, b) => { + // 開始時刻が分かるものを時刻順に並べ、分からないものは後ろに回す。 + const ta = startMinutes(a.time); + const tb = startMinutes(b.time); + if (ta !== null && tb !== null && ta !== tb) return ta - tb; + if (ta === null && tb !== null) return 1; + if (ta !== null && tb === null) return -1; + // 同時刻や時刻不明のものは、会議を先にして名前順。 if (a.type !== b.type) return a.type === 'meeting' ? -1 : 1; return a.name.localeCompare(b.name, 'ja'); }); |
