Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 13 additions & 2 deletions components/frontend/src/lib/components/hackathon/CtaSection.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,34 @@
buttonLabel,
buttonHref,
note,
external = false,
}: {
heading: string;
subtitle: string;
buttonLabel: string;
buttonHref: string;
note?: string;
// Opt in for an off-site buttonHref: marks the link outgoing the way the
// rest of the app does. Left off, the button navigates in-app as before.
external?: boolean;
} = $props();
</script>

<section class="flex flex-col items-center gap-4 px-4 py-12 sm:px-10 md:px-20">
<h2 class="text-display">{heading}</h2>
<p class="text-sm text-ink-2">{subtitle}</p>
<!-- eslint-disable-next-line svelte/no-navigation-without-resolve -->
<a href={buttonHref} class="btn btn-solid no-underline">
<!-- eslint-disable svelte/no-navigation-without-resolve -->
<a
href={buttonHref}
target={external ? '_blank' : undefined}
rel={external ? 'noopener noreferrer' : undefined}
aria-label={external ? `${buttonLabel} (opens in a new tab)` : undefined}
class="btn btn-solid no-underline"
>
<UserPlus class="h-4 w-4" />
{buttonLabel}
</a>
<!-- eslint-enable svelte/no-navigation-without-resolve -->
{#if note}
<span class="text-xs text-ink-2">{note}</span>
{/if}
Expand Down
165 changes: 50 additions & 115 deletions components/frontend/src/routes/(public)/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@
import {
ArrowRight,
Code,
Trophy,
Archive,
Users,
Lightbulb,
Upload,
Vote,
ChevronLeft,
ChevronRight,
} from 'lucide-svelte';
import HackathonRow from '$lib/components/hackathon/HackathonRow.svelte';
import CtaSection from '$lib/components/hackathon/CtaSection.svelte';
Expand Down Expand Up @@ -41,20 +37,25 @@
return GRADIENTS[i % GRADIENTS.length]!;
}

let carouselIndex = $state(0);
const carouselSlides = [
{ src: '/images/hackathon-ord-2024/ambiance/ambiance_1.webp', caption: 'ORD Hackathon 2024 — Opening ceremony' },
{ src: '/images/hackathon-ord-2024/teams/teams_1.webp', caption: 'ORD Hackathon 2024 — Team collaboration' },
{ src: '/images/hackathon-ord-2024/ambiance/ambiance_3.webp', caption: 'ORD Hackathon 2024 — Working sessions' },
{ src: '/images/hackathon-ord-2024/winners/winners_1.webp', caption: 'ORD Hackathon 2024 — Award ceremony' },
// Same shape and light/dark handling as OrganizersSection: a dark asset when
// one exists, otherwise invert the light-on-transparent source. Only these
// three have logo assets in static/ today.
const INSTITUTIONS = [
{
name: 'SDSC',
url: 'https://datascience.ch',
logoUrl: '/logos/sdsc.svg',
logoDarkUrl: '/logos/sdsc_white.svg',
},
{ name: 'ETH Zurich', url: 'https://ethz.ch', logoUrl: '/images/logos/eth-zurich.svg' },
{ name: 'EPFL', url: 'https://epfl.ch', logoUrl: '/images/logos/epfl.svg' },
];

function nextSlide() {
carouselIndex = (carouselIndex + 1) % carouselSlides.length;
}
function prevSlide() {
carouselIndex = (carouselIndex - 1 + carouselSlides.length) % carouselSlides.length;
}
// Matches AppFooter's LOGO_LINK.
const LOGO_LINK = 'no-underline opacity-80 transition-opacity hover:opacity-100';

// The same destination AppFooter's "Contact" link points at.
const SDSC_CONTACT_URL = 'https://datascience.ch/contact';
</script>

<!-- Hero (full-bleed width) -->
Expand Down Expand Up @@ -102,24 +103,13 @@
<div class="mx-auto w-full max-w-7xl">
<!-- Trending -->
<section id="trending" class="px-4 py-12 sm:px-10 md:px-20">
<div class="flex items-center justify-between">
<h2 class="text-title">Trending this month</h2>
<a href={resolve('/')} class="text-sm text-accent-ink no-underline">Browse all →</a>
</div>
<h2 class="text-title">Trending this month</h2>

<div class="mt-6 flex gap-1 border-b border-line">
<button class="chip chip-active">
<Code class="h-3.5 w-3.5" />
<span>Hackathons</span>
</button>
<button class="chip">
<Trophy class="h-3.5 w-3.5" />
<span>Challenges</span>
</button>
<button class="chip">
<Archive class="h-3.5 w-3.5" />
<span>Past Events</span>
</button>
</div>

<div class="mt-0 divide-y divide-line">
Expand All @@ -141,86 +131,6 @@
</div>
</section>

<!-- Winners -->
<section class="px-4 py-12 sm:px-10 md:px-20">
<div class="flex items-center justify-between">
<h2 class="text-title">Award-winning projects</h2>
<a href={resolve('/')} class="text-sm text-accent-ink no-underline">See all →</a>
</div>

<div class="mt-6 grid grid-cols-3 gap-4">
{#each [
{ hackathon: 'ORD Hackathon 2025', project: 'AutoORD: Automated\nResearch Data Pipelines', team: 'by Team DataFlow', summary: 'Automated pipeline for converting raw research data into FAIR-compliant open datasets.' },
{ hackathon: 'GenAI Hackathon 2025', project: 'GenomeLens', team: 'by BioViz Crew', summary: 'Interactive visualization of genomic variants powered by generative models.' },
{ hackathon: 'Climate Data 2025', project: 'ClimateQA', team: 'by Green Bytes', summary: 'RAG-based Q&A trained on Swiss climate data, making decades of measurements queryable.' },
] as card, i (i)}
<div class="card overflow-hidden">
<div
class="flex h-10 items-center justify-between border-b border-line px-4"
>
<div class="flex items-center gap-1.5 text-warning-ink">
<Trophy class="h-3.5 w-3.5" />
<span class="text-xs font-bold">1st Place</span>
</div>
<span class="text-xs text-ink-3">{card.hackathon}</span>
</div>
<div class="flex flex-col gap-2 p-4">
<p class="text-sm font-semibold leading-tight whitespace-pre-line">{card.project}</p>
<span class="text-xs text-accent-ink">{card.team}</span>
<p class="text-xs leading-snug text-ink-3">{card.summary}</p>
</div>
</div>
{/each}
</div>
</section>

