Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add event details page #51

Merged
merged 12 commits into from
Jan 16, 2025
110 changes: 110 additions & 0 deletions website-frontend/src/lib/components/events/DetailsBanner.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<script lang="ts">
import { deslugify } from '$lib/utils';
import { PUBLIC_APIURL } from '$env/static/public';
import { Clock, MapPin } from 'lucide-svelte';

export let title: string;
export let background_image: string;
export let location: string;
export let start_date: string;
export let end_date: string;

$: deslugify_title = deslugify(title);

// function to extract date

function getDateParts(dateString: string): { day: number; month: string } {
const date = new Date(dateString);
const options: Intl.DateTimeFormatOptions = { month: 'long' };
return {
day: date.getDate(),
month: new Intl.DateTimeFormat('en-US', options).format(date)
};
}

const { day: startDay, month: startMonth } = getDateParts(start_date);

let endDay: number | undefined;
let endMonth: string | undefined;

if (end_date) {
({ day: endDay, month: endMonth } = getDateParts(end_date));
}

// function to extract time

function getTimeParts(dateString: string): { hours: number; minutes: string } {
const date = new Date(dateString);
return {
hours: date.getHours(), // Hours in 24-hour format
minutes: date.getMinutes().toString().padStart(2, '0') // Padded minutes
};
}

const { hours: startHours, minutes: startMinutes } = getTimeParts(start_date);
let endHours: number | undefined;
let endMinutes: string | undefined;

if (end_date) {
({ hours: endHours, minutes: endMinutes } = getTimeParts(end_date));
}
</script>

<div class="relative z-0">
<div
class="h-[40vh] bg-cover bg-center md:h-[70vh]"
style="background-image: linear-gradient(to top, #004420, transparent), url('{PUBLIC_APIURL}/assets/{background_image}')"
></div>

