Skip to content

Commit

Permalink
Merge pull request #258 from christopher-adolphe/feature/speaker-prof…
Browse files Browse the repository at this point in the history
…ile-bio

feat: speakers profile bio
  • Loading branch information
MrSunshyne authored Dec 6, 2024
2 parents 260719d + 38c0dad commit 589ff10
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 35 deletions.
17 changes: 17 additions & 0 deletions packages/frontendmu-data/data/speakers-profile.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[
{
"bio": "Front-end Developer based in Mauritius.",
"job_title": "Senior Front-end Engineer @ Livestorm",
"location": "Mauritius",
"website": "https://sandeep.ramgolam.com",
"github": "MrSunshyne",
"twitter": "@__sun__"
},
{
"bio": "Front-End Engineer | Streamer (Twitch)",
"job_title": "Senior Front-end Engineer @ Livestorm",
"location": "Mauritius",
"github": "cedpoilly",
"twitter": ""
}
]
103 changes: 80 additions & 23 deletions packages/frontendmu-nuxt/components/speaker/Single.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,42 @@ import LogoSpiral from '@/components/misc/LogoSpiral.vue'
import { getGithubUrl } from '@/utils/helpers'
import ContentBlock from '@/components/misc/ContentBlock.vue'
const props = defineProps({
speaker: {
type: Object,
required: true,
},
})
const speaker_photo = getGithubUrl(props.speaker.person?.github_account)
import type { SpeakerProfileWithSessions } from '~/utils/types'
interface SpeakerSingleProps {
speaker: SpeakerProfileWithSessions
}
const props = defineProps<SpeakerSingleProps>()
const person = computed(() => props.speaker.person)
const sessions = computed(() => props.speaker.sessions)
const profile = computed(() => props.speaker.profile)
const hasProfileBio = computed(() => profile.value.bio !== '')
const hasProfileLocation = computed(() => profile.value.location !== '')
const hasProfileWebsite = computed(() => profile.value.website !== '')
const hasProfileGithub = computed(() => profile.value.github !== '')
const hasProfileTwitter = computed(() => profile.value.twitter !== '')
const speaker_photo = getGithubUrl(person.value.github_account)
</script>

<template>
<div>
<!-- <pre>
<code>{{ JSON.stringify(props.speaker, null, 2) }}</code>
</pre> -->
<div :data-title="props.speaker.person?.name">
<div :data-title="person.name">
<ContentBlock>
<div class="flex md:flex-row justify-between flex-col-reverse">
<div>
<div class="flex flex-col-reverse md:flex-row justify-start md:gap-6">
<div class="flex-grow">
<!-- Content area -->
<div>
<div>
<div class="hidden md:block">
<BaseHeading :level="1" weight="bold">
{{ props.speaker.person?.name }}
{{ person.name }}
</BaseHeading>
</div>

<EventsList :sessions="props.speaker.sessions" />
<EventsList :sessions="sessions" />
</div>

<!-- Stats section -->
Expand Down Expand Up @@ -61,13 +69,62 @@ const speaker_photo = getGithubUrl(props.speaker.person?.github_account)
</div>
</div>

<div class="flex-grow relative">
<div class="w-full flex justify-end">
<img class="h-auto w-[80%] mx-auto md:mx-0 my-10 object-cover rounded-full lg:h-96 lg:w-96"
:src="speaker_photo" :style="vTransitionName(props.speaker.person?.name, 'photo')"
:alt="props.speaker.person?.name" :title="props.speaker.person?.name" width="300" height="300"
<div class="flex-grow relative w-full lg:max-w-[32.375rem]">
<div class="flex flex-col justify-start items-end w-full ">
<img
class="h-auto w-[80%] mx-auto md:mx-0 my-10 object-cover rounded-full lg:h-96 lg:w-96"
:src="speaker_photo" :style="vTransitionName(person.name, 'photo')"
:alt="person.name" :title="person.name" width="300" height="300"
>

<div
v-if="profile"
class="grid gap-4 w-full p-4 border-2 border-verse-400 rounded-xl z-20 text-verse-600 dark:text-verse-300"
>
<div class="w-full h-full absolute top-0">
<BaseHeading
class="md:hidden"
:level="1"
weight="bold"
>
{{ person.name }}
</BaseHeading>

<p v-if="hasProfileBio">
{{ profile.bio }}
</p>

<nav class="grid gap-2 *:flex *:justify-start *:items-center *:gap-2">
<span v-if="hasProfileLocation">
<Icon name="lucide:map-pin" mode="svg" class="size-6" />{{ profile.location }}
</span>

<NuxtLink
v-if="hasProfileWebsite"
:to="profile.website"
target="_blank"
>
<Icon name="lucide:link" mode="svg" class="size-6" />{{ profile.website }}
</NuxtLink>

