Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4f615e5
refactor: migrate types to shared directory and update parsing functi…
mirumodapon Apr 5, 2026
b4593aa
refactor: extract fetchPretalxTable function for improved data fetchi…
mirumodapon Apr 5, 2026
8a8f83f
fix: update SubmissionSchema to change tags type from string to number
mirumodapon Apr 5, 2026
84d971a
fix: remove unreachable code
mirumodapon Apr 5, 2026
940069b
fix: handle null room in parseSlot function and update SlotSchema to …
mirumodapon Apr 5, 2026
7b5ea22
fix: correct import statement for zod in fetch.ts
mirumodapon Apr 5, 2026
d65c8f5
fix: add error handling for missing speakers, submission types, and r…
mirumodapon Apr 5, 2026
85f6c1e
fix: add error handling for missing room in parseSlot function
mirumodapon Apr 5, 2026
1d7e25a
fix: add error handling for undefined slots in session retrieval
mirumodapon Apr 5, 2026
9003f2e
refactor: update QUESTION_MAP type assertion and improve iteration ov…
mirumodapon Apr 5, 2026
ab3a87a
fix: update start and end fields in SessionSummarySchema to be nullable
mirumodapon Apr 7, 2026
7b2336b
fix: add null check for slot properties before returning session data
mirumodapon Apr 9, 2026
b1730c1
refactor: improve session filtering and grouping by date
mirumodapon Apr 9, 2026
258ecf5
feat(ui): add `CpSessionItem` and `CpBadge` Component
mirumodapon Mar 7, 2026
e2e80a1
feat(ui): add CpMenu component
mirumodapon Mar 15, 2026
4dcec72
feat(ui): add CpSessionInfoCard component
mirumodapon Mar 15, 2026
e98d494
feat(ui): add CpButton component
mirumodapon Mar 16, 2026
991bdb7
feat(ui): refactor toggle functionality in CpMenu and CpPopup components
mirumodapon Apr 4, 2026
d746dd7
feat(ui): implement logic of CpSessionTable component for session gri…
mirumodapon Apr 4, 2026
d2d59dd
feat(ui): remove text-justify class from title in CpSessionItem compo…
mirumodapon Apr 5, 2026
6a6ebd3
style: fix with eslint
mirumodapon Apr 5, 2026
d6cdaed
feat(ui): integrate drag scroll functionality in CpSessionTable compo…
mirumodapon Apr 5, 2026
fc3d529
feat: remove useless statement
mirumodapon Apr 9, 2026
227edc9
feat(ui): implement CpSessionDaySelector for day selection in session…
mirumodapon Apr 12, 2026
997bf19
fix(ui): enhance CpButton component to support disabled state and imp…
mirumodapon Apr 12, 2026
d5fb81b
fix(ui): session item should can be clicked
mirumodapon Apr 12, 2026
e4d5d90
fix: current session item url
mirumodapon Apr 12, 2026
13bb105
fix(ui): correct styling issues in CpSessionInfoCard and CpSessionIte…
mirumodapon Apr 12, 2026
0e7daa3
fix(ui): add hyperlink for co-write in CpSessionInfoCard component
mirumodapon Apr 12, 2026
30a3f25
fix(types): update PretalxData interface to allow numeric keys in map…
mirumodapon Apr 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions app/components/feature/CpSessionDaySelector.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<script setup lang="ts">
const props = defineProps<{
days: string[]
selectedDay?: string
}>()

const selectedDay = defineModel<string>()

function formatDayLabel(day: string) {
return new Intl.DateTimeFormat('en-US', {
day: 'numeric',
month: 'short',
timeZone: 'Asia/Taipei',
})
.format(new Date(`${day}T00:00:00+08:00`))
.replace(' ', '.')
}

const activeDay = computed(() => selectedDay.value ?? props.days[0] ?? '')
</script>

<template>
<div class="px-6 pb-4 pt-3 border-b border-primary-100 flex justify-center">
<div class="flex flex-wrap gap-3 items-center justify-center">
<button
v-for="day in days"
:key="day"
class="text-2xl text-white font-bold px-8 py-2 border-3 rounded-full min-w-34 cursor-pointer italic shadow-[0_4px_0_0_var(--un-shadow-color)] transition-colors"
:class="day === activeDay
? 'border-primary-700 bg-primary-400 shadow-primary-700'
: 'border-primary-700 bg-gray-200 shadow-primary-700'"
type="button"
@click="selectedDay = day"
>
{{ formatDayLabel(day) }}
</button>
</div>
</div>
</template>
162 changes: 162 additions & 0 deletions app/components/feature/CpSessionInfoCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'

