mirror of
https://github.com/Lapikud/lapikud.github.io.git
synced 2026-08-08 16:39:14 +00:00
temporary push, with testing changes for nav and Juhatus
This commit is contained in:
@@ -22,6 +22,45 @@
|
|||||||
let isClosing = $state(false);
|
let isClosing = $state(false);
|
||||||
let currentPath = $state(getPath());
|
let currentPath = $state(getPath());
|
||||||
|
|
||||||
|
const aboutRoutes = [
|
||||||
|
"/lapikutest",
|
||||||
|
"/aboutus",
|
||||||
|
"/tudengile",
|
||||||
|
"/student",
|
||||||
|
"/mentorid",
|
||||||
|
"/mentors",
|
||||||
|
"/juhatus",
|
||||||
|
"/management",
|
||||||
|
];
|
||||||
|
|
||||||
|
const eventsRoutes = ["/kalender", "/striim", "/koolitused"];
|
||||||
|
|
||||||
|
function isCurrent(path) {
|
||||||
|
return currentPath === path;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInGroup(paths) {
|
||||||
|
return paths.includes(currentPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
function navButtonClass(active = false) {
|
||||||
|
return active
|
||||||
|
? "border-transparent text-orange-500 bg-white/5"
|
||||||
|
: "border-transparent text-white/75 hover:text-white hover:bg-white/5";
|
||||||
|
}
|
||||||
|
|
||||||
|
function dropdownButtonClass(active = false) {
|
||||||
|
return active
|
||||||
|
? "border-transparent text-orange-500 bg-white/5"
|
||||||
|
: "border-transparent text-white/75 hover:text-white hover:bg-white/5";
|
||||||
|
}
|
||||||
|
|
||||||
|
function dropdownItemClass(active = false) {
|
||||||
|
return active
|
||||||
|
? "bg-orange-500/10 text-orange-500"
|
||||||
|
: "bg-transparent text-black hover:text-orange-500";
|
||||||
|
}
|
||||||
|
|
||||||
// Update currentPath when navigation occurs
|
// Update currentPath when navigation occurs
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
const handleNavigation = () => {
|
const handleNavigation = () => {
|
||||||
@@ -125,84 +164,111 @@
|
|||||||
</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">
|
||||||
<Container maxWidth={true} center={false} class="py-0">
|
<div class="border-b-2 border-orange-500 bg-gray-900/95 backdrop-blur-md">
|
||||||
{#if $text && Object.keys($text).length > 0}
|
<Container maxWidth={true} center={true} class="py-0">
|
||||||
<div class="flex items-center w-full relative min-h-10">
|
{#if $text && Object.keys($text).length > 0}
|
||||||
<!-- Logo -->
|
<div class="flex min-h-16 items-center gap-4">
|
||||||
{#if currentPath !== "/"}
|
<Button
|
||||||
<div class="absolute left-1/2 -translate-x-1/2 top-1/2 -translate-y-1/2 md:relative md:left-auto md:translate-x-0 md:top-auto md:translate-y-0">
|
onClick={() => handleNavigation("/")}
|
||||||
<Button onClick={() => handleNavigation("/")} class="border-transparent">
|
class="nav-logo-button border-transparent bg-transparent px-0 py-0 text-white hover:text-white"
|
||||||
<img src="assets/LapLogo_black_white.png" alt="Lapikud Logo" class="h-14" />
|
>
|
||||||
</Button>
|
<img src="/assets/LapLogo_white_orange.png" alt="Lapikud Logo" class="h-12 md:h-14 w-auto" />
|
||||||
</div>
|
</Button>
|
||||||
{/if}
|
|
||||||
|
|
||||||
<div class="flex items-center justify-end ml-auto w-full md:w-auto md:border-b-3 md:border-white backdrop-blur-lg bg-black/35">
|
|
||||||
<!-- Desktop Navigation -->
|
|
||||||
<nav class="z-10 hidden md:flex gap-1 justify-end text-lg">
|
|
||||||
<Dropdown
|
|
||||||
name={$text.about}
|
|
||||||
buttonClass="hover:text-orange-500 border-transparent"
|
|
||||||
panelClass="bg-white text-black"
|
|
||||||
>
|
|
||||||
<Button class="bg-transparent hover:text-orange-500 border-transparent" onClick={() => navigate("/lapikutest")}
|
|
||||||
>{$text.aboutPages.info}</Button
|
|
||||||
>
|
|
||||||
<Button class="bg-transparent hover:text-orange-500 border-transparent" onClick={() => navigate("/tudengile")}
|
|
||||||
><Bot />{$text.aboutPages.join}</Button
|
|
||||||
>
|
|
||||||
<Button class="bg-transparent hover:text-orange-500 border-transparent" onClick={() => navigate("/mentorid")}
|
|
||||||
><HandHeart />{$text.aboutPages.mentors}</Button
|
|
||||||
>
|
|
||||||
<Button class="bg-transparent hover:text-orange-500 border-transparent" onClick={() => navigate("/juhatus")}
|
|
||||||
><Lectern />{$text.aboutPages.board}</Button
|
|
||||||
>
|
|
||||||
</Dropdown>
|
|
||||||
<Dropdown
|
|
||||||
name={$text.events}
|
|
||||||
buttonClass="hover:text-orange-500 border-transparent"
|
|
||||||
panelClass="bg-white text-black"
|
|
||||||
>
|
|
||||||
<Button class="bg-transparent hover:text-orange-500 border-transparent" onClick={() => navigate("/koolitused")}
|
|
||||||
><Presentation />{$text.eventsPages.workshops}</Button
|
|
||||||
>
|
|
||||||
<Button class="bg-transparent hover:text-orange-500 border-transparent" onClick={() => navigate("https://asikarikas.ee/", { external: true })}
|
|
||||||
><Trophy />ASI Karikas</Button
|
|
||||||
>
|
|
||||||
<Button class="bg-transparent hover:text-orange-500 border-transparent" onClick={() => navigate("https://remondikohvik.lapikud.ee/", { external: true })}
|
|
||||||
><Coffee />{$text.eventsPages.repair}</Button
|
|
||||||
>
|
|
||||||
</Dropdown>
|
|
||||||
<Button class="hover:text-orange-500 border-transparent" onClick={() => navigate("/helpdesk")}
|
|
||||||
>{$text.helpdesk}
|
|
||||||
</Button>
|
|
||||||
<Button class="hover:text-orange-500 border-transparent" onClick={() => navigate("/kontakt")}
|
|
||||||
>{$text.contact}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<!-- Language Switcher -->
|
|
||||||
<Button
|
|
||||||
class="px-3 py-1 text-sm ml-4 hover:text-orange-500 border-transparent"
|
|
||||||
onClick={() => switchLanguageRoute($currentLang === 'est' ? 'en' : 'est')}
|
|
||||||
>
|
|
||||||
{$currentLang === 'est' ? 'EN' : 'EST'}
|
|
||||||
</Button>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<!-- Mobile Hamburger Button - Fixed position -->
|
<div class="flex items-center justify-end ml-auto w-full md:w-auto">
|
||||||
{#if !mobileMenuOpen}
|
<nav class="z-10 hidden md:flex items-center gap-1 justify-end text-lg">
|
||||||
<Button
|
<Dropdown
|
||||||
onClick={toggleMobileMenu}
|
name={$text.about}
|
||||||
class="mobile-only p-2 text-white transition-colors bg-transparent absolute right-0 hover:text-white border-transparent"
|
buttonClass={`${dropdownButtonClass(isInGroup(aboutRoutes))} ${isInGroup(aboutRoutes) ? "nav-active-parent" : ""}`}
|
||||||
aria-label="Toggle navigation menu"
|
panelClass="nav-dropdown-panel"
|
||||||
>
|
>
|
||||||
<Menu size={32} />
|
<Button
|
||||||
</Button>
|
class={dropdownItemClass(isCurrent("/lapikutest") || isCurrent("/aboutus"))}
|
||||||
{/if}
|
onClick={() => handleNavigation("/lapikutest")}
|
||||||
|
>
|
||||||
|
{$text.aboutPages.info}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
class={dropdownItemClass(isCurrent("/tudengile") || isCurrent("/student"))}
|
||||||
|
onClick={() => handleNavigation("/tudengile")}
|
||||||
|
>
|
||||||
|
<Bot />{$text.aboutPages.join}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
class={dropdownItemClass(isCurrent("/mentorid") || isCurrent("/mentors"))}
|
||||||
|
onClick={() => handleNavigation("/mentorid")}
|
||||||
|
>
|
||||||
|
<HandHeart />{$text.aboutPages.mentors}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
class={dropdownItemClass(isCurrent("/juhatus") || isCurrent("/management"))}
|
||||||
|
onClick={() => handleNavigation("/juhatus")}
|
||||||
|
>
|
||||||
|
<Lectern />{$text.aboutPages.board}
|
||||||
|
</Button>
|
||||||
|
</Dropdown>
|
||||||
|
|
||||||
|
<Dropdown
|
||||||
|
name={$text.events}
|
||||||
|
buttonClass={`${dropdownButtonClass(isInGroup(eventsRoutes))} ${isInGroup(eventsRoutes) ? "nav-active-parent" : ""}`}
|
||||||
|
panelClass="nav-dropdown-panel"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
class={dropdownItemClass(isCurrent("/koolitused"))}
|
||||||
|
onClick={() => handleNavigation("/koolitused")}
|
||||||
|
>
|
||||||
|
<Presentation />{$text.eventsPages.workshops}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
class="bg-transparent text-black hover:text-orange-500"
|
||||||
|
onClick={() => handleNavigation("https://asikarikas.ee/", { external: true })}
|
||||||
|
>
|
||||||
|
<Trophy />ASI Karikas
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
class="bg-transparent text-black hover:text-orange-500"
|
||||||
|
onClick={() => handleNavigation("https://remondikohvik.lapikud.ee/", { external: true })}
|
||||||
|
>
|
||||||
|
<Coffee />{$text.eventsPages.repair}
|
||||||
|
</Button>
|
||||||
|
</Dropdown>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
class={navButtonClass(isCurrent("/helpdesk"))}
|
||||||
|
onClick={() => handleNavigation("/helpdesk")}
|
||||||
|
>
|
||||||
|
{$text.helpdesk}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
class={navButtonClass(isCurrent("/kontakt") || isCurrent("/contact"))}
|
||||||
|
onClick={() => handleNavigation("/kontakt")}
|
||||||
|
>
|
||||||
|
{$text.contact}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
class="ml-3 border-transparent bg-transparent px-3 py-1 text-sm text-white/75 hover:text-orange-500 hover:bg-white/5"
|
||||||
|
onClick={() => switchLanguageRoute($currentLang === "est" ? "en" : "est")}
|
||||||
|
>
|
||||||
|
{$currentLang === "est" ? "EN" : "EST"}
|
||||||
|
</Button>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{#if !mobileMenuOpen}
|
||||||
|
<Button
|
||||||
|
onClick={toggleMobileMenu}
|
||||||
|
class="mobile-only ml-auto border-transparent bg-transparent p-2 text-white transition-colors hover:text-orange-500"
|
||||||
|
aria-label="Toggle navigation menu"
|
||||||
|
>
|
||||||
|
<Menu size={32} />
|
||||||
|
</Button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
</Container>
|
||||||
</Container>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- Full Screen Mobile Menu -->
|
<!-- Full Screen Mobile Menu -->
|
||||||
@@ -226,33 +292,40 @@
|
|||||||
|
|
||||||
<!-- Menu Content -->
|
<!-- Menu Content -->
|
||||||
<Stack gap="gap-5" class="flex-1 px-8 pt-24 pb-12 text-white text-xl">
|
<Stack gap="gap-5" class="flex-1 px-8 pt-24 pb-12 text-white text-xl">
|
||||||
|
<Button
|
||||||
|
onClick={() => handleNavigation("/")}
|
||||||
|
class="mb-3 border-transparent bg-transparent px-0 py-0 text-left text-white hover:text-white"
|
||||||
|
>
|
||||||
|
<img src="/assets/LapLogo_white_orange.png" alt="Lapikud Logo" class="h-12 w-auto" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
<!-- About Section -->
|
<!-- About Section -->
|
||||||
<Stack gap="gap-3">
|
<Stack gap="gap-3">
|
||||||
<h3 class="text-2xl font-bold text-orange-500">{$text.about}</h3>
|
<h3 class="text-2xl font-bold text-orange-500">{$text.about}</h3>
|
||||||
<Stack gap="gap-2" class="pl-4">
|
<Stack gap="gap-2" class="pl-4">
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleNavigation("/lapikutest")}
|
onClick={() => handleNavigation("/lapikutest")}
|
||||||
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500 border-transparent"
|
class={`text-left transition-colors flex items-center gap-2 bg-transparent border-transparent ${isCurrent("/lapikutest") || isCurrent("/aboutus") ? "text-orange-500" : "hover:text-orange-500"}`}
|
||||||
>
|
>
|
||||||
{$text.aboutPages.info}
|
{$text.aboutPages.info}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleNavigation("/tudengile")}
|
onClick={() => handleNavigation("/tudengile")}
|
||||||
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500 border-transparent"
|
class={`text-left transition-colors flex items-center gap-2 bg-transparent border-transparent ${isCurrent("/tudengile") || isCurrent("/student") ? "text-orange-500" : "hover:text-orange-500"}`}
|
||||||
>
|
>
|
||||||
<Bot size={20} />
|
<Bot size={20} />
|
||||||
{$text.aboutPages.join}
|
{$text.aboutPages.join}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleNavigation("/mentorid")}
|
onClick={() => handleNavigation("/mentorid")}
|
||||||
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500 border-transparent"
|
class={`text-left transition-colors flex items-center gap-2 bg-transparent border-transparent ${isCurrent("/mentorid") || isCurrent("/mentors") ? "text-orange-500" : "hover:text-orange-500"}`}
|
||||||
>
|
>
|
||||||
<HandHeart size={20} />
|
<HandHeart size={20} />
|
||||||
{$text.aboutPages.mentors}
|
{$text.aboutPages.mentors}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleNavigation("/juhatus")}
|
onClick={() => handleNavigation("/juhatus")}
|
||||||
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500 border-transparent"
|
class={`text-left transition-colors flex items-center gap-2 bg-transparent border-transparent ${isCurrent("/juhatus") || isCurrent("/management") ? "text-orange-500" : "hover:text-orange-500"}`}
|
||||||
>
|
>
|
||||||
<Lectern size={20} />
|
<Lectern size={20} />
|
||||||
{$text.aboutPages.board}
|
{$text.aboutPages.board}
|
||||||
@@ -292,13 +365,13 @@
|
|||||||
<Stack gap="gap-3">
|
<Stack gap="gap-3">
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleNavigation("/helpdesk")}
|
onClick={() => handleNavigation("/helpdesk")}
|
||||||
class="text-left text-2xl font-semibold transition-colors bg-transparent hover:text-orange-500 border-transparent"
|
class={`text-left text-2xl font-semibold transition-colors bg-transparent border-transparent ${isCurrent("/helpdesk") ? "text-orange-500" : "hover:text-orange-500"}`}
|
||||||
>
|
>
|
||||||
{$text.helpdesk}
|
{$text.helpdesk}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleNavigation("/kontakt")}
|
onClick={() => handleNavigation("/kontakt")}
|
||||||
class="text-left text-2xl font-semibold transition-colors bg-transparent hover:text-orange-500 border-transparent"
|
class={`text-left text-2xl font-semibold transition-colors bg-transparent border-transparent ${isCurrent("/kontakt") || isCurrent("/contact") ? "text-orange-500" : "hover:text-orange-500"}`}
|
||||||
>
|
>
|
||||||
{$text.contact}
|
{$text.contact}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
17
src/lib/locales/en/Management.json
Normal file
17
src/lib/locales/en/Management.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"hero": {
|
||||||
|
"eyebrow": "MTÜ Lapikud",
|
||||||
|
"title": "Management",
|
||||||
|
"intro": "People who keep the organisation moving forward."
|
||||||
|
},
|
||||||
|
"current": {
|
||||||
|
"label": "Current board",
|
||||||
|
"hint": "Contacts and responsibilities"
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
"label": "People who have led the organisation over time",
|
||||||
|
"hint": "Thanks to everyone who has helped guide Lapikud"
|
||||||
|
},
|
||||||
|
"loading": "Loading data…",
|
||||||
|
"error": "Failed to load the management data."
|
||||||
|
}
|
||||||
17
src/lib/locales/est/Management.json
Normal file
17
src/lib/locales/est/Management.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"hero": {
|
||||||
|
"eyebrow": "MTÜ Lapikud",
|
||||||
|
"title": "Juhtkond",
|
||||||
|
"intro": "Inimesed, kes viivad organisatsiooni edasi."
|
||||||
|
},
|
||||||
|
"current": {
|
||||||
|
"label": "Praegune juhtkond",
|
||||||
|
"hint": "Kontaktid ja vastutusvaldkonnad"
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
"label": "Organisatsiooni juhtinud inimesed läbi aegade",
|
||||||
|
"hint": "Tänu kõigile, kes on Lapikuid juhtinud"
|
||||||
|
},
|
||||||
|
"loading": "Laadin andmeid…",
|
||||||
|
"error": "Juhtkonna andmete laadimine ebaõnnestus."
|
||||||
|
}
|
||||||
@@ -1,113 +1,610 @@
|
|||||||
<script>
|
<script>
|
||||||
import {
|
import { Section, Grid, Container, Image } from "$components";
|
||||||
Section,
|
import { text } from "$lib";
|
||||||
Grid,
|
|
||||||
Card,
|
|
||||||
Center,
|
|
||||||
Container,
|
|
||||||
Stack,
|
|
||||||
} from "$components";
|
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import yaml from 'js-yaml';
|
import yaml from "js-yaml";
|
||||||
import { currentLang, getLangText } from "$lib";
|
import Mail from "lucide-svelte/icons/mail";
|
||||||
import Mailbox from "lucide-svelte/icons/mailbox";
|
|
||||||
import Phone from "lucide-svelte/icons/phone";
|
import Phone from "lucide-svelte/icons/phone";
|
||||||
|
|
||||||
let currentManagement = [];
|
let currentManagement = [];
|
||||||
let pastManagement = [];
|
let pastManagement = [];
|
||||||
let lang = 'est';
|
let loading = true;
|
||||||
|
let loadError = false;
|
||||||
|
|
||||||
currentLang.subscribe(value => {
|
const fallbackText = {
|
||||||
lang = value;
|
est: {
|
||||||
});
|
hero: {
|
||||||
|
eyebrow: "MTÜ Lapikud",
|
||||||
|
title: "Juhtkond",
|
||||||
|
intro: "Inimesed, kes viivad organisatsiooni edasi.",
|
||||||
|
},
|
||||||
|
current: {
|
||||||
|
label: "Praegune juhtkond",
|
||||||
|
hint: "Kontaktid ja vastutusvaldkonnad",
|
||||||
|
},
|
||||||
|
history: {
|
||||||
|
label: "Organisatsiooni juhtinud inimesed läbi aegade",
|
||||||
|
hint: "Tänu kõigile, kes on Lapikuid juhtinud",
|
||||||
|
},
|
||||||
|
loading: "Laadin andmeid…",
|
||||||
|
error: "Juhtkonna andmete laadimine ebaõnnestus.",
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
hero: {
|
||||||
|
eyebrow: "MTÜ Lapikud",
|
||||||
|
title: "Management",
|
||||||
|
intro: "People who keep the organisation moving forward.",
|
||||||
|
},
|
||||||
|
current: {
|
||||||
|
label: "Current board",
|
||||||
|
hint: "Contacts and responsibilities",
|
||||||
|
},
|
||||||
|
history: {
|
||||||
|
label: "People who have led the organisation over time",
|
||||||
|
hint: "Thanks to everyone who has helped guide Lapikud",
|
||||||
|
},
|
||||||
|
loading: "Loading data…",
|
||||||
|
error: "Failed to load the management data.",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function getText() {
|
||||||
|
return $text.management ?? fallbackText.est;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseYearLabel(label) {
|
||||||
|
const text = String(label ?? "");
|
||||||
|
const match = text.match(/^(\d{4})(?:\s*\((.+)\))?$/);
|
||||||
|
|
||||||
|
if (!match) {
|
||||||
|
return { year: text, tag: "" };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
year: match[1],
|
||||||
|
tag: match[2] ?? "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBoardLabel(member) {
|
||||||
|
if (!member) return "";
|
||||||
|
if (member.role && member.role !== "Juhatuse liige") {
|
||||||
|
return member.role;
|
||||||
|
}
|
||||||
|
return member.subrole || member.role || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPhoneHref(phone) {
|
||||||
|
if (!phone) return "";
|
||||||
|
return `tel:${String(phone).replace(/[\s()-]/g, "")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInitials(name) {
|
||||||
|
return String(name ?? "")
|
||||||
|
.split(/\s+/)
|
||||||
|
.filter(Boolean)
|
||||||
|
.slice(0, 2)
|
||||||
|
.map((part) => part[0]?.toUpperCase() ?? "")
|
||||||
|
.join("") || "?";
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
try {
|
try {
|
||||||
const currentRes = await fetch('/_data/management.yml');
|
const [currentRes, pastRes] = await Promise.all([
|
||||||
const currentYaml = await currentRes.text();
|
fetch("/_data/management.yml"),
|
||||||
currentManagement = yaml.load(currentYaml) || [];
|
fetch("/_data/past_management.yml"),
|
||||||
|
]);
|
||||||
|
|
||||||
const pastRes = await fetch('/_data/past_management.yml');
|
const [currentYaml, pastYaml] = await Promise.all([
|
||||||
const pastYaml = await pastRes.text();
|
currentRes.text(),
|
||||||
|
pastRes.text(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
currentManagement = yaml.load(currentYaml) || [];
|
||||||
pastManagement = yaml.load(pastYaml) || [];
|
pastManagement = yaml.load(pastYaml) || [];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading management data:', error);
|
console.error("Error loading management data:", error);
|
||||||
|
loadError = true;
|
||||||
|
} finally {
|
||||||
|
loading = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Current Management Section -->
|
<Section
|
||||||
<Section padding="large">
|
padding="none"
|
||||||
<Center>
|
fullWidth={true}
|
||||||
<h1 class="text-4xl font-light pb-8 text-center">Praegune juhtkond</h1>
|
contentClass="!px-0 !py-0"
|
||||||
</Center>
|
class="management-page overflow-hidden text-white"
|
||||||
<Grid min="500px" gap="3rem">
|
background="#0d0d0d"
|
||||||
{#each currentManagement as member (member.name)}
|
>
|
||||||
<div class="flex flex-col sm:flex-row gap-6 items-start">
|
<div class="hero-shell">
|
||||||
<div class="w-full sm:w-auto sm:max-w-[200px] aspect-square shrink-0">
|
<div class="hero-orb hero-orb-1" aria-hidden="true"></div>
|
||||||
<img
|
<div class="hero-orb hero-orb-2" aria-hidden="true"></div>
|
||||||
src={`/assets/management-images/${member.photo}`}
|
|
||||||
alt={member.name}
|
<Container class="relative z-10 py-[clamp(3rem,8vw,6rem)]">
|
||||||
class="w-full h-full object-cover rounded-md"
|
<div class="max-w-4xl">
|
||||||
/>
|
<p class="eyebrow">{getText().hero.eyebrow}</p>
|
||||||
</div>
|
<h1 class="hero-title">{getText().hero.title}</h1>
|
||||||
<div class="flex flex-col gap-2 grow">
|
<p class="hero-intro">{getText().hero.intro}</p>
|
||||||
<h3 class="text-2xl font-medium">{member.name}</h3>
|
</div>
|
||||||
<p class="text-base text-gray-700">
|
</Container>
|
||||||
{getLangText(member, 'role', lang)} - {getLangText(member, 'subrole', lang)}
|
</div>
|
||||||
</p>
|
|
||||||
<a
|
|
||||||
href="mailto:{member.email}"
|
|
||||||
class="text-base flex items-center gap-2 text-[#f0941d] hover:opacity-80 transition"
|
|
||||||
>
|
|
||||||
<Mailbox size={18} />{member.email}
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="tel:{member.phone}"
|
|
||||||
class="text-base flex items-center gap-2 text-[#f0941d] hover:opacity-80 transition"
|
|
||||||
>
|
|
||||||
<Phone size={18} />{member.phone}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</Grid>
|
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<!-- Past Management Section -->
|
<Section padding="large" class="current-section bg-white text-gray-900">
|
||||||
<Section padding="large" background="rgba(240, 148, 29, 0.05)">
|
<Container>
|
||||||
<Container center={false}>
|
<div class="section-label">
|
||||||
<Center>
|
<span>{getText().current.label}</span>
|
||||||
<h1 class="text-4xl font-light pb-8 text-center">
|
<span class="section-label-line"></span>
|
||||||
Organisatsiooni juhtinud inimesed läbi aegade
|
</div>
|
||||||
</h1>
|
|
||||||
</Center>
|
<div class="section-heading-row">
|
||||||
<Stack gap="3rem">
|
<div>
|
||||||
{#each pastManagement as yearData (yearData.year)}
|
<h2 class="section-title">{getText().current.label}</h2>
|
||||||
<div>
|
<p class="section-subtitle">{getText().current.hint}</p>
|
||||||
<div class="flex items-center gap-4 pb-6 mb-6 border-b-2 border-[#f0941d]">
|
</div>
|
||||||
<h2 class="text-3xl font-light text-[#f0941d] whitespace-nowrap">
|
</div>
|
||||||
{yearData.year}
|
|
||||||
</h2>
|
{#if loading}
|
||||||
</div>
|
<p class="section-message">{getText().loading}</p>
|
||||||
<Grid min="120px" gap="1rem">
|
{:else if loadError}
|
||||||
{#each yearData.members as member (member.name)}
|
<p class="section-message section-message-error">{getText().error}</p>
|
||||||
<div class="flex flex-col items-center">
|
{:else}
|
||||||
<div class="w-full h-auto max-w-[150px] mx-auto aspect-square mb-3">
|
<Grid min="280px" gap="gap-6" class="board-grid">
|
||||||
<img
|
{#each currentManagement as member (member.name)}
|
||||||
src={`/assets/past-management-images/optimised/${member.image}`}
|
<article class="board-card">
|
||||||
alt={member.name}
|
<div class="board-card-media">
|
||||||
class="w-full h-full object-cover rounded-md"
|
{#if member.photo}
|
||||||
/>
|
<Image
|
||||||
</div>
|
src={`/assets/management-images/${member.photo}`}
|
||||||
<h3 class="text-base font-medium text-center">
|
alt={member.name}
|
||||||
{member.name}
|
objectFit="cover"
|
||||||
</h3>
|
class="board-card-image"
|
||||||
|
pictureClass="board-card-picture"
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<div class="board-card-placeholder">{getInitials(member.name)}</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="board-card-body">
|
||||||
|
<div class="board-card-domain">{getBoardLabel(member)}</div>
|
||||||
|
<div class="board-card-name">{member.name}</div>
|
||||||
|
|
||||||
|
<div class="board-card-contacts">
|
||||||
|
{#if member.email}
|
||||||
|
<a href={`mailto:${member.email}`}>
|
||||||
|
<Mail size={14} strokeWidth={2} />
|
||||||
|
<span>{member.email}</span>
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if member.phone}
|
||||||
|
<a href={getPhoneHref(member.phone)}>
|
||||||
|
<Phone size={14} strokeWidth={2} />
|
||||||
|
<span>{member.phone}</span>
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
</div>
|
||||||
</Grid>
|
</article>
|
||||||
</div>
|
{/each}
|
||||||
{/each}
|
</Grid>
|
||||||
</Stack>
|
{/if}
|
||||||
</Container>
|
</Container>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
|
<div class="divider"></div>
|
||||||
|
|
||||||
|
<Section padding="large" class="history-section" background="#fffdfa">
|
||||||
|
<Container>
|
||||||
|
<div class="section-label">
|
||||||
|
<span>{getText().history.label}</span>
|
||||||
|
<span class="section-label-line"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section-heading-row">
|
||||||
|
<div>
|
||||||
|
<h2 class="section-title">{getText().history.label}</h2>
|
||||||
|
<p class="section-subtitle">{getText().history.hint}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if loading}
|
||||||
|
<p class="section-message">{getText().loading}</p>
|
||||||
|
{:else if loadError}
|
||||||
|
<p class="section-message section-message-error">{getText().error}</p>
|
||||||
|
{:else}
|
||||||
|
<div class="history-list">
|
||||||
|
{#each pastManagement as yearData (yearData.year)}
|
||||||
|
<section class="year-block">
|
||||||
|
<div class="year-header">
|
||||||
|
<div class="year-heading-group">
|
||||||
|
<span class="year-number">{parseYearLabel(yearData.year).year}</span>
|
||||||
|
{#if parseYearLabel(yearData.year).tag}
|
||||||
|
<span class="year-tag">{parseYearLabel(yearData.year).tag}</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<span class="year-line"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Grid min="150px" gap="gap-5" class="year-people">
|
||||||
|
{#each yearData.members as member (member.name)}
|
||||||
|
<div class="person-item">
|
||||||
|
<div class="person-photo">
|
||||||
|
{#if member.image}
|
||||||
|
<Image
|
||||||
|
src={`/assets/past-management-images/optimised/${member.image}`}
|
||||||
|
alt={member.name}
|
||||||
|
objectFit="cover"
|
||||||
|
class="person-image"
|
||||||
|
pictureClass="person-picture"
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<div class="person-placeholder">{getInitials(member.name)}</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<span class="person-name">{member.name}</span>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</Grid>
|
||||||
|
</section>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</Container>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.hero-shell {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background: linear-gradient(180deg, #0d0d0d 0%, #111111 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-shell::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: auto 0 0 0;
|
||||||
|
height: 1px;
|
||||||
|
background: rgba(240, 148, 29, 0.16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-orb {
|
||||||
|
position: absolute;
|
||||||
|
border: 1px solid rgba(240, 148, 29, 0.12);
|
||||||
|
border-radius: 999px;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-orb-1 {
|
||||||
|
top: -4rem;
|
||||||
|
right: -4rem;
|
||||||
|
width: 20rem;
|
||||||
|
height: 20rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-orb-2 {
|
||||||
|
bottom: -5rem;
|
||||||
|
right: 4rem;
|
||||||
|
width: 13rem;
|
||||||
|
height: 13rem;
|
||||||
|
border-color: rgba(240, 148, 29, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.eyebrow {
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||||
|
"Liberation Mono", "Courier New", monospace;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
letter-spacing: 0.16em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: #f0941d;
|
||||||
|
margin: 0 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: clamp(2.4rem, 6vw, 4.2rem);
|
||||||
|
line-height: 1.05;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.04em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-intro {
|
||||||
|
margin: 1rem 0 0;
|
||||||
|
max-width: 52ch;
|
||||||
|
font-size: clamp(1.05rem, 1.5vw, 1.25rem);
|
||||||
|
line-height: 1.7;
|
||||||
|
color: rgba(255, 255, 255, 0.76);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.8rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||||
|
"Liberation Mono", "Courier New", monospace;
|
||||||
|
font-size: 0.72rem;
|
||||||
|
letter-spacing: 0.14em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: #f0941d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-label-line {
|
||||||
|
flex: 1;
|
||||||
|
height: 1px;
|
||||||
|
background: rgba(13, 13, 13, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-heading-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 1.5rem;
|
||||||
|
margin-bottom: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: clamp(1.8rem, 3vw, 2.6rem);
|
||||||
|
line-height: 1.12;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-subtitle {
|
||||||
|
margin: 0.45rem 0 0;
|
||||||
|
color: rgba(13, 13, 13, 0.62);
|
||||||
|
font-size: 0.98rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-message {
|
||||||
|
margin: 0;
|
||||||
|
padding: 1rem 0;
|
||||||
|
color: rgba(13, 13, 13, 0.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-message-error {
|
||||||
|
color: #b42318;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.board-grid) {
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-card {
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 14px;
|
||||||
|
border: 1px solid rgba(13, 13, 13, 0.08);
|
||||||
|
background: #ffffff;
|
||||||
|
transition: transform 0.2s ease, border-color 0.2s ease,
|
||||||
|
box-shadow 0.2s ease;
|
||||||
|
box-shadow: 0 1px 0 rgba(13, 13, 13, 0.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-card:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
border-color: rgba(240, 148, 29, 0.35);
|
||||||
|
box-shadow: 0 12px 30px rgba(13, 13, 13, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-card-media {
|
||||||
|
aspect-ratio: 4 / 3;
|
||||||
|
background: linear-gradient(135deg, #f7f1e6, #efe5d3);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.board-card-picture),
|
||||||
|
:global(.board-card-image) {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.board-card-image) {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-card-placeholder {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.04em;
|
||||||
|
color: #d67d0a;
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||||
|
"Liberation Mono", "Courier New", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-card-body {
|
||||||
|
padding: 1.2rem 1.2rem 1.25rem;
|
||||||
|
border-top: 1px solid rgba(13, 13, 13, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-card-domain {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 0.7rem;
|
||||||
|
padding: 0.2rem 0.55rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(240, 148, 29, 0.1);
|
||||||
|
color: #d67d0a;
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||||
|
"Liberation Mono", "Courier New", monospace;
|
||||||
|
font-size: 0.65rem;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-card-name {
|
||||||
|
margin: 0 0 0.8rem;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 650;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-card-contacts {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-card-contacts a {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.45rem;
|
||||||
|
color: rgba(13, 13, 13, 0.54);
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||||
|
"Liberation Mono", "Courier New", monospace;
|
||||||
|
font-size: 0.77rem;
|
||||||
|
font-weight: 500;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-card-contacts a:hover {
|
||||||
|
color: #f0941d;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
height: 1px;
|
||||||
|
background: rgba(13, 13, 13, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.history-section) {
|
||||||
|
background: #fffdfa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.year-block {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.year-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-bottom: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.year-heading-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 0.75rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.year-number {
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||||
|
"Liberation Mono", "Courier New", monospace;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.04em;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.year-tag {
|
||||||
|
padding: 0.2rem 0.55rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(240, 148, 29, 0.12);
|
||||||
|
color: #d67d0a;
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||||
|
"Liberation Mono", "Courier New", monospace;
|
||||||
|
font-size: 0.64rem;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.year-line {
|
||||||
|
flex: 1;
|
||||||
|
height: 1px;
|
||||||
|
background: rgba(13, 13, 13, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.year-people) {
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.55rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-photo {
|
||||||
|
width: 112px;
|
||||||
|
height: 112px;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: linear-gradient(135deg, #efe6d7, #e7dbc7);
|
||||||
|
outline: 2px solid transparent;
|
||||||
|
outline-offset: 2px;
|
||||||
|
transition: outline-color 0.2s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-item:hover .person-photo {
|
||||||
|
outline-color: #f0941d;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.person-picture),
|
||||||
|
:global(.person-image) {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.person-image) {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-placeholder {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
color: #d67d0a;
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||||
|
"Liberation Mono", "Courier New", monospace;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-name {
|
||||||
|
max-width: 14ch;
|
||||||
|
font-size: 0.86rem;
|
||||||
|
line-height: 1.35;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #0d0d0d;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.section-heading-row {
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.year-header {
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.year-line {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-photo {
|
||||||
|
width: 96px;
|
||||||
|
height: 96px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user