updated and fixed most pages + navbar update on home page

This commit is contained in:
Henri
2026-04-22 20:59:29 +03:00
parent 83e090ef8f
commit 08d6e08c4d
12 changed files with 168 additions and 213 deletions

View File

@@ -1,52 +1,41 @@
# Workshops & courses conducted by Lapikud members # Workshops & courses conducted by Lapikud members
# #
- title: - title:
en: Go Programming Language Workshop en: C workshop
est: Go programmeerimiskeele töötuba est: C koolitus
description: description:
en: Introduction to Go through practical exercises. Covered basic syntax, goroutines, channels and concurrency with real-world examples. en: Three-part introductory C workshop series for beginners and early-stage programmers. Covered core programming foundations and practical C basics in Estonian at TalTech IT College.
est: Sissejuhatus Go keelde läbi praktiliste ülesannete. Kaetud on põhisüntaks, goroutiinid, kanalid ja konkurentsus reaaleluliste näidete kaudu. est: Kolmeosaline C programmeerimiskeele koolitus algajatele ja varasema kogemusega huvilistele. Käsitleti programmeerimise alusteadmisi ja C keele põhiteemasid praktiliste näidete kaudu TalTech IT Kolledžis.
mentor: mentor:
en: Henri Karba en: Lapikud mentors
est: Henri Karba est: MTÜ Lapikud mentorid
duration: duration:
en: 3 × 2h en: 3 × 1h 30min
est: 3 × 2h est: 3 × 1h 30min
date: date:
en: March 2025 en: March 2026
est: Märts 2025 est: Märts 2026
gallery: 3 gallery:
- temp1.jpg
- temp2.jpg
- title: - title:
en: Figma Design Workshop en: C workshop
est: Figma disainitöötuba est: C koolitus
description: description:
en: Over two days we learned the Figma workflow, covering components, auto-layout, prototyping and presenting to clients. en: Three-part introductory C workshop series for beginners and early-stage programmers. Covered core programming foundations and practical C basics in Estonian at TalTech IT College.
est: Kahe päeva jooksul õppisime Figma töövoogu, komponendid, auto-layout, prototüüpimine ja klientidele esitamine. est: Kolmeosaline C programmeerimiskeele koolitus algajatele ja varasema kogemusega huvilistele. Käsitleti programmeerimise alusteadmisi ja C keele põhiteemasid praktiliste näidete kaudu TalTech IT Kolledžis.
mentor: mentor:
en: Maris Tamm en: Lapikud mentors
est: Maris Tamm est: MTÜ Lapikud mentorid
duration: duration:
en: 2 days en: 3 × 1h 30min
est: 2 päeva est: 3 × 1h 30min
date: date:
en: November 2024 en: March 2026
est: Nov 2024 est: Märts 2026
gallery: 2 gallery:
- temp1.jpg
- temp2.jpg
- temp3.jpg
- title:
en: Web Security Basics
est: Veebiturvalisuse alused
description:
en: Practical seminar on OWASP Top 10 attacks and defense methods. Lab work involved fixing real vulnerabilities in a controlled environment.
est: Praktiline seminar OWASP Top 10 rünnakute ja kaitsmismeetodite kohta. Laboris lahendati päris haavatavusi kontrollitud keskkonnas.
mentor:
en: Juku Rebane
est: Juku Rebane
duration:
en: 4 hours
est: 4 tundi
date:
en: September 2024
est: Sept 2024
gallery: 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

View File

