Skip to content

Commit 857dcef

Browse files
committed
Merge branch 'add-time-table-page'
2 parents 166f4fc + ea321c8 commit 857dcef

File tree

6 files changed

+493
-0
lines changed

6 files changed

+493
-0
lines changed

_data/time_table.yml

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
slot_minutes: 10
2+
3+
rooms:
4+
- 大会議室 (セッション)
5+
- 展示 (コンテスト用)
6+
- 展示
7+
- 中会議室 (WS1 電子工作)
8+
- 中会議室 (WS2 LTブース)
9+
- 中会議室 (WS3)
10+
- 中会議室 (WS4)
11+
12+
room_styles:
13+
大会議室 (セッション): { color: "#c43b3b" }
14+
展示 (コンテスト用): { color: "#f5a201" }
15+
展示: { color: "#888888" }
16+
中会議室 (WS1 電子工作): { color: "#2e7d32" }
17+
中会議室 (WS2 LTブース): { color: "#1976d2" }
18+
中会議室 (WS3): { color: "#7b1fa2" }
19+
中会議室 (WS4): { color: "#ef6c00" }
20+
21+
events:
22+
# 大会議室 (セッション)
23+
- room: "大会議室 (セッション)"
24+
start: "10:00"
25+
end: "10:10"
26+
title: "開会式"
27+
28+
- room: "大会議室 (セッション)"
29+
start: "10:10"
30+
end: "10:20"
31+
title: "基調講演 (宮島さん)"
32+
link: "/sessions/keynote1/"
33+
34+
- room: "大会議室 (セッション)"
35+
start: "11:00"
36+
end: "12:00"
37+
title: "コンテスト作品発表"
38+
39+
- room: "大会議室 (セッション)"
40+
start: "12:00"
41+
end: "12:40"
42+
title: "ランチタイム"
43+
note: "適宜お昼をお取りください"
44+
45+
- room: "大会議室 (セッション)"
46+
start: "12:40"
47+
end: "13:00"
48+
title: "みんなのセッション"
49+
50+
- room: "大会議室 (セッション)"
51+
start: "13:40"
52+
end: "14:00"
53+
title: "九州チャンピオン座談会"
54+
55+
- room: "大会議室 (セッション)"
56+
start: "14:20"
57+
end: "14:40"
58+
title: "スピーカーセッション とり子さん (20分)"
59+
60+
- room: 大会議室 (セッション)
61+
start: "14:40"
62+
end: "14:50"
63+
title: "伸びるかも予備"
64+
65+
- room: "大会議室 (セッション)"
66+
start: "14:50"
67+
end: "15:10"
68+
title: "スピーカーセッション 早良区Dojoチャンピオン (20分)"
69+
70+
- room: "大会議室 (セッション)"
71+
start: "15:10"
72+
end: "15:20"
73+
title: "スポンサーセッション (2件)"
74+
75+
- room: "大会議室 (セッション)"
76+
start: "15:20"
77+
end: "15:30"
78+
title: "招待講演 (小宮山さん)"
79+
link: "/sessions/keynote2/"
80+
81+
- room: "大会議室 (セッション)"
82+
start: "16:00"
83+
end: "16:10"
84+
title: "コンテスト結果発表"
85+
86+
- room: "大会議室 (セッション)"
87+
start: "16:10"
88+
end: "16:20"
89+
title: "スポンサーセッション (1件)"
90+
note: "該当なしの場合は CoderDojo Japan 活動報告"
91+
92+
- room: "大会議室 (セッション)"
93+
start: "16:20"
94+
end: "16:30"
95+
title: "閉会式"
96+
97+
# 展示
98+
- room: "展示 (コンテスト用)"
99+
start: "10:00"
100+
end: "16:00"
101+
title: "ファイナリスト作品展示"
102+
note: "14:00 投票締切"
103+
104+
- room: "展示"
105+
start: "10:00"
106+
end: "16:00"
107+
title: "展示"
108+
109+
# WS1 電子工作 (随時受付)
110+
- room: "中会議室 (WS1 電子工作)"
111+
start: "11:00"
112+
end: "16:00"
113+
title: "電子工作ワークショップ (随時受付)"
114+
115+
# WS2 LTブース
116+
- room: "中会議室 (WS2 LTブース)"
117+
start: "11:20"
118+
end: "12:00"
119+
title: "Dojo関係者等大人LT (要申込)"
120+
121+
- room: "中会議室 (WS2 LTブース)"
122+
start: "13:00"
123+
end: "14:00"
124+
title: "DojoニンジャLT (要申込)"
125+
126+
# WS3
127+
- room: "中会議室 (WS3)"
128+
start: "11:00"
129+
end: "12:00"
130+
title: "ブレンダー (要申込)"
131+
132+
- room: "中会議室 (WS3)"
133+
start: "13:00"
134+
end: "14:00"
135+
title: "PLAYRISE"
136+
137+
# WS4
138+
- room: "中会議室 (WS4)"
139+
start: "11:00"
140+
end: "12:00"
141+
title: "PowerPoint とプログラミング"
142+
143+
- room: "中会議室 (WS4)"
144+
start: "14:10"
145+
end: "15:00"
146+
title: "PowerPoint とプログラミング"

