workshops template

This commit is contained in:
Henri
2026-04-21 20:17:59 +03:00
parent 2ef643d15f
commit 83e090ef8f
4 changed files with 203 additions and 10 deletions

View File

@@ -0,0 +1,52 @@
# Workshops & courses conducted by Lapikud members
#
- title:
en: Go Programming Language Workshop
est: Go programmeerimiskeele töötuba
description:
en: Introduction to Go through practical exercises. Covered basic syntax, goroutines, channels and concurrency with real-world examples.
est: Sissejuhatus Go keelde läbi praktiliste ülesannete. Kaetud on põhisüntaks, goroutiinid, kanalid ja konkurentsus reaaleluliste näidete kaudu.
mentor:
en: Henri Karba
est: Henri Karba
duration:
en: 3 × 2h
est: 3 × 2h
date:
en: March 2025
est: Märts 2025
gallery: 3
- title:
en: Figma Design Workshop
est: Figma disainitöötuba
description:
en: Over two days we learned the Figma workflow, covering components, auto-layout, prototyping and presenting to clients.
est: Kahe päeva jooksul õppisime Figma töövoogu, komponendid, auto-layout, prototüüpimine ja klientidele esitamine.
mentor:
en: Maris Tamm
est: Maris Tamm
duration:
en: 2 days
est: 2 päeva
date:
en: November 2024
est: Nov 2024
gallery: 2
- 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

View File

@@ -0,0 +1,13 @@
{
"hero": {
"label": "Our work",
"title": "Workshops",
"titleHighlight": "& courses.",
"subtitle": "A selection of workshops conducted by our members over the years."
},
"details": {
"mentor": "Mentor",
"duration": "Duration",
"date": "Date"
}
}

View File

@@ -0,0 +1,13 @@
{
"hero": {
"label": "Meie tehtud",
"title": "Koolitused",
"titleHighlight": "& töötoad.",
"subtitle": "Valik koolitusi, mida meie liikmed on aastate jooksul läbi viinud."
},
"details": {
"mentor": "Juhendaja",
"duration": "Kestus",
"date": "Toimumisaeg"
}
}

View File

@@ -1,21 +1,136 @@
<script>
import {
Section,
Grid,
Center,
} from "$components";
import { onDestroy } from "svelte";
import { createPageTextStore } from "$lib";
import { Section, Stack, Container } from "$components";
import { onMount, onDestroy } from "svelte";
import yaml from "js-yaml";
import { currentLang, getLangText, createPageTextStore } from "$lib";
let workshops = [];
const text = createPageTextStore("Workshops");
onMount(async () => {
const response = await fetch("/_data/workshops.yml");
const yamlText = await response.text();
const parsed = yaml.load(yamlText) || [];
workshops = parsed.filter((w) => w?.title);
});
onDestroy(() => {
text.destroy();
});
function getField(workshop, field) {
return getLangText(workshop, field, $currentLang);
}
function getGalleryClass(count) {
const classes = {
1: "grid-cols-1 grid-rows-1",
2: "grid-cols-2",
3: "grid-cols-2 grid-rows-2",
4: "grid-cols-2 grid-rows-2",
};
return classes[count] || classes[1];
}
function getImageHeightClass(count, index) {
if (count === 1) return "h-56";
if (count === 2) return "h-40";
if (count === 3) {
return index === 0 ? "h-72 row-span-2" : "h-32";
}
if (count === 4) return "h-32";
return "h-40";
}
</script>
<div class="safe-area-navbar">
<!-- Hero Section -->
<Section bg="bg-black" class="text-white">
<div class="max-w-2xl">
<p class="font-dm-mono text-xs uppercase tracking-widest text-orange-500 mb-4">
{$text["hero"]?.label}
</p>
<h1 class="font-syne text-5xl md:text-6xl lg:text-7xl font-bold leading-tight mb-4">
{$text["hero"]?.title}
<em class="block text-orange-500 not-italic"
>{@html $text["hero"]?.titleHighlight}</em
>
</h1>
<p class="text-sm text-gray-400 max-w-sm leading-relaxed font-space-grotesk font-light">
{$text["hero"]?.subtitle}
</p>
</div>
</Section>
<!-- Workshops Content -->
<Section>
<p>In development...</p>
<Stack gap="lg">
{#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" : ""}`}>
<!-- Gallery -->
<div
class={`grid gap-1.5 ${index % 2 === 1 ? "md:order-2" : ""}`}
>
<div class={`grid ${getGalleryClass(workshop.gallery)} gap-1.5`}>
{#each Array(workshop.gallery) as _, i}
<div
class={`bg-gray-100 overflow-hidden flex items-center justify-center ${getImageHeightClass(workshop.gallery, i)}`}
>
<svg
width="48"
height="48"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
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>
{/each}
</div>
</div>
<!-- Content -->
<div class={`pt-2 ${index % 2 === 1 ? "md:order-1" : ""}`}>
<h2 class="font-syne text-2xl md:text-3xl font-bold text-gray-900 mb-4">
{getField(workshop, "title")}
</h2>
<p class="text-sm leading-7 text-gray-600 font-space-grotesk font-light mb-7">
{getField(workshop, "description")}
</p>
<div class="flex flex-wrap gap-7">
<div class="flex flex-col gap-1">
<span class="font-dm-mono text-xs uppercase tracking-wide text-gray-500">
{$text["details"]?.mentor}
</span>
<span class="text-sm text-gray-700 font-space-grotesk">
{getField(workshop, "mentor")}
</span>
</div>
<div class="flex flex-col gap-1">
<span class="font-dm-mono text-xs uppercase tracking-wide text-gray-500">
{$text["details"]?.duration}
</span>
<span class="text-sm text-gray-700 font-space-grotesk">
{getField(workshop, "duration")}
</span>
</div>
<div class="flex flex-col gap-1">
<span class="font-dm-mono text-xs uppercase tracking-wide text-gray-500">
{$text["details"]?.date}
</span>
<span class="text-sm text-gray-700 font-space-grotesk">
{getField(workshop, "date")}
</span>
</div>
</div>
</div>
</div>
{/each}
</Stack>
</Section>
</div>