This commit is contained in:
Henri
2026-04-21 19:41:01 +03:00
parent 6b885d80af
commit 2ef643d15f
8 changed files with 260 additions and 518 deletions

View File

@@ -1,4 +1,9 @@
{ {
"intro": {
"prefix": "Our ",
"emphasis": "work.",
"subtitle": "A selection of projects our members have delivered, from websites to mobile apps."
},
"hero": { "hero": {
"title": "For companies", "title": "For companies",
"description": "We help bring your ideas to life. Our experienced students are ready to deliver your projects." "description": "We help bring your ideas to life. Our experienced students are ready to deliver your projects."
@@ -89,9 +94,13 @@
] ]
}, },
"portfolio": { "portfolio": {
"title": "Our work", "label": "Our Work",
"subtitle": "See what we have built before", "title": "Projects that speak for themselves.",
"projectLink": "View project" "subtitle": "Every project has a story. Here is a selection of work our members have delivered over the years.",
"projectLink": "View project",
"featured": "Featured",
"placeholder": "No image",
"noDescription": "Description coming soon."
}, },
"cta": { "cta": {
"title": "Shall we start working together?", "title": "Shall we start working together?",

View File

@@ -1,4 +1,9 @@
{ {
"intro": {
"prefix": "Meie tehtud ",
"emphasis": "tööd.",
"subtitle": "Valik projekte, mida meie liikmed on teostanud, veebilehtedest mobiilirakendusteni."
},
"hero": { "hero": {
"title": "Ettevõttele", "title": "Ettevõttele",
"description": "Aitame sinu ideed ellu viia! Meie kogenud tudengid on valmis teie projekte realiseerima." "description": "Aitame sinu ideed ellu viia! Meie kogenud tudengid on valmis teie projekte realiseerima."
@@ -89,9 +94,13 @@
] ]
}, },
"portfolio": { "portfolio": {
"title": "Meie tehtud tööd", "label": "Tehtud tööd",
"subtitle": "Vaata, mida oleme varem loonud", "title": "Projektid, mis räägivad enda eest.",
"projectLink": "Vaata projekti" "subtitle": "Igal projektil on oma lugu. Siin on valik töödest, mida meie liikmed on aastate jooksul ellu viinud.",
"projectLink": "Vaata projekti",
"featured": "Esile tõstetud",
"placeholder": "Pilt puudub",
"noDescription": "Kirjeldus lisamisel."
}, },
"cta": { "cta": {
"title": "Alustame koostööd?", "title": "Alustame koostööd?",

View File

@@ -15,6 +15,6 @@
<div class="safe-area-navbar"> <div class="safe-area-navbar">
<Section> <Section>
{$text.placeholder || "In development..."} <p>In development...</p>
</Section> </Section>
</div> </div>

View File

@@ -2,321 +2,20 @@
import { import {
Section, Section,
Grid, Grid,
Card,
Center, Center,
} from "$components"; } from "$components";
import { onDestroy } from "svelte"; import { onDestroy } from "svelte";
import { createPageTextStore } from "$lib"; import { createPageTextStore } from "$lib";
import MapPin from "lucide-svelte/icons/map-pin";
import Mail from "lucide-svelte/icons/mail";
import Phone from "lucide-svelte/icons/phone";
import MessageCircle from "lucide-svelte/icons/message-circle";
import Facebook from "lucide-svelte/icons/facebook";
import Instagram from "lucide-svelte/icons/instagram";
import Github from "lucide-svelte/icons/github";
import Building from "lucide-svelte/icons/building";
import Clock from "lucide-svelte/icons/clock";
const text = createPageTextStore("Contact"); const text = createPageTextStore("Contact");
$: contactMethods = [
{
icon: MapPin,
title: $text["methods"]?.addressTitle || "Aadress",
content: "Akadeemia tee 5, 12616 Tallinn",
subtitle: $text["methods"]?.addressSubtitle || "ICT-teaduskond, Raja 15 ruum 111",
link: "https://goo.gl/maps/..."
},
{
icon: Mail,
title: $text["methods"]?.emailTitle || "E-post",
content: "lapikud@lapikud.ee",
link: "mailto:lapikud@lapikud.ee"
},
{
icon: Phone,
title: $text["methods"]?.phoneTitle || "Telefon",
content: "+372 58 160 799",
link: "tel:+37258160799"
},
{
icon: MessageCircle,
title: $text["methods"]?.messengerTitle || "Messenger",
content: "m.me/Lapikud",
link: "https://m.me/Lapikud"
}
];
const socialMedia = [
{
icon: Facebook,
name: "Facebook",
link: "https://www.facebook.com/Lapikud/"
},
{
icon: Instagram,
name: "Instagram",
link: "https://www.instagram.com/lapikud/"
},
{
icon: Github,
name: "GitHub",
link: "https://github.com/Lapikud/"
}
];
$: organizationInfo = [
{
icon: Building,
title: $text["organization"]?.registryTitle || "Registrikood",
content: "80167145"
},
{
icon: Building,
title: $text["organization"]?.bankTitle || "Pangakonto",
content: "EE812200221019551756",
subtitle: $text["organization"]?.bankSubtitle || "Swedbank"
}
];
let formData = {
name: '',
email: '',
subject: '',
message: ''
};
function handleSubmit(e) {
e.preventDefault();
// Create mailto link with form data
const mailtoLink = `mailto:lapikud@lapikud.ee?subject=${encodeURIComponent(formData.subject)}&body=${encodeURIComponent(`${$text["form"]?.mailBody?.name || "Nimi"}: ${formData.name}\n${$text["form"]?.mailBody?.email || "E-post"}: ${formData.email}\n\n${$text["form"]?.mailBody?.message || "Sõnum"}:\n${formData.message}`)}`;
window.location.href = mailtoLink;
}
onDestroy(() => { onDestroy(() => {
text.destroy(); text.destroy();
}); });
</script> </script>
<div class="safe-area-navbar"> <div class="safe-area-navbar">
<!-- Hero Section -->
<Section background="orange">
<Center>
<div class="text-center max-w-4xl">
<h1 class="text-5xl font-bold mb-6">{$text["hero"]?.title || "Võta ühendust"}</h1>
<p class="text-2xl leading-relaxed">
{$text["hero"]?.description || "Kas sul on küsimusi? Tahad liituda? Või soovid alustada koostööd? Võta julgelt ühendust!"}
</p>
</div>
</Center>
</Section>
<!-- Contact Methods -->
<Section> <Section>
<div class="text-center mb-12"> <p>In development...</p>
<h2 class="text-4xl font-bold mb-4">{$text["methods"]?.title || "Kuidas meiega ühendust võtta?"}</h2>
<p class="text-xl text-gray-600">{$text["methods"]?.subtitle || "Vali endale sobiv viis"}</p>
</div>
<Grid columns={2} gap="gap-5">
{#each contactMethods as method}
<Card variant="glass">
<div class="flex items-start gap-4">
<div class="feature-icon shrink-0" style="color: var(--orange)">
<svelte:component this={method.icon} size={32} strokeWidth={1.5} />
</div>
<div class="flex-1">
<h3 class="text-xl font-bold mb-2">{method.title}</h3>
{#if method.link}
<a
href={method.link}
class="text-lg hover:underline"
style="color: var(--orange)"
target={method.link.startsWith('http') ? '_blank' : '_self'}
rel={method.link.startsWith('http') ? 'noopener noreferrer' : ''}
>
{method.content}
</a>
{:else}
<p class="text-lg">{method.content}</p>
{/if}
{#if method.subtitle}
<p class="text-gray-600 text-sm mt-1">{method.subtitle}</p>
{/if}
</div>
</div>
</Card>
{/each}
</Grid>
</Section>
<!-- Contact Form -->
<Section background="neutral">
<div class="max-w-3xl mx-auto">
<div class="text-center mb-8">
<h2 class="text-4xl font-bold mb-4">{$text["form"]?.title || "Saada meile sõnum"}</h2>
<p class="text-xl text-gray-600">{$text["form"]?.subtitle || "Täida vorm ja me võtame sinuga ühendust"}</p>
</div>
<Card variant="glass">
<form on:submit={handleSubmit} class="space-y-6">
<div>
<label for="name" class="block text-sm font-semibold mb-2">{$text["form"]?.nameLabel || "Nimi *"}</label>
<input
type="text"
id="name"
bind:value={formData.name}
required
class="w-full px-4 py-3 rounded-lg border border-gray-300 focus:border-orange-500 focus:ring-2 focus:ring-orange-200 outline-none transition"
placeholder={$text["form"]?.namePlaceholder || "Sinu nimi"}
/>
</div>
<div>
<label for="email" class="block text-sm font-semibold mb-2">{$text["form"]?.emailLabel || "E-post *"}</label>
<input
type="email"
id="email"
bind:value={formData.email}
required
class="w-full px-4 py-3 rounded-lg border border-gray-300 focus:border-orange-500 focus:ring-2 focus:ring-orange-200 outline-none transition"
placeholder={$text["form"]?.emailPlaceholder || "sinu@email.ee"}
/>
</div>
<div>
<label for="subject" class="block text-sm font-semibold mb-2">{$text["form"]?.subjectLabel || "Teema *"}</label>
<input
type="text"
id="subject"
bind:value={formData.subject}
required
class="w-full px-4 py-3 rounded-lg border border-gray-300 focus:border-orange-500 focus:ring-2 focus:ring-orange-200 outline-none transition"
placeholder={$text["form"]?.subjectPlaceholder || "Sõnumi teema"}
/>
</div>
<div>
<label for="message" class="block text-sm font-semibold mb-2">{$text["form"]?.messageLabel || "Sõnum *"}</label>
<textarea
id="message"
bind:value={formData.message}
required
rows="6"
class="w-full px-4 py-3 rounded-lg border border-gray-300 focus:border-orange-500 focus:ring-2 focus:ring-orange-200 outline-none transition resize-none"
placeholder={$text["form"]?.messagePlaceholder || "Kirjuta oma sõnum siia..."}
></textarea>
</div>
<button
type="submit"
class="w-full py-3 px-6 bg-orange-500 hover:bg-orange-600 text-white font-semibold rounded-lg transition-colors"
>
{$text["form"]?.submit || "Saada sõnum"}
</button>
</form>
</Card>
</div>
</Section>
<!-- Office Hours & Location -->
<Section>
<Grid gap="gap-5">
<Card variant="glass">
<div class="flex items-start gap-4 mb-4">
<div class="feature-icon" style="color: var(--orange)">
<Clock size={32} strokeWidth={1.5} />
</div>
<div>
<h2 class="text-3xl font-bold mb-4">{$text["hours"]?.title || "Lahtiolekuajad"}</h2>
</div>
</div>
<div class="space-y-3 text-lg">
<div class="flex justify-between">
<span class="font-semibold">{$text["hours"]?.weekdays || "Esmaspäev - Reede:"}</span>
<span>{$text["hours"]?.weekdaysTime || "10:00 - 16:00"}</span>
</div>
<div class="flex justify-between">
<span class="font-semibold">{$text["hours"]?.weekend || "Laupäev - Pühapäev:"}</span>
<span>{$text["hours"]?.weekendTime || "Suletud"}</span>
</div>
<p class="text-sm text-gray-600 mt-4">
{$text["hours"]?.note || "* Soovitame enne külastamist võtta ühendust, et vältida ootamist"}
</p>
</div>
</Card>
<Card variant="glass">
<div class="flex items-start gap-4 mb-4">
<div class="feature-icon" style="color: var(--orange)">
<MapPin size={32} strokeWidth={1.5} />
</div>
<div>
<h2 class="text-3xl font-bold mb-4">{$text["location"]?.title || "Kuidas meid leida?"}</h2>
</div>
</div>
<div class="space-y-3 text-lg">
<p><strong>{$text["location"]?.addressLabel || "Aadress:"}</strong> {$text["location"]?.address || "Akadeemia tee 5, 12616 Tallinn"}</p>
<p><strong>{$text["location"]?.buildingLabel || "Hoone:"}</strong> {$text["location"]?.building || "ICT-teaduskond (Raja 15)"}</p>
<p><strong>{$text["location"]?.roomLabel || "Ruum:"}</strong> {$text["location"]?.room || "111"}</p>
<p class="text-sm text-gray-600 mt-4">
{$text["location"]?.note || "Asume Tallinna Tehnikaülikooli ICT-teaduskonna hoones. Kui tuled ühistranspordiga, on lähimad peatused \"Mustakivi\" ja \"Tehnikaülikool\"."}
</p>
</div>
</Card>
</Grid>
</Section>
<!-- Social Media & Legal Info -->
<Section background="neutral">
<Grid gap="gap-5">
<Card variant="glass">
<h2 class="text-3xl font-bold mb-6 text-center">{$text["social"]?.title || "Jälgi meid sotsiaalmeedias"}</h2>
<div class="flex flex-wrap justify-center gap-4">
{#each socialMedia as social}
<a
href={social.link}
target="_blank"
rel="noopener noreferrer"
class="flex items-center gap-3 px-6 py-3 bg-orange-100 hover:bg-orange-200 rounded-lg transition-colors"
>
<svelte:component this={social.icon} size={24} style="color: var(--orange)" />
<span class="font-semibold">{social.name}</span>
</a>
{/each}
</div>
</Card>
<Card variant="glass">
<h2 class="text-3xl font-bold mb-6 text-center">{$text["organization"]?.title || "MTÜ Lapikud"}</h2>
<div class="space-y-3">
{#each organizationInfo as info}
<div class="flex items-start gap-4">
<svelte:component this={info.icon} size={24} style="color: var(--orange)" />
<div>
<p class="font-semibold">{info.title}</p>
<p class="text-gray-700">{info.content}</p>
{#if info.subtitle}
<p class="text-sm text-gray-600">{info.subtitle}</p>
{/if}
</div>
</div>
{/each}
</div>
</Card>
</Grid>
</Section> </Section>
</div> </div>
<style>
.feature-icon {
display: flex;
align-items: center;
justify-content: center;
width: 64px;
height: 64px;
background: rgba(255, 127, 0, 0.1);
border-radius: 50%;
}
</style>

View File

@@ -1,242 +1,241 @@
<script> <script>
import { import { Section, Grid, Card, Button } from "$components";
Section,
Grid,
Card,
Center,
} 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";
import Rocket from "lucide-svelte/icons/rocket";
import Users from "lucide-svelte/icons/users";
import Target from "lucide-svelte/icons/target";
import Briefcase from "lucide-svelte/icons/briefcase";
import Code from "lucide-svelte/icons/code";
import Smartphone from "lucide-svelte/icons/smartphone";
import Globe from "lucide-svelte/icons/globe";
import ArrowRight from "lucide-svelte/icons/arrow-right";
import ExternalLink from "lucide-svelte/icons/external-link"; import ExternalLink from "lucide-svelte/icons/external-link";
let projects = []; let projects = [];
const text = createPageTextStore("OurWork"); const text = createPageTextStore("OurWork");
onMount(async () => { onMount(async () => {
const response = await fetch('/_data/ourwork.yml'); const response = await fetch("/_data/ourwork.yml");
const yamlText = await response.text(); const yamlText = await response.text();
projects = yaml.load(yamlText).filter(p => p.title); const parsed = yaml.load(yamlText) || [];
projects = parsed.filter((p) => p?.title);
}); });
onDestroy(() => { onDestroy(() => {
text.destroy(); text.destroy();
}); });
$: services = [ $: featuredProject = projects[0] || null;
{ $: regularProjects = projects.slice(1);
icon: Globe,
title: $text["services"]?.items?.[0]?.title || "Veebilahendused",
description: $text["services"]?.items?.[0]?.description || "Kaasaegsed ja responsiivsed veebilehed, mis toimivad igal seadmel"
},
{
icon: Smartphone,
title: $text["services"]?.items?.[1]?.title || "Mobiilirakendused",
description: $text["services"]?.items?.[1]?.description || "iOS ja Android rakendused kasutajasõbralike liidestega"
},
{
icon: Code,
title: $text["services"]?.items?.[2]?.title || "Tarkvara arendus",
description: $text["services"]?.items?.[2]?.description || "Kohandatud tarkvaralahendused teie ärivajadusteks"
},
{
icon: Briefcase,
title: $text["services"]?.items?.[3]?.title || "Konsultatsioon",
description: $text["services"]?.items?.[3]?.description || "IT-nõustamine ja projekti planeerimine"
}
];
$: whyUs = [ function projectTitle(project) {
{ return getLangText(project, "title", $currentLang);
icon: Users, }
title: $text["whyUs"]?.items?.[0]?.title || "Motiveeritud meeskond",
description: $text["whyUs"]?.items?.[0]?.description || "Meie tudengid on andekad, õhevil ja tahavad tõestada oma oskuseid" function projectDescription(project) {
}, return getLangText(project, "description", $currentLang);
{ }
icon: Target,
title: $text["whyUs"]?.items?.[1]?.title || "Kvaliteetne tulemus", function projectImage(project) {
description: $text["whyUs"]?.items?.[1]?.description || "Võtame iga projekti tõsiselt ja pingutame parima tulemuse nimel" return project?.photo
}, ? `/assets/ourwork-images/optimised/${project.photo}`
{ : "";
icon: Rocket, }
title: $text["whyUs"]?.items?.[2]?.title || "Kaasaegsed tehnoloogiad",
description: $text["whyUs"]?.items?.[2]?.description || "Kasutame uusimaid tööriistu ja tehnoloogiaid" function handleImageError(event, photo) {
} event.currentTarget.src = `/assets/ourwork-images/original/${photo}`;
]; }
function openCtaEmail() {
window.location.href = "mailto:lapikud@lapikud.ee";
}
function openCtaContact() {
window.location.href = "/contact";
}
</script> </script>
<div class="safe-area-navbar"> <div class="safe-area-navbar">
<!-- Hero Section -->
<Section background="orange"> <!-- Hero Section -->
<Center> <Section
<div class="text-center max-w-4xl"> padding="none"
<h1 class="text-5xl font-bold mb-6">{$text["hero"]?.title || "Ettevõttele"}</h1> bg="bg-gray-900"
<p class="text-2xl leading-relaxed"> class="overflow-hidden"
{$text["hero"]?.description || "Aitame sinu ideed ellu viia! Meie kogenud tudengid on valmis teie projekte realiseerima."} contentClass="relative z-10 py-[clamp(3.5rem,8vw,5rem)]"
>
<div class="relative z-10">
<h1 class="max-w-[20ch] text-[clamp(2.6rem,5.5vw,4.8rem)] leading-none font-bold tracking-[-0.03em] text-white">
{$text["intro"]?.prefix || "Meie tehtud "}
<br />
<span class="text-orange-500">{$text["intro"]?.emphasis || "tööd."}</span>
</h1>
<p class="mt-5 max-w-105 text-[0.95rem] leading-[1.7] text-white/45">
{$text["intro"]?.subtitle || "Valik projekte, mida meie liikmed on teostanud, veebilehtedest mobiilirakendusteni."}
</p> </p>
</div> </div>
</Center> </Section>
</Section>
<!-- Services Section --> <!-- CTA Section -->
<Section> <Section
<div class="text-center mb-12"> padding="none"
<h2 class="text-4xl font-bold mb-4">{$text["services"]?.title || "Mida me pakume?"}</h2> bg="bg-orange-500"
<p class="text-xl text-gray-600">{$text["services"]?.subtitle || "Laia valik IT-teenuseid teie ärivajaduste täitmiseks"}</p> contentClass="py-[clamp(2.3rem,5vw,3.25rem)]"
</div> >
<div class="flex flex-col items-start justify-between gap-6 lg:flex-row lg:items-center lg:gap-10">
<Grid columns={2} gap="gap-5"> <div>
{#each services as service} <h2 class="mb-2 text-[clamp(1.4rem,2.5vw,2rem)] leading-[1.1] font-bold tracking-[-0.02em] text-gray-900">
<Card variant="glass"> {$text["cta"]?.title || "Alustame koostööd?"}
<div class="feature-icon mb-4" style="color: var(--orange)"> </h2>
<svelte:component this={service.icon} size={48} strokeWidth={1.5} /> <p class="max-w-95 text-[0.88rem] leading-[1.6] text-gray-900/70">
</div> {$text["cta"]?.description || "Võta ühendust ja arutame, kuidas saame sinu ideed ellu viia!"}
<h3 class="text-2xl font-bold mb-3">{service.title}</h3> </p>
<p class="text-gray-600">{service.description}</p>
</Card>
{/each}
</Grid>
</Section>
<!-- Why Choose Us -->
<Section background="neutral">
<div class="text-center mb-12">
<h2 class="text-4xl font-bold mb-4">{$text["whyUs"]?.title || "Miks meiega koostööd teha?"}</h2>
</div>
<Grid columns={3} gap="gap-5">
{#each whyUs as item}
<Card variant="glass">
<div class="feature-icon mb-4" style="color: var(--orange)">
<svelte:component this={item.icon} size={48} strokeWidth={1.5} />
</div>
<h3 class="text-2xl font-bold mb-3">{item.title}</h3>
<p class="text-gray-600">{item.description}</p>
</Card>
{/each}
</Grid>
</Section>
<!-- Process Section -->
<Section>
<Grid gap="gap-5">
<Card variant="glass">
<h2 class="text-4xl font-bold mb-6">{$text["process"]?.title || "Kuidas töötame?"}</h2>
<div class="space-y-6">
{#each $text["process"]?.steps || [] as step, index}
<div class="flex items-start gap-4">
<div class="text-3xl font-bold" style="color: var(--orange)">{index + 1}.</div>
<div>
<strong class="text-lg">{step.title}</strong><br/>
{step.description}
</div>
</div>
{/each}
</div> </div>
</Card>
<Card variant="glass"> <div class="flex flex-wrap items-center gap-3">
<h2 class="text-4xl font-bold mb-6">{$text["fit"]?.title || "Millal meie sobime?"}</h2> <Button
<div class="space-y-4 text-lg"> onClick={openCtaEmail}
{#each $text["fit"]?.items || [] as item} class="gap-2 rounded-none! border-gray-900! bg-gray-900 px-5.5 py-3 text-[0.83rem] font-semibold text-white transition-colors hover:border-gray-800 hover:bg-gray-800"
<p>
<strong>{item.title}</strong> {item.description}
</p>
{/each}
</div>
</Card>
</Grid>
</Section>
<!-- Portfolio Section -->
<Section>
<div class="text-center mb-12">
<h2 class="text-4xl font-bold mb-4">{$text["portfolio"]?.title || "Meie tehtud tööd"}</h2>
<p class="text-xl text-gray-600">{$text["portfolio"]?.subtitle || "Vaata, mida oleme varem loonud"}</p>
</div>
<Grid columns={3} gap="gap-5">
{#each projects as project}
<Card variant="animated-neutral">
{#if project.photo}
<div class="mb-4 overflow-hidden rounded-lg">
<img
src={`/assets/ourwork-images/optimised/${project.photo}`}
alt={getLangText(project, 'title', $currentLang)}
class="w-full h-48 object-cover hover:scale-105 transition-transform duration-300"
on:error={(e) => {
e.target.src = '/assets/ourwork-images/original/' + project.photo;
}}
/>
</div>
{/if}
<h3 class="text-xl font-bold mb-2">{getLangText(project, 'title', $currentLang)}</h3>
{#if project.description}
<p class="text-gray-600 text-sm mb-4">{getLangText(project, 'description', $currentLang)}</p>
{/if}
{#if project.url}
<a
href={project.url}
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center gap-2 text-orange-500 hover:text-orange-600 font-semibold"
>
{$text["portfolio"]?.projectLink || "Vaata projekti"} <ExternalLink size={16} />
</a>
{/if}
</Card>
{/each}
</Grid>
</Section>
<!-- CTA Section -->
<Section background="orange">
<Center>
<div class="text-center max-w-4xl text-white">
<h2 class="text-4xl font-bold mb-6">{$text["cta"]?.title || "Alustame koostööd?"}</h2>
<p class="text-xl mb-8">
{$text["cta"]?.description || "Võta ühendust ja arutame, kuidas saame sinu ideed ellu viia!"}
</p>
<div class="flex flex-wrap gap-4 justify-center">
<a
href="mailto:lapikud@lapikud.ee"
class="inline-flex items-center gap-2 px-8 py-3 bg-white text-orange-500 hover:bg-gray-100 font-semibold rounded-lg transition-colors"
> >
{$text["cta"]?.emailButton || "Saada e-kiri"} <ArrowRight size={20} /> {$text["cta"]?.emailButton || "Saada e-kiri"} <span aria-hidden="true">&rarr;</span>
</a> </Button>
<a <Button
href="/contact" onClick={openCtaContact}
class="inline-flex items-center gap-2 px-8 py-3 bg-transparent border-2 border-white hover:bg-white hover:text-orange-500 font-semibold rounded-lg transition-colors" class="rounded-none! border-gray-900/35! bg-transparent px-5.5 py-3 text-[0.83rem] font-semibold text-gray-900 transition-colors hover:border-gray-900 hover:bg-gray-900/6"
> >
{$text["cta"]?.contactButton || "Kontaktandmed"} {$text["cta"]?.contactButton || "Kontaktandmed"}
</a> </Button>
</div> </div>
</div> </div>
</Center> </Section>
</Section>
<Section padding="large">
<div class="mb-12">
<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>
<p class="mt-4 max-w-[62ch] leading-[1.65] text-gray-900">
{$text["portfolio"]?.subtitle || "Igal projektil on oma lugu. Siin on valik töödest, mida meie liikmed on aastate jooksul ellu viinud."}
</p>
</div>
{#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">
<div class="min-h-[220px] overflow-hidden bg-gray-100/70 p-2 md:min-h-[280px]">
{#if featuredProject.photo}
<img
src={projectImage(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)]"
on:error={(event) => handleImageError(event, featuredProject.photo)}
/>
{:else}
<div class="grid h-full min-h-[180px] w-full place-items-center text-[0.85rem] text-gray-900">{$text["portfolio"]?.placeholder || "Pilt puudub"}</div>
{/if}
</div>
<div class="flex flex-col justify-center gap-2 p-[clamp(1.5rem,3vw,2.5rem)]">
<h2 class="m-0 text-[clamp(1.45rem,2.7vw,2rem)] leading-[1.2] tracking-[-0.02em]">{projectTitle(featuredProject)}</h2>
{#if projectDescription(featuredProject)}
<p class="m-0 text-[0.9rem] leading-[1.6] text-gray-900">{projectDescription(featuredProject)}</p>
{/if}
{#if featuredProject.url}
<a
href={featuredProject.url}
target="_blank"
rel="noopener noreferrer"
class="mt-0.5 inline-flex w-fit items-center gap-1.5 font-semibold text-orange-500 hover:underline"
>
{$text["portfolio"]?.projectLink || "Vaata projekti"}
<ExternalLink size={16} />
</a>
{/if}
</div>
</Card>
{/if}
<div class="ourwork-grid">
{#each regularProjects as project}
<Card variant="default" class="ourwork-grid-card rounded-none! border-0! bg-white! p-0!">
<div class="aspect-16/10 overflow-hidden bg-gray-100/70 p-2">
{#if project.photo}
<img
src={projectImage(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)]"
on:error={(event) => handleImageError(event, project.photo)}
/>
{:else}
<div class="grid h-full min-h-[180px] w-full place-items-center text-[0.85rem] text-gray-900">{$text["portfolio"]?.placeholder || "Pilt puudub"}</div>
{/if}
</div>
<div class="ourwork-card-content flex h-full flex-1 flex-col gap-2 p-5">
<h3 class="ourwork-card-title m-0 text-base leading-[1.2] tracking-[-0.02em]">{projectTitle(project)}</h3>
{#if projectDescription(project)}
<p class="ourwork-card-description m-0 text-[0.9rem] leading-[1.6] text-gray-900">{projectDescription(project)}</p>
{:else}
<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 project.url}
<a
href={project.url}
target="_blank"
rel="noopener noreferrer"
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"}
<ExternalLink size={16} />
</a>
{/if}
</div>
</Card>
{/each}
</div>
</Section>
</div> </div>
<style> <style>
.feature-icon { .ourwork-grid {
display: flex; display: flex;
align-items: center; flex-wrap: wrap;
gap: 1px;
justify-content: center; justify-content: center;
width: 80px; }
height: 80px;
background: rgba(255, 127, 0, 0.1); .ourwork-grid :global(.ourwork-grid-card) {
border-radius: 50%; display: flex;
margin: 0 auto; flex-direction: column;
height: 100%;
min-width: 0;
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) {
.ourwork-grid :global(.ourwork-grid-card) {
width: calc((100% - 1px) / 2);
}
}
@media (min-width: 1200px) {
.ourwork-grid :global(.ourwork-grid-card) {
width: calc((100% - 2px) / 3);
}
} }
</style> </style>

View File

@@ -30,6 +30,10 @@
document.getElementById("liitu")?.scrollIntoView({ behavior: "smooth", block: "start" }); document.getElementById("liitu")?.scrollIntoView({ behavior: "smooth", block: "start" });
}; };
const scrollToUnderHero = () => {
document.getElementById("tiimid")?.scrollIntoView({ behavior: "smooth", block: "start" });
};
const openJoinForm = () => { const openJoinForm = () => {
window.open(joinFormUrl, "_blank", "noopener,noreferrer"); window.open(joinFormUrl, "_blank", "noopener,noreferrer");
}; };
@@ -62,7 +66,7 @@
<Button onClick={scrollToJoin} class="border-transparent bg-orange-500 px-8 py-3 text-sm font-semibold text-white hover:opacity-90"> <Button onClick={scrollToJoin} class="border-transparent bg-orange-500 px-8 py-3 text-sm font-semibold text-white hover:opacity-90">
{$text["hero"]?.cta || ""} {$text["hero"]?.cta || ""}
</Button> </Button>
<span class="text-sm text-white/40">{$text["hero"]?.aside || ""}</span> <a href="#tiimid" on:click|preventDefault={scrollToUnderHero} class="text-sm text-white/40">{$text["hero"]?.aside || ""}</a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,21 @@
<script>
import {
Section,
Grid,
Center,
} from "$components";
import { onDestroy } from "svelte";
import { createPageTextStore } from "$lib";
const text = createPageTextStore("Workshops");
onDestroy(() => {
text.destroy();
});
</script>
<div class="safe-area-navbar">
<Section>
<p>In development...</p>
</Section>
</div>

View File

@@ -11,6 +11,7 @@ import Contact from './Contact.svelte'
import Managment from './Managment.svelte' import Managment from './Managment.svelte'
import Striim from './Striim.svelte' import Striim from './Striim.svelte'
import Calendar from './Calendar.svelte' import Calendar from './Calendar.svelte'
import Workshops from './Workshops.svelte';
// Route mapping for language switching // Route mapping for language switching
export const routeMap = { export const routeMap = {
@@ -104,8 +105,8 @@ export const routes = {
'/contact': Contact, '/contact': Contact,
'/juhatus': Managment, '/juhatus': Managment,
'/management': Managment, '/management': Managment,
'/koolitused': Home, // TODO '/koolitused': Workshops,
'/workshops': Home, // TODO '/workshops': Workshops,
'/striim': Striim, '/striim': Striim,
'/kalender': Calendar, '/kalender': Calendar,
'/calendar': Calendar, '/calendar': Calendar,