<div
class="-mt-[0.4px] w-full bg-[#004420] pb-10 pt-10 md:absolute md:bottom-10 md:bg-transparent md:pb-0"
>
<div
class="-mt-16 flex w-full
flex-col items-center px-5 text-center
md:flex-row md:justify-between md:px-32 md:text-start"
>
<div class="text-white md:max-w-[60vw]">
<h1 class="text-4xl font-bold md:mb-4 md:text-4xl">{deslugify_title}</h1>
<div class="my-6 space-y-1 text-gray-100 md:my-0 md:flex">
{#if location}
<div class="flex items-center justify-center space-x-2 md:mr-10 md:justify-start">
<MapPin class="h-4 w-4" />
<h4>{@html location}</h4>
</div>
{/if}

<div class="flex items-center justify-center space-x-2 md:justify-start">
<Clock class="h-4 w-4" />
{#if end_date}
<h4>{startHours}:{startMinutes} - {endHours}:{endMinutes}</h4>
{:else}
<h4>Whole day event</h4>
{/if}
</div>
</div>
</div>

<!-- Date Display -->

<div class="flex flex-row items-center md:pl-12">
<div
class="flex h-28 w-28 flex-col items-center justify-center rounded-lg bg-white text-gray-900 shadow-xl md:h-36 md:w-36"
>
<h1 class="text-4xl font-bold md:mb-2 md:text-5xl">{startDay}</h1>
<h3 class="font-medium text-[#004420]">{startMonth}</h3>
</div>

{#if end_date}
<div class="mx-3 h-1 w-3 bg-gray-300"></div>
<div
class="flex h-28 w-28 flex-col items-center justify-center rounded-lg bg-white text-gray-900 shadow-xl md:h-36 md:w-36"
>
<h1 class="text-4xl font-bold md:mb-2 md:text-5xl">{endDay}</h1>
<h3 class="font-medium text-[#004420]">{endMonth}</h3>
</div>
{/if}
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
export let event: Event;
</script>

<div class="card h-fit w-72 max-w-72 snap-center p-4 md:w-96 md:max-w-96">
<div class="mb-4 md:flex md:justify-between">
<h3>{event.event_headline}</h3>
<h3>{new Date(event.date_created).toLocaleDateString()}</h3>
<a href="/events/{event.slug}">
<div class="card h-fit w-72 max-w-72 snap-center p-4 md:w-96 md:max-w-96">
<div class="mb-4 md:flex md:justify-between">
<h3>{event.event_headline}</h3>
<h3>{new Date(event.date_created).toLocaleDateString()}</h3>
</div>
<div class="max-h-6 overflow-hidden *:truncate">

Check warning on line 12 in website-frontend/src/lib/components/events/FeaturedEventCard.svelte

View workflow job for this annotation

GitHub Actions / test

`{@html}` can lead to XSS attack
{@html event.event_content}
</div>
<p>View details &#8594;</p>
</div>
<div class="max-h-6 overflow-hidden *:truncate">
{@html event.event_content}
</div>
<p>View details &#8594;</p>
</div>
</a>
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<script lang="ts">
import { onMount } from 'svelte';
import { enhanceWysiwygContent } from '.';
export let content: string = '';
import { onMount } from 'svelte';
import { enhanceWysiwygContent } from '.';
export let content: string = '';

let enhancedContent = content;

onMount(() => {
enhancedContent = content ? enhanceWysiwygContent(content) : '';
});
let enhancedContent = content;

$: if (typeof window !== 'undefined') {
enhancedContent = content ? enhanceWysiwygContent(content) : '';
}
onMount(() => {
enhancedContent = content ? enhanceWysiwygContent(content) : '';
});

$: if (typeof window !== 'undefined') {
enhancedContent = content ? enhanceWysiwygContent(content) : '';
}
</script>

{#if content}
{@html enhancedContent}
{@html enhancedContent}

Check warning on line 18 in website-frontend/src/lib/components/flexible_content/FlexibleContent.svelte

View workflow job for this annotation

GitHub Actions / test

`{@html}` can lead to XSS attack
{/if}
5 changes: 4 additions & 1 deletion website-frontend/src/lib/components/nav/NavBar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@
<NavItem href="/students" to="Students" dropdown={true}>
<NavItem href="/students" to="Overview" />
<NavItem href="/students/batch-representatives" to="Batch Representatives" />
<NavItem href="/students/student-ethics-health-and-wellbeing" to="Student Ethics, Health, and Wellbeing" />
<NavItem
href="/students/student-ethics-health-and-wellbeing"
to="Student Ethics, Health, and Wellbeing"
/>
<NavItem href="/students/student-opportunities" to="Student Opportunities" />
<NavItem href="/students/organizations" to="Organizations" />
</NavItem>
Expand Down
18 changes: 16 additions & 2 deletions website-frontend/src/lib/models/event.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
import { cleanHtml } from '$lib/models-helpers';
import { array, isoTimestamp, nullable, object, pipe, string, type InferOutput } from 'valibot';
import {
array,
isoTimestamp,
nullable,
object,
optional,
pipe,
string,
type InferOutput
} from 'valibot';

export const Event = object({
slug: string(),
date_created: pipe(string(), isoTimestamp()),
event_headline: string(),
hero_image: optional(nullable(string())),
event_content: pipe(string(), cleanHtml),
tags: nullable(array(string()))
tags: nullable(array(string())),
start_date: pipe(string(), isoTimestamp()),
end_date: nullable(pipe(string(), isoTimestamp())),
location: nullable(string())
});

export const Events = array(Event);
Expand Down
29 changes: 29 additions & 0 deletions website-frontend/src/routes/events/[slug]/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/** @type {import('./$types').PageServerLoad} */
import { readItems } from '@directus/sdk';
import getDirectusInstance from '$lib/directus';
import { error } from '@sveltejs/kit';

export async function load({ params, fetch }) {
const directus = await getDirectusInstance(fetch);
const eventSlug = params.slug;

const events = await directus.request(
readItems('events', {
filter: {
slug: {
_eq: eventSlug
}
}
})
);

if (!events.length) {
throw error(404, 'Event not found');
}

const event = events[0];

return {
event
};
}
41 changes: 41 additions & 0 deletions website-frontend/src/routes/events/[slug]/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<script lang="ts">
/** @type {import('./$types').PageData} */
import DetailsBanner from '$lib/components/events/DetailsBanner.svelte';

export let data;
$: ({ event } = data);
</script>

<body class="bg-white">
{#if event}
<div class="relative">
<DetailsBanner
title={event.event_headline}
background_image={event.hero_image ?? ''}
location={event.location ?? ''}
start_date={event.start_date}
end_date={event.end_date ?? ''}
/>
</div>

<div class="px-4 py-14 text-gray-800 md:px-64 md:py-16">
{event.event_content}
</div>

<h1 class="mb-8 px-4 text-2xl font-bold text-gray-900 md:px-32">Related Events</h1>

<!-- <div
class="mx-auto my-3 grid
max-w-[94vw] grid-cols-2 gap-2 pb-20
md:my-8 md:max-w-[80vw] md:grid-cols-4 md:gap-4"
>
{#each related_events as related_event}
<a href="/events/{related_event.event_headline}">
<FeaturedEventCard {related_event} />
</a>
{/each}
</div> -->
{:else}
<p>Event not found</p>
{/if}
</body>
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import getDirectusInstance from '$lib/directus';
export async function load({ fetch }) {
const directus = await getDirectusInstance(fetch);
const page = await directus.request(readItem('students_pages', 4));

return {
page
};
Expand Down
Loading