_pages/time-table.html

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
---
2+
layout: default
3+
permalink: /time-table/
4+
title: タイムテーブル
5+
---
6+
{% include navbar.html %}
7+
8+
{% comment %}
9+
Jekyll プラグインで事前計算されたタイムテーブル表を使用
10+
ロジックはプラグインで計算済み。Liquid は描画のみを担当
11+
{% endcomment %}
12+
13+
{% assign tte = site.data.time_table_events %}
14+
{% assign events = tte.events %}
15+
{% assign rooms = tte.rooms %}
16+
{% assign time_labels = tte.time_labels %}
17+
{% assign total_slots = tte.total_slots %}
18+
{% assign total_rooms = tte.total_rooms %}
19+
20+
<section class="w-[calc(100dvw-40px)] max-w-7xl mx-auto mt-25 xl:mt-5">
21+
<h2 class="text-4xl text-center mb-8">
22+
Time table
23+
<span class="block mt-3 text-2xl">タイムテーブル</span>
24+
</h2>
25+
<div class="overflow-x-auto border-[1px] border-[#e6e6e9]" aria-label="タイムテーブル(横スクロール可)">
26+
<table class="ttable" style="--room-count: {{ rooms | size }};">
27+
<thead>
28+
<tr>
29+
<th scope="col" class="ttable__th ttable__th--start">時間</th>
30+
{% comment %} ルーム単位でヘッダーを描画 {% endcomment %}
31+
{% for room in rooms %}
32+
<th scope="col"
33+
class="ttable__th ttable__th--room"
34+
style="--room-color: {{ room.style.color | default: '#c43b3b' }};">
35+
<span class="ttable__room-cap">{{ room.name }}</span>
36+
</th>
37+
{% endfor %}
38+
</tr>
39+
</thead>
40+
41+
<tbody>
42+
{% comment %} スロット単位(行単位)でイベントを描画 {% endcomment %}
43+
{% for slot in (0..total_slots) %}
44+
<tr>
45+
<th scope="row" class="ttable__cell ttable__cell--start">{{ time_labels[slot] }}</th>
46+
47+
{% comment %} 各イベントを描画 {% endcomment %}
48+
{% for room_index in (0..total_rooms) %}
49+
{% assign event = events[slot][room_index] %}
50+
{% assign room = rooms[room_index] %}
51+
52+
{% if event == 'continued' %}
53+
{% comment %} イベント継続中 (rowspan で描画するため出力は不要) {% endcomment %}
54+
{% elsif event %}
55+
{% comment %} イベントを描画 {% endcomment %}
56+
{% assign accent = event.accent | default: room.style.color | default: '#c43b3b' %}
57+
{% assign link_url = event.url | default: event.link %}
58+
59+
<td class="ttable__cell ttable__cell--event"
60+
rowspan="{{ event.duration }}"
61+
style="--span: {{ event.duration }};">
62+
{% if link_url %}
63+
<a class="ttable__event" href="{{ link_url | relative_url }}" style="--accent: {{ accent }};">
64+
{% else %}
65+
<div class="ttable__event" style="--accent: {{ accent }};">
66+
{% endif %}
67+
<div class="ttable__event-time" >{{ event.start }}–{{ event.end }}</div>
68+
<div class="ttable__event-title">{{ event.title }}</div>
69+
{% if event.subtitle %}<div class="ttable__event-subtitle">{{ event.subtitle }}</div>{% endif %}
70+
{% if event.badge %}<span class="ttable__badge">{{ event.badge }}</span>{% endif %}
71+
{% if event.note %}<div class="ttable__event-note">{{ event.note }}</div>{% endif %}
72+
{% if link_url %}
73+
</a>
74+
{% else %}
75+
</div>
76+
{% endif %}
77+
</td>
78+
{% else %}
79+
{% comment %} イベント無し {% endcomment %}
80+
<td class="ttable__cell ttable__cell--empty" aria-label="空き時間"></td>
81+
{% endif %}
82+
{% endfor %}
83+
</tr>
84+
{% endfor %}
85+
</tbody>
86+
</table>
87+
</div>
88+
</section>