<!-- Event Showcase Carousel -->
<section class="px-4 py-12 sm:px-10 md:px-20">
<div class="flex items-center justify-between">
<h2 class="text-title">Event showcase</h2>
<div class="flex items-center gap-2">
<button onclick={prevSlide} class="btn btn-icon btn-sm btn-outline">
<ChevronLeft class="h-4 w-4" />
</button>
<button onclick={nextSlide} class="btn btn-icon btn-sm btn-outline">
<ChevronRight class="h-4 w-4" />
</button>
</div>
</div>

<div class="relative mt-6 overflow-hidden">
<div
class="flex gap-4 transition-transform duration-500 ease-in-out"
style="transform: translateX(-{carouselIndex * 25}%)"
>
{#each carouselSlides as slide, i (i)}
<div class="w-[calc(25%-12px)] shrink-0">
<div class="relative aspect-video overflow-hidden rounded-card border border-line">
<img
src={slide.src}
alt={slide.caption}
class="h-full w-full object-cover"
/>
</div>
<p class="mt-2 text-xs text-ink-3">{slide.caption}</p>
</div>
{/each}
</div>
</div>

<div class="mt-4 flex justify-center gap-1.5">
{#each carouselSlides as slide, i (i)}
<button
onclick={() => carouselIndex = i}
class="h-1.5 w-1.5 rounded-full transition-colors {i === carouselIndex
? 'bg-accent'
: 'bg-overlay'}"
aria-label="Go to slide: {slide.caption}"
></button>
{/each}
</div>
</section>

<!-- Features -->
<section class="bg-raised px-4 py-12 sm:px-10 md:px-20">
<div class="flex flex-col items-center gap-2 text-center">
Expand Down Expand Up @@ -252,12 +162,36 @@
<!-- Orgs -->
<section class="flex flex-col items-center gap-8 px-4 py-12 sm:px-10 md:px-20">
<h2 class="text-title">Trusted by Swiss research institutions</h2>
<div class="flex items-center gap-12">
{#each ['SDSC', 'ETH Zurich', 'EPFL', 'Univ. of Bern', 'Univ. of Zurich', 'SOAD'] as name, i (i)}
<div class="flex flex-col items-center gap-2">
<div class="flex h-14 w-14 items-center justify-center rounded-card border border-line"></div>
<span class="text-xs font-medium text-ink-3">{name}</span>
</div>
<div class="flex flex-wrap items-center justify-center gap-x-12 gap-y-6">
{#each INSTITUTIONS as org, i (i)}
<!-- eslint-disable svelte/no-navigation-without-resolve -- off-site institution URL -->
<a
href={org.url}
target="_blank"
rel="noopener noreferrer"
aria-label="{org.name} (opens in a new tab)"
class="flex h-7 w-28 items-center justify-center {LOGO_LINK}"
>
{#if org.logoDarkUrl}
<img
src={org.logoUrl}
alt={org.name}
class="block max-h-full max-w-full object-contain dark:hidden"
/>
<img
src={org.logoDarkUrl}
alt={org.name}
class="hidden max-h-full max-w-full object-contain dark:block"
/>
{:else}
<img
src={org.logoUrl}
alt={org.name}
class="max-h-full max-w-full object-contain invert dark:invert-0"
/>
{/if}
</a>
<!-- eslint-enable svelte/no-navigation-without-resolve -->
{/each}
</div>
</section>
Expand All @@ -266,7 +200,8 @@
heading="Want to host your own hackathon?"
subtitle="SDSC provides the platform, tools, and expertise. Bring your challenge — we'll help you run it."
buttonLabel="Contact Us"
buttonHref={resolve('/')}
buttonHref={SDSC_CONTACT_URL}
external
/>

</div>
Loading