PageSourceSearch

https://komekaigi.dev/2025/js/speakers.js

js komekaigi.dev collected 2026-09-26 04:37:33 UTC 3,556 bytes, 105 lines download raw bytes

1/**
2 * KomeKaigi スピーカー表示機能
3 */
4(function(window, document) {
5    'use strict';
6
7    // 設定
8    const CONFIG = {
9        DATA_URL: 'data/speakers.json',
10        SECTION_ID: 'sessions',
11        CONTAINER_SELECTOR: '#sessions .flex'
12    };
13
14    /**
15     * スピーカーセクションを非表示にする
16     */
17    function hideSpeakersSection() {
18        const container = document.querySelector(CONFIG.CONTAINER_SELECTOR);
19        if (container) {
20            container.innerHTML = '';
21        }
22        const sessionsSection = document.getElementById(CONFIG.SECTION_ID);
23        if (sessionsSection) {
24            sessionsSection.style.display = 'none';
25        }
26    }
27
28    /**
29     * スピーカーデータを取得して表示
30     */
31    async function loadSpeakers() {
32        try {
33            const response = await fetch(CONFIG.DATA_URL);
34            if (!response.ok) {
35                throw new Error(`HTTP error! status: ${response.status}`);
36            }
37            const data = await response.json();
38            
39            renderSpeakerCards(data.sessions || []);
40            
41        } catch (error) {
42            console.error('スピーカーデータの取得エラー:', error);
43            hideSpeakersSection();
44        }
45    }
46
47    /**
48     * スピーカーカードをレンダリング
49     * @param {Array} sessions - セッションの配列
50     */
51    function renderSpeakerCards(sessions) {
52        const container = document.querySelector(CONFIG.CONTAINER_SELECTOR);
53        if (!container) return;
54
55        // スピーカーがいるセッションのみ表示
56        const speakerCards = sessions
57            .filter(session => session.speakers && session.speakers.length > 0)
58            .flatMap(session =>
59                session.speakers.map(speaker =>
60                    createSpeakerCard(speaker, session.type)
61                )
62            )
63            .join('');
64
65        if (!speakerCards) {
66            hideSpeakersSection();
67            return;
68        }
69
70        container.innerHTML = speakerCards;
71    }
72
73    /**
74     * スピーカーカードを作成
75     * @param {Object} speaker - スピーカーのデータ
76     * @param {string} sessionType - セッションタイプ
77     * @returns {string} HTMLテキスト
78     */
79    function createSpeakerCard(speaker, sessionType) {
80        return `
81            <div class="speaker-card card p-8 md:p-10">
82                <div class="text-center mb-6">
83                    <span class="speaker-type text-xl md:text-2xl font-bold uppercase tracking-wider inline-block mb-4">
84                        ${escapeHtml(sessionType)}
85                    </span>
86                    <div class="mb-6">
87                        <img src="${escapeHtml(speaker.image)}" 
88                             alt="${escapeHtml(speaker.name)}" 
89                             class="speaker-image w-36 h-36 mx-auto rounded-full object-cover border-2 border-gray-200"
90                             loading="lazy"/>
91                    </div>
92                    <h3 class="text-2xl font-bold mb-3 text-gray-800">${escapeHtml(speaker.name)}</h3>
93                    <p class="text-gray-600 mb-6">${escapeHtml(speaker.role)}</p>
94                </div>
95                <div class="text-left px-2">
96                    <p class="text-gray-700 leading-loose text-sm">${speaker.description}</p>
97                </div>
98            </div>
99        `;
100    }
101
102    // 初期化
103    document.addEventListener('DOMContentLoaded', loadSpeakers);
104
105})(window, document);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.