_plugins/time_table_generator.rb

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
module Jekyll
2+
module TimeTableGenerator
3+
# タイムテーブル表を事前に計算してイベント表形式に変換
4+
# これにより、Liquid テンプレートは単純な表示のみを担当
5+
class Generator < Jekyll::Generator
6+
safe true
7+
priority :high
8+
9+
# デフォルト設定値
10+
DEFAULT_SLOT_MINUTES = 15
11+
DEFAULT_DAY_START_HOUR = 10 # 10:00
12+
DEFAULT_DAY_END_HOUR = 16 # 16:00
13+
14+
def generate(site)
15+
tt = site.data['time_table']
16+
return unless tt
17+
18+
# 設定値を取得
19+
slot_minutes = tt.fetch('slot_minutes', DEFAULT_SLOT_MINUTES)
20+
day_start = tt.fetch('day_start_hour', DEFAULT_DAY_START_HOUR)
21+
day_end = tt.fetch('day_end_hour', DEFAULT_DAY_END_HOUR)
22+
rooms = tt.fetch('rooms', [])
23+
events = tt.fetch('events', [])
24+
room_styles = tt.fetch('room_styles', {})
25+
26+
# イベント情報を表形式で生成
27+
time_table_events = create_event_table(events, rooms, room_styles, slot_minutes, day_start, day_end)
28+
29+
# 生成したイベント表データを Liquid に提供
30+
site.data['time_table_events'] = time_table_events
31+
end
32+
33+
private
34+
35+
def create_event_table(events, rooms, room_styles, slot_minutes, day_start, day_end)
36+
total_slots = ((day_end - day_start) * 60 / slot_minutes).to_i
37+
38+
# 時間ラベルを生成
39+
time_labels = (0...total_slots).map do |slot|
40+
minutes = day_start * 60 + slot * slot_minutes
41+
"#{minutes / 60}:%02d" % (minutes % 60)
42+
end
43+
44+
# ルーム情報を生成(room.style でアクセス可能)
45+
rooms_data = rooms.map do |room_name|
46+
{
47+
'name' => room_name,
48+
'style' => room_styles[room_name] || {}
49+
}
50+
end
51+
52+
# イベント表を生成(2次元配列)
53+
table = Array.new(total_slots) { Array.new(rooms.size) }
54+
55+
events.each do |event|
56+
place_event(event, table, rooms, slot_minutes, day_start, total_slots)
57+
end
58+
59+
{
60+
'events' => table,
61+
'rooms' => rooms_data,
62+
'time_labels' => time_labels,
63+
'total_slots' => total_slots - 1, # Liquidの (0..n) は inclusive なので -1
64+
'total_rooms' => rooms.size - 1, # Liquidの (0..n) は inclusive なので -1
65+
}
66+
end
67+
68+
def place_event(event, table, rooms, slot_minutes, day_start, total_slots)
69+
room_index = rooms.index(event['room'])
70+
return unless room_index
71+
72+
# 時間を分に変換して揃える
73+
event_start = time_to_minutes(event['start'])
74+
event_end = time_to_minutes(event['end'])
75+
76+
# スロット計算(分に揃える)
77+
slot_start = [(event_start - day_start * 60) / slot_minutes, 0].max.to_i
78+
slot_end = [(event_end - day_start * 60) / slot_minutes, total_slots].min.to_i
79+
duration = slot_end - slot_start
80+
81+
return if slot_start >= total_slots || duration <= 0
82+
83+
# イベントの長さ情報 (duration) を追加
84+
table[slot_start][room_index] = event.merge('duration' => duration)
85+
86+
# 継続スロットをマーク
87+
(slot_start + 1...slot_end).each do |slot|
88+
break if slot >= total_slots
89+
table[slot][room_index] = 'continued'
90+
end
91+
end
92+
93+
def time_to_minutes(time_str)
94+
return 0 unless time_str
95+
hours, minutes = time_str.split(':').map(&:to_i)
96+
hours * 60 + minutes
97+
end
98+
end
99+
end
100+
end

0 commit comments

Comments
 (0)