@@ -1,6 +1,6 @@
/* Global stylesheet */ /* Global stylesheet */
@import url("https://fonts.googleapis.com/css2?family=Unbounded:wght@300;400;500;600;700&display=swap"); @import url("https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700;900&display=swap");
@import "tailwindcss"; @import "tailwindcss";
/* Overwriting tailwindcss specific variables */ /* Overwriting tailwindcss specific variables */
@@ -46,12 +46,7 @@
--spacing-6: 48px; --spacing-6: 48px;
/* type scale (fluid base + modular sizes) */ /* type scale (fluid base + modular sizes) */
--fs-base: clamp(0.95rem, 0.9vw + 0.9rem, 1rem); --fs-base: clamp(1.1rem, 1vw + 1rem, 1.2rem);
--fs-xs: 0.85rem;
--fs-sm: 0.92rem;
--fs-md: 1rem;
--fs-lg: 1.125rem;
--fs-xl: 1.5rem;
--line-height: 1.6; --line-height: 1.6;
} }
@@ -62,7 +57,7 @@
box-sizing: border-box; box-sizing: border-box;
} }
html { html {
font-family: "Unbounded", ui-sans-serif, system-ui, -apple-system, "Segoe UI", font-family: "Lato", ui-sans-serif, system-ui, -apple-system, "Segoe UI",
Roboto, "Helvetica Neue", Arial; Roboto, "Helvetica Neue", Arial;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;

View File

@@ -9,6 +9,7 @@
} = $props(); } = $props();
let isOpen = $state(false); let isOpen = $state(false);
let panelElement = $state(null);
const toggle = () => (isOpen = !isOpen); const toggle = () => (isOpen = !isOpen);
const close = () => (isOpen = false); const close = () => (isOpen = false);
@@ -21,6 +22,26 @@
return; return;
close(); close();
} }
$effect(() => {
if (!isOpen) return;
const handleDocumentClick = (event) => {
const target = event.target;
if (!(target instanceof HTMLElement) || !panelElement) return;
if (
panelElement.contains(target) &&
target.closest("button, a, [role='menuitem']")
) {
close();
}
};
document.addEventListener("click", handleDocumentClick);
return () => document.removeEventListener("click", handleDocumentClick);
});
</script> </script>
<div class="relative inline-block" onfocusout={handleFocusOut}> <div class="relative inline-block" onfocusout={handleFocusOut}>
@@ -38,6 +59,7 @@
<div <div
class="{panelClass} absolute mt-2 rounded-md shadow-lg overflow-visible flex flex-col" class="{panelClass} absolute mt-2 rounded-md shadow-lg overflow-visible flex flex-col"
style:visibility={isOpen ? "visible" : "hidden"} style:visibility={isOpen ? "visible" : "hidden"}
bind:this={panelElement}
> >
<div> <div>
{@render children?.()} {@render children?.()}

View File

