Skip to content

Commit 2d7732d

Browse files
committed
feat: add agenda desktop component
1 parent e5471f8 commit 2d7732d

File tree

15 files changed

+2026
-14
lines changed

15 files changed

+2026
-14
lines changed

src/components/Navbar.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const { t } = useI18n(Astro.url.pathname)
88
const pathname = pathnameWithoutBaseAndLocale(Astro.url.pathname)
99
1010
const navs = [
11-
{ href: getRelativeLocaleUrl(locale, 'agenda'), name: t('nav.agenda') },
11+
{ href: getRelativeLocaleUrl(locale, 'agenda/day1'), name: t('nav.agenda') },
1212
{ href: getRelativeLocaleUrl(locale, 'visit'), name: t('nav.visit') },
1313
{ href: getRelativeLocaleUrl(locale, 'venue'), name: t('nav.venue') },
1414
{ href: getRelativeLocaleUrl(locale, 'speaker'), name: t('nav.speaker') },
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
---
2-
import Layout from '~/layouts/Layout.astro'
32
import { useI18n } from '~/i18n/utils'
3+
import Layout from '~/layouts/Layout.astro'
4+
import Desktop from './Desktop.astro'
45
56
const { t } = useI18n(Astro.url.pathname)
7+
const { title, date } = Astro.props
68
---
79

810
<Layout pageName={t('nav.agenda')}>
9-
<h1>{t('nav.agenda')}</h1>
11+
<Desktop title={title} date={date} />
1012
</Layout>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
---
2+
import { getRelativeLocaleUrl } from 'astro:i18n'
3+
import { useI18n, getLocaleFromPath } from '~/i18n/utils'
4+
import schedule from '~/data/schedule.json'
5+
import { extractHHmm } from '~/utils/build/agenda/extractHHmm'
6+
import Time from '~/components/agenda/Time.astro'
7+
import Session from '~/components/agenda/Session.astro'
8+
9+
const { t } = useI18n(Astro.url.pathname)
10+
const locale = getLocaleFromPath(Astro.url.pathname)
11+
const { title, date } = Astro.props
12+
13+
const times = new Set()
14+
const sessions = []
15+
schedule.sessions.forEach(session => {
16+
if (session.start.startsWith(date)) {
17+
times.add(extractHHmm(session.start))
18+
times.add(extractHHmm(session.end))
19+
sessions.push(session)
20+
}
21+
})
22+
---
23+
24+
<div class="agenda">
25+
<div class="sticky top-0 z-30 flex flex-col justify-center bg-white" style="height: var(--agenda-header-height);">
26+
<div class="mb-5 flex justify-center gap-4 font-bold">
27+
<a class={title === 'Day 1' ? 'text-info-dark' : 'text-info'} href={getRelativeLocaleUrl(locale, 'agenda/day1')}>Day 1</a>
28+
<a class={title === 'Day 2' ? 'text-info-dark' : 'text-info'} href={getRelativeLocaleUrl(locale, 'agenda/day2')}>Day 2</a>
29+
</div>
30+
31+
<div class="agenda-grid grid text-center">
32+
<div></div>
33+
<div class="bg-primary mx-3 py-2 text-white">{t('room.R0')}</div>
34+
<div class="bg-primary mx-3 py-2 text-white">{t('room.R1')}</div>
35+
<div class="bg-primary mx-3 py-2 text-white">{t('room.R2')}</div>
36+
<div class="bg-primary mx-3 py-2 text-white">{t('room.RH')}</div>
37+
</div>
38+
</div>
39+
40+
<h2 class="mt-8 mb-12">{title}</h2>
41+
42+
<div class="agenda-grid relative grid">
43+
{Array.from(times).map(time => <Time at={time} />)}
44+
{sessions.map(session => <Session session={session} />)}
45+
</div>
46+
</div>
47+
48+
<style>
49+
.agenda-grid {
50+
grid-template-columns: [time] 4rem [R0] 1fr [R1] 1fr [R2] 1fr [RH] 1fr [end] auto [R4] 0;
51+
}
52+
</style>
53+
54+
<style is:global>
55+
.agenda {
56+
--agenda-header-height: 130px;
57+
}
58+
</style>

src/components/agenda/Mobile.astro

Whitespace-only changes.
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
---
2+
import { getLocaleFromPath, useI18n } from '~/i18n/utils'
3+
import schedule from '~/data/schedule.json'
4+
import { extractHHmm } from '~/utils/build/agenda/extractHHmm'
5+
6+
const { t } = useI18n(Astro.url.pathname)
7+
const locale = getLocaleFromPath(Astro.url.pathname)
8+
const isZhTW = locale === 'zh-tw'
9+
10+
const { session } = Astro.props
11+
12+
const columnOrder = {
13+
R0: 0,
14+
R1: 1,
15+
R2: 2,
16+
RH: 3,
17+
}
18+
const tags = session.tags.map(tagId => tagIdToDetail(tagId))
19+
const speakers = session.speakers.map(speakerId => speakerIdToDetail(speakerId))
20+
const type = typeToDetail(session.type)
21+
const startRow = parseInt(extractHHmm(session.start).replace(':', '')) || 0
22+
const endRow = parseInt(extractHHmm(session.end).replace(':', '')) || 0
23+
const [startCol, endCol] = getColumnStartEnd(session.broadcast || session.room)
24+
const isRest = session.type === 'R'
25+
26+
const style = `grid-area: ${startRow} / ${startCol} / ${endRow} / ${endCol};`
27+
28+
function getColumnStartEnd(columns) {
29+
columns = columns.split(',')
30+
if (columns.length === 1) return [columns[0], columns[0]]
31+
columns.sort((a, b) => columnOrder[a] - columnOrder[b])
32+
return [columns[0], columns.at(-1)]
33+
}
34+
35+
function speakerIdToDetail(speakerId) {
36+
return schedule.speakers.find(speaker => speaker.id === speakerId)
37+
}
38+
39+
function tagIdToDetail(tagId) {
40+
return schedule.tags.find(tag => tag.id === tagId)
41+
}
42+
43+
function typeToDetail(type) {
44+
return schedule.session_types.find(t => t.id === type)
45+
}
46+
---
47+
48+
<div class="flex flex-col p-3" style={style}>
49+
<div class=`relative z-10 shrink-0 grow cursor-pointer p-4 ${isRest ? 'bg-neutral-300' : 'bg-neutral-100'}`>
50+
<div class="sticky" style="top: calc(var(--agenda-header-height) + 1rem);">
51+
<div class="font-bold text-neutral-800">{isZhTW ? session.zh.title : session.en.title}</div>
52+
<div class="flex flex-col items-stretch">
53+
{speakers.map(speaker => <div class="text-sm text-neutral-700">{isZhTW ? speaker.zh.name : speaker.en.name}</div>)}
54+
</div>
55+
56+
{
57+
!isRest && (
58+
<div class="my-2 flex flex-wrap gap-1 text-xs text-white">
59+
{session.type && <span class="bg-primary rounded-full px-2">{isZhTW ? type.zh.name : type.en.name}</span>}
60+
{session.language && <span class="rounded-full bg-neutral-500 px-2">{t(`language.${session.language}`)}</span>}
61+
{tags.map(tag => (
62+
<span class="rounded-full bg-neutral-400 px-2">{isZhTW ? tag.zh.name : tag.en.name}</span>
63+
))}
64+
</div>
65+
)
66+
}
67+
</div>
68+
</div>
69+
</div>
70+
71+
<style is:global>
72+
#navbar {
73+
position: static;
74+
}
75+
</style>

src/components/agenda/Time.astro

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
const { at } = Astro.props
3+
4+
const row = parseInt(at.replace(':', '')) || 0
5+
6+
const style = at ? `grid-area: ${row} / time` : ''
7+
---
8+
9+
<div class="agenda-timeline z-0 block" style={style}>
10+
<div class="translate-y-[-50%] font-medium">{at}</div>
11+
</div>
12+
13+
<style>
14+
.agenda-timeline:before {
15+
content: '';
16+
position: absolute;
17+
left: 4rem;
18+
right: 0;
19+
height: 1px;
20+
background-color: #e5e5e5;
21+
}
22+
</style>

0 commit comments

Comments
 (0)