const props = defineProps<{
title: string
time: string
speakers: {
id?: string
name: string
bio: string
avatar?: string
}[]
room: string
coWrite?: string
tags: string[]
description: string
}>()

const { t } = useI18n()

const speakerNames = computed(() =>
props.speakers.map((s) => s.name).join(', '),
)
</script>

<template>
<article class="p-6 bg-white flex flex-col gap-3">
<header>
<h1 class="text-2xl text-primary-400 leading-tight font-bold mb-4">
{{ title }}
</h1>
<table class="border-separate border-spacing-4">
<tbody>
<tr class="border-none">
<td class="text-gray-400">
<Icon name="tabler:clock" />
{{ t("time") }}
</td>
<td class="text-gray-700">
{{ time }}
</td>
</tr>
<tr class="border-none">
<td class="text-gray-400">
<Icon name="tabler:user" />
{{ t("speaker") }}
</td>
<td class="text-gray-700">
{{ speakerNames }}
</td>
</tr>
<tr class="border-none">
<td class="text-gray-400">
<Icon name="tabler:map-pin" />
{{ t("room") }}
</td>
<td class="text-gray-700">
{{ room }}
</td>
</tr>
<tr class="border-none">
<td class="text-gray-400">
<Icon name="tabler:file-text" />
{{ t("co-write") }}
</td>
<td class="text-gray-700">
<a
v-if="coWrite?.startsWith('http')"
class="underline cursor-pointer"
:href="coWrite"
>{{ coWrite }}</a>
<span
v-else
>{{ coWrite }}</span>
</td>
Comment thread
mirumodapon marked this conversation as resolved.
</tr>
</tbody>
</table>
<div
class="mt-5 pb-3 border-b border-gray-200 flex flex-wrap gap-2"
>
<span
v-for="tag in tags"
:key="tag"
class="text-xs text-primary-700 font-medium px-3 py-1 rounded-full bg-primary-100"
>
{{ tag }}
</span>
</div>
</header>
<section>
<h2 class="text-lg text-primary-400 font-bold my-3">
{{ t("abstract") }}
</h2>
<div
class="text-gray-700 leading-relaxed text-justify whitespace-pre-wrap"
>
{{ description }}
</div>
</section>
<section>
<h2 class="text-lg text-primary-400 font-bold my-2">
{{ t("speaker") }}
</h2>
<div class="flex flex-col gap-6">
<div
v-for="speaker in speakers"
:key="speaker.name"
class="flex flex-col gap-4"
>
<div class="flex gap-4 items-center">
<div
class="border-2 border-primary-100 rounded-full bg-gray-100 flex-shrink-0 h-16 w-16 overflow-hidden"
>
<img
v-if="speaker.avatar"
:alt="speaker.name"
class="h-full w-full object-cover"
:src="speaker.avatar"
>
<div
v-else
class="text-gray-400 flex h-full w-full items-center justify-center"
>
<Icon
class="h-8 w-8"
name="tabler:user"
/>
</div>
</div>
<div>
<h3 class="text-lg text-gray-700 font-bold">
{{ speaker.name }}
</h3>
</div>
</div>
<div
class="text-sm text-gray-700 leading-relaxed whitespace-pre-wrap"
>
{{ speaker.bio }}
</div>
</div>
</div>
</section>
</article>
</template>

<i18n lang="yaml">
en:
abstract: Abstract
co-write: Co-write
room: Room
speaker: Speaker
time: time
zh:
abstract: 摘要
room: 位置
speaker: 講者
time: 時間
co-write: 共筆
</i18n>
33 changes: 33 additions & 0 deletions app/components/feature/CpSessionItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<script setup lang="ts">
import CpBadge from '~/components/shared/CpBadge.vue'

defineProps<{
title: string
start: string
end: string
speaker: string
tags: string[]
}>()
</script>

<template>
<div class="text-primary-600 p-2 border border-primary-100 rounded bg-primary-50 relative">
<div class="flex flex-col">
<h1 class="text-base text-inherit font-normal my-1">
{{ title }}
</h1>
<time class="text-base opacity-50">{{ start }} ~ {{ end }}</time>
<p class="text-sm my-1">
{{ speaker }}
</p>
<p class="flex gap-1">
<CpBadge
v-for="tag in tags"
:key="tag"
>
{{ tag }}
</CpBadge>
</p>
</div>
</div>
</template>
Loading