@@ -44,63 +44,19 @@
return paths.includes(currentPath); return paths.includes(currentPath);
} }
function isHomePage() {
return currentPath === "/";
}
function headerShellClass() {
return isHomePage()
? "bg-transparent"
: "border-b-2 border-orange-500 bg-gray-900 backdrop-blur-md";
}
function headerRowClass() {
return isHomePage()
? "flex min-h-16 items-center w-full relative gap-4"
: "flex min-h-16 items-center gap-4";
}
function headerWrapClass() {
return isHomePage()
? "ml-auto flex w-full self-stretch items-center justify-end md:w-auto md:border-b-3 md:border-white backdrop-blur-lg bg-black/35 pr-(--page-padding-inline)"
: "flex items-center justify-end ml-auto w-full md:w-auto";
}
function desktopNavClass() {
return isHomePage()
? "z-10 hidden md:flex gap-1 justify-end text-lg"
: "z-10 hidden md:flex items-center gap-1 justify-end text-lg";
}
function navButtonClass(active = false) { function navButtonClass(active = false) {
if (isHomePage()) {
return active
? "border-transparent text-orange-500 bg-transparent"
: "border-transparent bg-transparent text-white/75 hover:text-orange-500";
}
return active return active
? "border-transparent text-orange-500 hover:bg-white/5" ? "border-transparent text-orange-500 hover:bg-white/5"
: "border-transparent text-white/75 hover:bg-white/5"; : "border-transparent text-white/75 hover:bg-white/5";
} }
function dropdownButtonClass(active = false) { function dropdownButtonClass(active = false) {
if (isHomePage()) {
return active
? "border-transparent text-orange-500 bg-transparent"
: "border-transparent bg-transparent text-white/75 hover:text-orange-500";
}
return active return active
? "border-transparent text-orange-500 hover:bg-white/5" ? "border-transparent text-orange-500 hover:bg-white/5"
: "border-transparent text-white/75 hover:bg-white/5"; : "border-transparent text-white/75 hover:bg-white/5";
} }
function languageButtonClass() { function languageButtonClass() {
if (isHomePage()) {
return "ml-3 border-transparent bg-transparent px-3 py-1 text-sm text-white/75 hover:text-orange-500";
}
return "ml-3 border-transparent bg-transparent px-3 py-1 text-sm text-white/75 hover:bg-white/5"; return "ml-3 border-transparent bg-transparent px-3 py-1 text-sm text-white/75 hover:bg-white/5";
} }
@@ -217,21 +173,19 @@
</style> </style>
<header class="fixed inset-x-0 top-0 z-50 text-white"> <header class="fixed inset-x-0 top-0 z-50 text-white">
<div class={headerShellClass()}> <div class="border-b-2 border-orange-500 bg-gray-900 backdrop-blur-md">
<Container maxWidth={true} center={!isHomePage()} class="py-0"> <Container class="py-0">
{#if $text && Object.keys($text).length > 0} {#if $text && Object.keys($text).length > 0}
<div class={headerRowClass()}> <div class="flex min-h-16 items-center gap-4">
{#if !isHomePage()}
<Button <Button
onClick={() => handleNavigation("/")} onClick={() => handleNavigation("/")}
class="nav-logo-button border-transparent bg-transparent px-0 py-3" class="nav-logo-button border-transparent bg-transparent px-0 py-3"
> >
<img src="/assets/logo.svg" alt="Lapikud logo" class="h-12 md:h-14 w-auto" /> <img src="/assets/logo.svg" alt="Lapikud logo" class="h-12 md:h-14 w-auto" />
</Button> </Button>
{/if}
<div class={headerWrapClass()}> <div class="ml-auto flex w-full items-center justify-end md:w-auto">
<nav class={desktopNavClass()}> <nav class="z-10 hidden items-center gap-1 justify-end text-lg md:flex">
<Dropdown <Dropdown
name={$text.about} name={$text.about}
buttonClass={`${dropdownButtonClass(isInGroup(aboutRoutes))} ${isInGroup(aboutRoutes) ? "nav-active-parent" : ""}`} buttonClass={`${dropdownButtonClass(isInGroup(aboutRoutes))} ${isInGroup(aboutRoutes) ? "nav-active-parent" : ""}`}
@@ -309,7 +263,7 @@
</Button> </Button>
<Button <Button
class={languageButtonClass()} class="ml-3 border-transparent bg-transparent px-3 py-1 text-sm text-white/75 hover:bg-white/5"
onClick={() => switchLanguageRoute($currentLang === "est" ? "en" : "est")} onClick={() => switchLanguageRoute($currentLang === "est" ? "en" : "est")}
> >
{$currentLang === "est" ? "EN" : "EST"} {$currentLang === "est" ? "EN" : "EST"}

View File

@@ -11,7 +11,23 @@
let { routes } = $props(); let { routes } = $props();
let currentPath = $state(window.location.pathname); let currentPath = $state(window.location.pathname);
let CurrentComponent = $derived(routes[currentPath] || routes["/"]); let CurrentComponent = $state(null);
async function resolveCurrentComponent(path) {
const routeEntry = routes[path] || routes["/"];
if (typeof routeEntry === "function") {
try {
const module = await routeEntry();
CurrentComponent = module?.default || null;
} catch {
CurrentComponent = null;
}
return;
}
CurrentComponent = routeEntry || null;
}
function navigate(path) { function navigate(path) {
window.history.pushState({}, "", path); window.history.pushState({}, "", path);
@@ -46,6 +62,10 @@
return () => window.removeEventListener("click", handleClick); return () => window.removeEventListener("click", handleClick);
}); });
$effect(() => {
resolveCurrentComponent(currentPath);
});
</script> </script>
{#if CurrentComponent} {#if CurrentComponent}

View File

@@ -54,12 +54,7 @@
</div> </div>
<div class="pointer-events-none absolute inset-y-0 left-1/2 w-screen -translate-x-1/2 bg-linear-to-r from-black/65 via-black/35 to-transparent" aria-hidden="true"></div> <div class="pointer-events-none absolute inset-y-0 left-1/2 w-screen -translate-x-1/2 bg-linear-to-r from-black/65 via-black/35 to-transparent" aria-hidden="true"></div>
<div class="relative z-20 flex min-h-screen w-full items-stretch py-8 md:py-12"> <div class="relative z-20 flex min-h-screen w-full items-stretch py-8 md:py-12">
<div class="flex w-full max-w-115 flex-col justify-between"> <div class="flex w-full max-w-115 flex-col justify-end">
<Image
src="/assets/logo.svg"
alt={$text["hero"]?.logoAlt || "MTÜ Lapikud"}
class="w-full max-w-65 md:max-w-80 h-auto pt-5 md:pt-10"
/>
<div class="flex flex-col items-start gap-5"> <div class="flex flex-col items-start gap-5">
<p class="w-full max-w-110 text-left text-lg leading-[165%] text-white drop-shadow-[0_2px_8px_rgba(0,0,0,0.6)] md:max-w-125 md:text-xl"> <p class="w-full max-w-110 text-left text-lg leading-[165%] text-white drop-shadow-[0_2px_8px_rgba(0,0,0,0.6)] md:max-w-125 md:text-xl">
{$text["hero"]?.description || "MTÜ Lapikud on Tallinna Tehnikaülikooli Tarkvaraarendusklubi, mis ühendab endisi ja praegusi IT huvilisi tudengeid."} {$text["hero"]?.description || "MTÜ Lapikud on Tallinna Tehnikaülikooli Tarkvaraarendusklubi, mis ühendab endisi ja praegusi IT huvilisi tudengeid."}

View File

@@ -105,7 +105,7 @@
</Section> </Section>
<Section padding="large"> <Section padding="large">
<div class="mb-12"> <div class="mb-22">
<p class="mb-3 text-[0.72rem] font-bold uppercase tracking-[0.12em] text-orange-500">{$text["portfolio"]?.label || "Tehtud tööd"}</p> <p class="mb-3 text-[0.72rem] font-bold uppercase tracking-[0.12em] text-orange-500">{$text["portfolio"]?.label || "Tehtud tööd"}</p>
<h1 class="m-0 max-w-[20ch] text-[clamp(1.9rem,4vw,3.15rem)] leading-[1.08] tracking-[-0.03em]">{$text["portfolio"]?.title || "Projektid, mis räägivad enda eest."}</h1> <h1 class="m-0 max-w-[20ch] text-[clamp(1.9rem,4vw,3.15rem)] leading-[1.08] tracking-[-0.03em]">{$text["portfolio"]?.title || "Projektid, mis räägivad enda eest."}</h1>
<p class="mt-4 max-w-[62ch] leading-[1.65] text-gray-900"> <p class="mt-4 max-w-[62ch] leading-[1.65] text-gray-900">
@@ -114,13 +114,13 @@
</div> </div>
{#if featuredProject} {#if featuredProject}
<Card class="mb-5! grid! overflow-hidden! rounded-none! border-0! bg-white! p-0! ring-1 ring-gray-200 md:grid-cols-[1.25fr_1fr]!" variant="default"> <Card class="mb-5! grid! gap-4 rounded-none! border-0! bg-white! p-0! md:grid-cols-[1.25fr_1fr]! md:gap-6" variant="default">
<div class="min-h-[220px] overflow-hidden bg-gray-100/70 p-2 md:min-h-[280px]"> <div class="flex min-h-[220px] items-center justify-center md:min-h-[280px]">
{#if featuredProject.photo} {#if featuredProject.photo}
<img <img
src={projectImage(featuredProject)} src={projectImage(featuredProject)}
alt={projectTitle(featuredProject)} alt={projectTitle(featuredProject)}
class="block h-full w-full border border-gray-200 bg-white object-contain object-center shadow-[0_1px_2px_rgba(13,13,13,0.05)]" class="block h-auto max-h-full w-auto max-w-full object-contain object-center shadow-[0_1px_2px_rgba(13,13,13,0.05)]"
on:error={(event) => handleImageError(event, featuredProject.photo)} on:error={(event) => handleImageError(event, featuredProject.photo)}
/> />
{:else} {:else}
@@ -128,17 +128,19 @@
{/if} {/if}
</div> </div>
<div class="flex flex-col justify-center gap-2 p-[clamp(1.5rem,3vw,2.5rem)]"> <div class="flex h-full flex-1 flex-col justify-between gap-[clamp(0.75rem,2vw,1.5rem)] p-[clamp(1.5rem,3vw,2.5rem)]">
<div class="flex flex-col gap-[clamp(0.45rem,1vw,0.8rem)]">
<h2 class="m-0 text-[clamp(1.45rem,2.7vw,2rem)] leading-[1.2] tracking-[-0.02em]">{projectTitle(featuredProject)}</h2> <h2 class="m-0 text-[clamp(1.45rem,2.7vw,2rem)] leading-[1.2] tracking-[-0.02em]">{projectTitle(featuredProject)}</h2>
{#if projectDescription(featuredProject)} {#if projectDescription(featuredProject)}
<p class="m-0 text-[0.9rem] leading-[1.6] text-gray-900">{projectDescription(featuredProject)}</p> <p class="m-0 text-[0.9rem] leading-[1.6] text-gray-900">{projectDescription(featuredProject)}</p>
{/if} {/if}
</div>
{#if featuredProject.url} {#if featuredProject.url}
<a <a
href={featuredProject.url} href={featuredProject.url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
class="mt-0.5 inline-flex w-fit items-center gap-1.5 font-semibold text-orange-500 hover:underline" class="mt-auto inline-flex w-fit items-center gap-1.5 pt-1 font-semibold text-orange-500 hover:underline"
> >
{$text["portfolio"]?.projectLink || "Vaata projekti"} {$text["portfolio"]?.projectLink || "Vaata projekti"}
<ExternalLink size={16} /> <ExternalLink size={16} />
@@ -149,13 +151,13 @@
{/if} {/if}
<div class="ourwork-grid"> <div class="ourwork-grid">
{#each regularProjects as project} {#each regularProjects as project}
<Card variant="default" class="ourwork-grid-card rounded-none! border-0! bg-white! p-0!"> <Card variant="default" class="ourwork-grid-card gap-4 rounded-none! border-0! bg-white! p-0!">
<div class="aspect-16/10 overflow-hidden bg-gray-100/70 p-2"> <div class="flex aspect-16/10 items-center justify-center">
{#if project.photo} {#if project.photo}
<img <img
src={projectImage(project)} src={projectImage(project)}
alt={projectTitle(project)} alt={projectTitle(project)}
class="block h-full w-full border border-gray-200 bg-white object-contain object-center shadow-[0_1px_2px_rgba(13,13,13,0.05)]" class="block h-auto max-h-full w-auto max-w-full object-contain object-center shadow-[0_1px_2px_rgba(13,13,13,0.05)]"
on:error={(event) => handleImageError(event, project.photo)} on:error={(event) => handleImageError(event, project.photo)}
/> />
{:else} {:else}
@@ -163,13 +165,15 @@
{/if} {/if}
</div> </div>
<div class="ourwork-card-content flex h-full flex-1 flex-col gap-2 p-5"> <div class="ourwork-card-content flex h-full flex-1 flex-col justify-between gap-[clamp(0.55rem,1vw,0.95rem)] px-5 pb-5 pt-1.5">
<div class="flex flex-col gap-[clamp(0.4rem,0.9vw,0.75rem)]">
<h3 class="ourwork-card-title m-0 text-base leading-[1.2] tracking-[-0.02em]">{projectTitle(project)}</h3> <h3 class="ourwork-card-title m-0 text-base leading-[1.2] tracking-[-0.02em]">{projectTitle(project)}</h3>
{#if projectDescription(project)} {#if projectDescription(project)}
<p class="ourwork-card-description m-0 text-[0.9rem] leading-[1.6] text-gray-900">{projectDescription(project)}</p> <p class="ourwork-card-description m-0 text-[0.9rem] leading-[1.6] text-gray-900">{projectDescription(project)}</p>
{:else} {:else}
<p class="ourwork-card-description m-0 text-[0.9rem] leading-[1.6] text-gray-900 italic">{$text["portfolio"]?.noDescription || "Kirjeldus lisamisel."}</p> <p class="ourwork-card-description m-0 text-[0.9rem] leading-[1.6] text-gray-900 italic">{$text["portfolio"]?.noDescription || "Kirjeldus lisamisel."}</p>
{/if} {/if}
</div>
{#if project.url} {#if project.url}
<a <a
@@ -191,10 +195,10 @@
<style> <style>
.ourwork-grid { .ourwork-grid {
display: flex; display: grid;
flex-wrap: wrap; gap: clamp(0.75rem, 1.5vw, 1.1rem);
gap: 1px; align-items: stretch;
justify-content: center; grid-template-columns: 1fr;
} }
.ourwork-grid :global(.ourwork-grid-card) { .ourwork-grid :global(.ourwork-grid-card) {
@@ -205,37 +209,15 @@
width: 100%; width: 100%;
} }
.ourwork-card-content {
min-height: 10.25rem;
}
.ourwork-card-title {
min-height: calc(1.2em * 2);
display: -webkit-box;
line-clamp: 2;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.ourwork-card-description {
min-height: calc(1.6em * 3);
display: -webkit-box;
line-clamp: 3;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
}
@media (min-width: 768px) { @media (min-width: 768px) {
.ourwork-grid :global(.ourwork-grid-card) { .ourwork-grid {
width: calc((100% - 1px) / 2); grid-template-columns: repeat(2, minmax(0, 1fr));
} }
} }
@media (min-width: 1200px) { @media (min-width: 1200px) {
.ourwork-grid :global(.ourwork-grid-card) { .ourwork-grid {
width: calc((100% - 2px) / 3); grid-template-columns: repeat(3, minmax(0, 1fr));
} }
} }
</style> </style>

View File

@@ -51,7 +51,7 @@
</script> </script>
<div class="safe-area-navbar"> <div class="safe-area-navbar">
<Section class="overflow-hidden bg-[#0f0f0f]" padding="none" fullWidth={true} contentClass="relative !px-0"> <Section class="overflow-hidden bg-gray-900" padding="none" fullWidth={true} contentClass="relative !px-0">
<div class="relative overflow-hidden py-[clamp(3rem,8vw,6rem)]"> <div class="relative overflow-hidden py-[clamp(3rem,8vw,6rem)]">
<div class="relative z-10 mx-auto w-full max-w-(--page-max-width) px-(--page-padding-inline)"> <div class="relative z-10 mx-auto w-full max-w-(--page-max-width) px-(--page-padding-inline)">
<div class="relative z-10 w-full max-w-3xl"> <div class="relative z-10 w-full max-w-3xl">

View File

@@ -1,5 +1,5 @@
<script> <script>
import { Section, Stack, Container } from "$components"; import { Section, Stack, Image } from "$components";
import { onMount, onDestroy } from "svelte"; import { onMount, onDestroy } from "svelte";
import yaml from "js-yaml"; import yaml from "js-yaml";
import { currentLang, getLangText, createPageTextStore } from "$lib"; import { currentLang, getLangText, createPageTextStore } from "$lib";
@@ -22,6 +22,10 @@
return getLangText(workshop, field, $currentLang); return getLangText(workshop, field, $currentLang);
} }
function getGallery(workshop) {
return Array.isArray(workshop?.gallery) ? workshop.gallery : [];
}
function getGalleryClass(count) { function getGalleryClass(count) {
const classes = { const classes = {
1: "grid-cols-1 grid-rows-1", 1: "grid-cols-1 grid-rows-1",
@@ -29,7 +33,7 @@
3: "grid-cols-2 grid-rows-2", 3: "grid-cols-2 grid-rows-2",
4: "grid-cols-2 grid-rows-2", 4: "grid-cols-2 grid-rows-2",
}; };
return classes[count] || classes[1]; return classes[count] || "grid-cols-2";
} }
function getImageHeightClass(count, index) { function getImageHeightClass(count, index) {
@@ -39,13 +43,13 @@
return index === 0 ? "h-72 row-span-2" : "h-32"; return index === 0 ? "h-72 row-span-2" : "h-32";
} }
if (count === 4) return "h-32"; if (count === 4) return "h-32";
return "h-40"; return "h-32";
} }
</script> </script>
<div class="safe-area-navbar"> <div class="safe-area-navbar">
<!-- Hero Section --> <!-- Hero Section -->
<Section bg="bg-black" class="text-white"> <Section bg="bg-gray-900" class="text-white">
<div class="max-w-2xl"> <div class="max-w-2xl">
<p class="font-dm-mono text-xs uppercase tracking-widest text-orange-500 mb-4"> <p class="font-dm-mono text-xs uppercase tracking-widest text-orange-500 mb-4">
{$text["hero"]?.label} {$text["hero"]?.label}
@@ -66,29 +70,23 @@
<Section> <Section>
<Stack gap="lg"> <Stack gap="lg">
{#each workshops as workshop, index (index)} {#each workshops as workshop, index (index)}
<div class={`grid grid-cols-1 md:grid-cols-2 gap-14 md:gap-16 py-16 border-b border-gray-100 ${index === workshops.length - 1 ? "border-b-0" : ""}`}> <div class={`grid grid-cols-1 md:grid-cols-2 gap-14 md:gap-16 py-16 border-b border-orange-500 ${index === workshops.length - 1 ? "border-b-0" : ""}`}>
<!-- Gallery --> <!-- Gallery -->
<div <div
class={`grid gap-1.5 ${index % 2 === 1 ? "md:order-2" : ""}`} class={`grid gap-1.5 ${index % 2 === 1 ? "md:order-2" : ""}`}
> >
<div class={`grid ${getGalleryClass(workshop.gallery)} gap-1.5`}> <div class={`grid ${getGalleryClass(getGallery(workshop).length)} gap-1.5`}>
{#each Array(workshop.gallery) as _, i} {#each getGallery(workshop) as filename, i (filename)}
<div <div
class={`bg-gray-100 overflow-hidden flex items-center justify-center ${getImageHeightClass(workshop.gallery, i)}`} class={`overflow-hidden ${getImageHeightClass(getGallery(workshop).length, i)}`}
> >
<svg <Image
width="48" src={`/assets/workshops/${filename}`}
height="48" alt={`${getField(workshop, "title")} ${i + 1}`}
viewBox="0 0 24 24" objectFit="cover"
fill="none" class="h-full w-full"
stroke="currentColor" pictureClass="h-full w-full"
stroke-width="1" />
class="text-gray-300"
>
<rect x="3" y="3" width="18" height="18" rx="1" />
<circle cx="8.5" cy="8.5" r="1.5" />
<polyline points="21 15 16 10 5 21" />
</svg>
</div> </div>
{/each} {/each}
</div> </div>

View File

@@ -1,17 +1,17 @@
// ADD PAGES HERE TO REGISTER ROUTES // ADD PAGES HERE TO REGISTER ROUTES
// examples: '/page', '/page/:id' // examples: '/page', '/page/:id'
import Home from './Home.svelte' const loadHome = () => import('./Home.svelte');
import Student from './Student.svelte' const loadStudent = () => import('./Student.svelte');
import Mentors from './Mentors.svelte' const loadMentors = () => import('./Mentors.svelte');
import Helpdesk from './Helpdesk.svelte' const loadHelpdesk = () => import('./Helpdesk.svelte');
import OurWork from './OurWork.svelte' const loadOurWork = () => import('./OurWork.svelte');
import AboutUs from './AboutUs.svelte' const loadAboutUs = () => import('./AboutUs.svelte');
import Contact from './Contact.svelte' const loadContact = () => import('./Contact.svelte');
import Managment from './Managment.svelte' const loadManagment = () => import('./Managment.svelte');
import Striim from './Striim.svelte' const loadStriim = () => import('./Striim.svelte');
import Calendar from './Calendar.svelte' const loadCalendar = () => import('./Calendar.svelte');
import Workshops from './Workshops.svelte'; const loadWorkshops = () => import('./Workshops.svelte');
// Route mapping for language switching // Route mapping for language switching
export const routeMap = { export const routeMap = {
@@ -91,23 +91,23 @@ export function getTranslatedRoute(currentPath, targetLang) {
} }
export const routes = { export const routes = {
'/': Home, '/': loadHome,
'/tudengile': Student, '/tudengile': loadStudent,
'/student': Student, '/student': loadStudent,
'/mentorid': Mentors, '/mentorid': loadMentors,
'/mentors': Mentors, '/mentors': loadMentors,
'/helpdesk': Helpdesk, '/helpdesk': loadHelpdesk,
'/ettevottele': OurWork, '/ettevottele': loadOurWork,
'/ourwork': OurWork, '/ourwork': loadOurWork,
'/lapikutest': AboutUs, '/lapikutest': loadAboutUs,
'/aboutus': AboutUs, '/aboutus': loadAboutUs,
'/kontakt': Contact, '/kontakt': loadContact,
'/contact': Contact, '/contact': loadContact,
'/juhatus': Managment, '/juhatus': loadManagment,
'/management': Managment, '/management': loadManagment,
'/koolitused': Workshops, '/koolitused': loadWorkshops,
'/workshops': Workshops, '/workshops': loadWorkshops,
'/striim': Striim, '/striim': loadStriim,
'/kalender': Calendar, '/kalender': loadCalendar,
'/calendar': Calendar, '/calendar': loadCalendar,
} }