Skip to content

Commit deb9f92

Browse files
committed
コンポーネントのインポートをリファクタリングし、レイアウト構造を強化
- Talksページをオブジェクト構造でページを管理する方式に変更し、コンポーネント名の管理とレンダリングを改善。 - DayNavigationコンポーネントを追加し、メニュー内でのカンファレンス日程間のナビゲーションを改善。 - 背景色やボタンスタイルなど、各種コンポーネントのスタイリングを統一し、UI体験の整合性を向上。 - PDF変換ツールを実装。PDFファイルを画像に変換し、ZIPファイルとしてダウンロード可能に。 - キャッシュ処理のため、特定の動画URLをコメントアウトするようサービスワーカーを調整。 - 配色と背景グラデーションを改善するため、Tailwind CSSの設定を更新。
2 parents 819c71e + 1da9be1 commit deb9f92

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2893
-765
lines changed

.env.development

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
NEXT_PUBLIC_API_BASE_URL=http://localhost:8888/
22
# NEXT_PUBLIC_API_BASE_URL=https://event.cloudnativedays.jp/
3-
NEXT_PUBLIC_EVENT_ABBR=srekaigi
3+
NEXT_PUBLIC_EVENT_ABBR=janog
44
NEXT_PUBLIC_DK_EVENT_ABBR=cndw2025
55
NEXT_PUBLIC_DEBUG='true'
66
# BGM の長さを音はめする 長さ全部: 111.33sec Notize_-_Mirror_Ball.mp3

.env.production

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# NEXT_PUBLIC_API_BASE_URL=https://dreamkast-dk-2666.dev.cloudnativedays.jp
22
# NEXT_PUBLIC_API_BASE_URL=https://staging.dev.cloudnativedays.jp/
33
NEXT_PUBLIC_API_BASE_URL=https://event.cloudnativedays.jp/
4-
NEXT_PUBLIC_EVENT_ABBR=srekaigi
4+
NEXT_PUBLIC_EVENT_ABBR=janog
55
NEXT_PUBLIC_DK_EVENT_ABBR=cndw2025
66
# NEXT_PUBLIC_DEBUG='true'
77
# BGM の長さを音はめする 長さ全部: 111.33sec Notize_-_Mirror_Ball.mp3

next.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
/** @type {import('next').NextConfig} */
33
const nextConfig = {
44
optimizeFonts: false,
5+
images: {
6+
domains: ['www.janog.gr.jp'],
7+
},
58
}
69

710
const isDev = process.env.NODE_ENV !== 'production'

public/janog57/background.png

72.1 KB
Loading

public/janog57/image.png

51.7 KB
Loading