<NuxtLink
v-if="hasProfileGithub"
:to="`https://github.com/${profile.github}`"
target="_blank"
>
<Icon name="lucide:github" mode="svg" class="size-6" />{{ profile.github }}
</NuxtLink>

<NuxtLink
v-if="hasProfileTwitter"
:to="`https://twitter.com/${profile.twitter}`"
target="_blank"
>
<Icon name="ri:twitter-x-fill" mode="svg" class="size-6" />{{ profile.twitter }}
</NuxtLink>
</nav>
</div>

<div class="w-full h-full absolute top-0 z-10">
<LogoSpiral class="w-full opacity-5 saturate-0" />
</div>
</div>
Expand Down
34 changes: 34 additions & 0 deletions packages/frontendmu-nuxt/error.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script setup lang="ts">
import type { NuxtError } from '#app'
const props = defineProps({
error: Object as () => NuxtError,
})
const handleError = () => clearError({ redirect: '/' })
</script>

<template>
<NuxtLayout name="simple">
<ContentBlock>
<div class="flex flex-col justify-start items-center gap-10 mx-auto max-w-[60ch] text-center">
<BaseHeading :level="1" weight="bold">
Oops!
</BaseHeading>

<BaseHeading :level="3" weight="bold">
{{ error.statusCode }} - The page you are looking for doesn't exist
</BaseHeading>

<p>{{ error.message }}</p>

<button
class="mx-auto bg-verse-500 hover:bg-verse-600 transition-colors duration-200 text-md block rounded-full px-4 py-4 text-center font-medium text-white md:px-6 md:text-lg cursor-pointer"
@click="handleError"
>
Back to Home
</button>
</div>
</ContentBlock>
</NuxtLayout>
</template>
51 changes: 40 additions & 11 deletions packages/frontendmu-nuxt/pages/speaker/[id].vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,41 @@
<script setup lang="ts">
import eventsResponse from '../../../frontendmu-data/data/meetups-raw.json'
import speakersResponse from '../../../frontendmu-data/data/speakers-raw.json'
import speakersProfileResponse from '../../../frontendmu-data/data/speakers-profile.json'
import type { SpeakerProfileWithSessions } from '~/utils/types'
definePageMeta({
middleware: [
function (to, _) {
const { id } = to.params
const speaker = speakersResponse.find((ev: { id: string }) => String(ev.id) === String(id))
if (!speaker) {
return abortNavigation(
createError({
status: 404,
message: `We could not find the speaker with ID: ${id}`,
}),
)
}
},
],
})
const route = useRoute()
const id = computed(() => route.params.id as string)
function getSpeaker(id: string | number) {
function getSpeaker(id: string): SpeakerProfileWithSessions {
const speaker = speakersResponse.find((ev: { id: string }) => String(ev.id) === String(id))
if (speaker === null) {
console.error('cannot find speaker id: ', id)
if (!speaker) {
return {
person: undefined,
sessions: undefined,
profile: undefined,
Date: '',
Venue: '',
}
}
// Get sessions of this speaker from the events
Expand All @@ -19,18 +45,21 @@ function getSpeaker(id: string | number) {
return id === session_speaker_id
})
const profile = speakersProfileResponse.find(profile => profile.github === speaker.github_account)
return {
person: speaker,
sessions: speakerSession,
profile,
Date: '',
Venue: '',
}
}
const speaker = ref(getSpeaker(id.value))
const speakerExists = computed(() => speaker.value !== null)
const speaker = ref(getSpeaker(route.params.id as string))
useHead({
title: speaker.value.person ? speaker.value.person.name : '',
title: speaker.value?.person ? speaker.value.person.name : '',
meta: [
{
hid: 'description',
Expand All @@ -41,15 +70,15 @@ useHead({
})
defineOgImageComponent('Speaker', {
title: speaker.value.person ? speaker.value.person.name : '',
username: speaker.value.person?.github_account,
title: speaker.value?.person ? speaker.value.person.name : '',
username: speaker.value?.person.github_account,
})
</script>

<template>
<div>
<template v-if="speaker">
<SpeakerSingle :route-id="id" :speaker="speaker" />
<SpeakerSingle :speaker="speaker" />
</template>
</div>
</template>
25 changes: 24 additions & 1 deletion packages/frontendmu-nuxt/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,14 @@ export interface SessionDetail {
}

export interface Speaker {
name: string
id: string
status: string
sort: string | null
name: string
github_account: string
featured: boolean
date_created: string
date_updated: string
}

export interface BrandingAsset {
Expand All @@ -269,3 +274,21 @@ export interface BrandingAsset {
filename: string
versions: string[]
}

export interface SpeakerProfile {
id: string
bio: string
job_title: string
location: string
website: string
github: string
twitter: string
}

export interface SpeakerProfileWithSessions {
person: Speaker
sessions: Sponsor[]
profile: SpeakerProfile
Date: string
Venue: string
}

0 comments on commit 589ff10

Please sign in to comment.