script/janog/convert.ts

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
// JANOGのAPIデータを元に、セッション・スピーカー情報を生成するスクリプト
2+
// APIエンドポイント:
3+
// - https://ai-chat.janog57.sakura.ad.jp/api/rooms/
4+
// - https://ai-chat.janog57.sakura.ad.jp/api/programs/
5+
// - https://ai-chat.janog57.sakura.ad.jp/api/speakers/
6+
// 変換先フォーマット: src/data/xxx.ts (Track, Speaker, Talk)
7+
// 実行コマンド: npx tsx ./script/janog/convert.ts && npm run fmt
8+
9+
import { janogProgramItem, janogSpeaker, janogRoom } from './type.js'
10+
import { Track, Speaker, Talk } from '../../src/data/types.js'
11+
import { exportEventData } from '../common/utils.js'
12+
13+
const API_BASE_URL: string = 'https://ai-chat.janog57.sakura.ad.jp/api'
14+
15+
const eventImageUrl: string =
16+
'https://www.janog.gr.jp/meeting/janog57/wp-content/uploads/2024/11/JANOG57-logo.png'
17+
18+
const conferenceDays = [
19+
{ id: 1, date: '2026-02-11' },
20+
{ id: 2, date: '2026-02-12' },
21+
{ id: 3, date: '2026-02-13' },
22+
]
23+
24+
// 手動で追加するトーク(最小限の情報)
25+
// IDは 9000番台を使用して自動生成されるIDと重複を避ける
26+
const manualTalks: Partial<Talk>[] = [
27+
// 必要に応じて追加
28+
]
29+
30+
/**
31+
* メイン処理関数
32+
*/
33+
async function main() {
34+
// APIからデータを取得する
35+
const [rooms, programs, speakersData] = await Promise.all([
36+
fetchRooms(),
37+
fetchPrograms(),
38+
fetchSpeakers(),
39+
])
40+
41+
// Track情報を生成する
42+
const tracks: Track[] = convertToTracks(rooms)
43+
44+
// Speaker情報を生成する(id:0でJANOG57を追加)
45+
const speakers: Speaker[] = [
46+
{
47+
id: 0,
48+
name: 'JANOG57',
49+
avatarUrl: eventImageUrl,
50+
},
51+
...convertToSpeakers(speakersData),
52+
]
53+
54+
// Talk情報を生成する
55+
const talks: Talk[] = convertToTalks(programs, speakers, rooms)
56+
57+
// 手動で追加したトークをマージ
58+
const allTalks: Talk[] = [...(manualTalks as Talk[]), ...talks].sort(
59+
(a, b) => {
60+
if (a.startTime < b.startTime) return -1
61+
if (a.startTime > b.startTime) return 1
62+
return 0
63+
}
64+
)
65+
66+
// 最終データを組み立てる
67+
exportEventData({ tracks, speakers, talks: allTalks })
68+
}
69+
70+
/**
71+
* Rooms APIからデータを取得する
72+
*/
73+
async function fetchRooms(): Promise<janogRoom[]> {
74+
const url = `${API_BASE_URL}/rooms/`
75+
const data: janogRoom[] = await fetch(url).then((res) => res.json())
76+
return data
77+
}
78+
79+
/**
80+
* Programs APIからデータを取得する
81+
*/
82+
async function fetchPrograms(): Promise<janogProgramItem[]> {
83+
const url = `${API_BASE_URL}/programs/`
84+
const data: janogProgramItem[] = await fetch(url).then((res) => res.json())
85+
return data
86+
}
87+
88+
/**
89+
* Speakers APIからデータを取得する
90+
*/
91+
async function fetchSpeakers(): Promise<janogSpeaker[]> {
92+
const url = `${API_BASE_URL}/speakers/`
93+
const data: janogSpeaker[] = await fetch(url).then((res) => res.json())
94+
return data
95+
}
96+
97+
/**
98+
* RoomデータからTrack情報を生成する
99+
*/
100+
function convertToTracks(rooms: janogRoom[]): Track[] {
101+
return rooms.map((room) => ({
102+
id: room.id,
103+
name: room.name,
104+
hashTag: 'janog57',
105+
}))
106+
}
107+
108+
/**
109+
* SpeakerデータからSpeaker情報を生成する
110+
*/
111+
function convertToSpeakers(speakersData: janogSpeaker[]): Speaker[] {
112+
const DEFAULT_IMAGE_PATH: string = eventImageUrl
113+
114+
return speakersData.map((speaker) => ({
115+
id: speaker.id,
116+
name: speaker.name,
117+
avatarUrl: speaker.avatar_url || DEFAULT_IMAGE_PATH,
118+
}))
119+
}
120+
121+
/**
122+
* プログラムデータからTalk情報を生成する
123+
*/
124+
function convertToTalks(
125+
programs: janogProgramItem[],
126+
speakers: Speaker[],
127+
rooms: janogRoom[]
128+
): Talk[] {
129+
const convertedTalks: Talk[] = []
130+
131+
programs
132+
.sort((a, b) => {
133+
// 日付と開始時間でソート
134+
const aDateTime = `${a.date}T${a.start_time}`
135+
const bDateTime = `${b.date}T${b.start_time}`
136+
if (aDateTime < bDateTime) return -1
137+
if (aDateTime > bDateTime) return 1
138+
return 0
139+
})
140+
.forEach((program) => {
141+
const room = rooms.find((r) => r.id === program.room.id)
142+
if (!room) {
143+
console.warn(
144+
`No room found for program: ${program.title} (room id: ${program.room.id})`
145+
)
146+
return
147+
}
148+
149+
// スピーカー情報を取得(いない場合は「JANOG57」を割り当て)
150+
const talkSpeakers =
151+
program.speakers && program.speakers.length > 0
152+
? program.speakers.map((s: janogSpeaker) => {
153+
const speaker = speakers.find((sp) => sp.id === s.id)
154+
return {
155+
id: speaker?.id || s.id,
156+
name: speaker?.name || s.name,
157+
}
158+
})
159+
: [{ id: 0, name: 'JANOG57' }]
160+
161+
// startTimeとendTimeを生成(ISO 8601形式)
162+
// APIが HH:MM:SS 形式を返す場合はそのまま、HH:MM 形式なら :00 を追加
163+
const formatTime = (time: string) =>
164+
time.split(':').length === 2 ? `${time}:00` : time
165+
const startTime = `${program.date}T${formatTime(program.start_time)}+09:00`
166+
const endTime = `${program.date}T${formatTime(program.end_time)}+09:00`
167+
168+
convertedTalks.push({
169+
id: program.id,
170+
trackId: room.id,
171+
title: program.title,
172+
abstract: program.abstract?.replace(/[\r\t\n]/g, '') || '',
173+
speakers: talkSpeakers,
174+
startTime,
175+
endTime,
176+
conferenceDayId: conferenceDays.find((day) => program.date === day.date)
177+
?.id,
178+
} as Talk)
179+
})
180+
181+
return convertedTalks
182+
}
183+
184+
main().catch(console.error)

script/janog/type.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
export type janogRoom = {
2+
id: number
3+
name: string
4+
location: string
5+
}
6+
7+
export type janogProgramItem = {
8+
id: number
9+
title: string
10+
date: string
11+
start_time: string
12+
end_time: string
13+
room: janogRoom
14+
speakers: janogSpeaker[]
15+
abstract: string
16+
url: string
17+
}
18+
19+
export type janogSpeaker = {
20+
id: number
21+
name: string
22+
company: string
23+
avatar_url: string
24+
program: number
25+
ordering: number
26+
}

src/app/animation/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import dynamic from 'next/dynamic'
44

5-
const PixiApp = dynamic(() => import('../../components/PixiApp'), {
5+
const PixiApp = dynamic(() => import('../../components/media/PixiApp'), {
66
ssr: false,
77
})
88

0 commit comments

Comments
 (0)