about us section ready

This commit is contained in:
Henri
2026-04-05 22:54:23 +03:00
parent eb459ed4b6
commit 884281bd58
18 changed files with 380 additions and 139 deletions

View File

@@ -51,7 +51,7 @@
--fs-md: 1rem;
--fs-lg: 1.125rem;
--fs-xl: 1.5rem;
--line-height: 1.45;
--line-height: 1.6;
}
/* Global box sizing & accessible defaults */
@@ -92,19 +92,7 @@ button,
input[type="button"],
input[type="submit"] {
font: inherit;
border: 1px solid var(--color-border); /* TODO: fix css magic (we need the border, but the variable doesnt exist, but you cant remove it either) */
padding: 0.5em 0.9em;
border-radius: var(--radius-sm);
cursor: pointer;
transition: box-shadow 120ms ease, transform 120ms ease,
border-color 120ms ease;
}
button:active {
transform: translateY(1px);
}
button:focus {
outline: 3px solid color-mix(in srgb, var(--color-primary) 14%, transparent); /* TODO: change same magic here */
outline-offset: 2px;
}
/* Utility: visually hidden (accessible labels) */

View File

@@ -1,10 +1,32 @@
<script>
export let onClick = () => {};
let {
onClick = () => {},
class: className = "",
children,
} = $props();
</script>
<button
on:click={onClick}
class="btn border-[1.5px] px-5 py-2.5 font-medium cursor-pointer flex items-center gap-2 whitespace-nowrap {$$props.class ?? ''}"
onclick={onClick}
data-animation
class="btn flex p-2.5 {className}"
>
<slot />
{@render children?.()}
</button>
<style>
.btn {
border-width: 2px;
border-style: solid;
border-radius: 0.2rem;
cursor: pointer;
align-items: center;
white-space: nowrap;
transition: color 200ms ease, background-color 200ms ease,
border-color 200ms ease, transform 120ms ease, box-shadow 200ms ease;
}
.btn:active {
transform: translateY(1px);
}
</style>

View File

@@ -1,11 +1,14 @@
<script>
import Button from "./Button.svelte";
export let name = "";
export let buttonClass = "";
export let panelClassName = "";
let {
name = "",
buttonClass = "",
panelClass = "",
children,
} = $props();
let isOpen = false;
let isOpen = $state(false);
const toggle = () => (isOpen = !isOpen);
const close = () => (isOpen = false);
@@ -20,7 +23,7 @@
}
</script>
<div class="relative inline-block" on:focusout={handleFocusOut}>
<div class="relative inline-block" onfocusout={handleFocusOut}>
<Button onClick={toggle} class={`${buttonClass} gap-0`}>
{name}
<svg
@@ -41,11 +44,11 @@
</Button>
<div
class="{panelClassName} 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"}
>
<div>
<slot />
{@render children?.()}
</div>
</div>
</div>

View File

@@ -12,7 +12,6 @@ hover effects, size variants, and object-fit options. Includes support for WebP
export let rel = "noopener noreferrer";
export let objectFit = "contain"; // 'contain' | 'cover' | 'fill' | 'none' | 'scale-down'
export let hover = false;
export let className = "";
// optional srcset for responsive images (w descriptors means width-based, x descriptors means pixel density-based)
// e.g. "image-400.jpg 400w, image-800.jpg 800w"
@@ -41,7 +40,7 @@ hover effects, size variants, and object-fit options. Includes support for WebP
{src}
srcset={srcSet || undefined}
alt={alt}
class="block h-auto max-w-full {objectFitClass} {hoverClasses} {className}"
class="block h-auto max-w-full {objectFitClass} {hoverClasses} {$$props.class ?? ''}"
/>
</picture>
</a>
@@ -54,7 +53,7 @@ hover effects, size variants, and object-fit options. Includes support for WebP
{src}
srcset={srcSet || undefined}
alt={alt}
class="block h-auto max-w-full {objectFitClass} {hoverClasses} {className}"
class="block h-auto max-w-full {objectFitClass} {hoverClasses} {$$props.class ?? ''}"
/>
</picture>
{/if}

View File

@@ -1,5 +1,20 @@
<script>
import { onDestroy } from 'svelte';
import Image from './Image.svelte';
/**
* Images can be either strings or objects with optimization options:
*
* String format (simple):
* images={["image1.jpg", "image2.jpg"]}
*
* Object format (multiple image options):
* images={[
* { src: "image1.jpg", webpSrc: "image1.webp", alt: "Description" },
* { src: "image2.jpg", webpSrc: "image2.webp", alt: "Description" }
* ]}
*
*/
export let images = [];
export let width = '100%';
@@ -16,6 +31,15 @@
let current = startIndex;
let timer;
$: currentImage = images[current];
$: isObjectImage = typeof currentImage === 'object' && currentImage !== null;
$: imageSrc = typeof currentImage === 'string' ? currentImage : currentImage?.src || '';
$: imageAlt = typeof currentImage === 'string' ? '' : currentImage?.alt || '';
$: imageWebpSrc = isObjectImage ? currentImage?.webpSrc || '' : '';
$: imageSrcSet = isObjectImage ? currentImage?.srcSet || '' : '';
$: imageWebpSrcSet = isObjectImage ? currentImage?.webpSrcSet || '' : '';
$: imageClass = isObjectImage ? currentImage?.class || '' : '';
const next = () => {
if (current < images.length - 1) {
current += 1;
@@ -51,10 +75,14 @@
aria-live="polite"
>
{#if images.length}
<img
src={typeof images[current] === 'string' ? images[current] : images[current].src}
alt={typeof images[current] === 'string' ? '' : images[current].alt || ''}
class="slide"
<Image
src={imageSrc}
alt={imageAlt}
webpSrc={imageWebpSrc}
srcSet={imageSrcSet}
webpSrcSet={imageWebpSrcSet}
objectFit="cover"
class={`w-full h-full block ${imageClass}`}
/>
{#if interactive && images.length > 1}
@@ -82,13 +110,6 @@
display: block;
}
.slide {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
/* interactive controls */
.prev,
.next {

View File

@@ -4,17 +4,16 @@
<script>
export let type;
export let className = "";
</script>
{#if type === "connector"}
<svg viewBox="0 0 182 66" class={className} fill="none" xmlns="http://www.w3.org/2000/svg">
<svg viewBox="0 0 182 66" class={$$props.class ?? ''} fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 63.5H67.5L102.5 15.5H156" stroke="currentColor" stroke-width="5"/>
<circle cx="166" cy="15.5" r="10" stroke="currentColor" stroke-width="5"/>
</svg>
{:else if type === "mirrorV"}
<svg viewBox="0 0 182 66" class={className} fill="none" xmlns="http://www.w3.org/2000/svg">
<svg viewBox="0 0 182 66" class={$$props.class ?? ''} fill="none" xmlns="http://www.w3.org/2000/svg">
<g transform="scale(1,-1) translate(0,-66)">
<path d="M0 63.5H67.5L102.5 15.5H156" stroke="currentColor" stroke-width="5"/>
<circle cx="166" cy="15.5" r="10" stroke="currentColor" stroke-width="5"/>
@@ -22,7 +21,7 @@
</svg>
{:else if type === "mirrorH"}
<svg viewBox="0 0 182 66" class={className} fill="none" xmlns="http://www.w3.org/2000/svg">
<svg viewBox="0 0 182 66" class={$$props.class ?? ''} fill="none" xmlns="http://www.w3.org/2000/svg">
<g transform="scale(-1,1) translate(-182,0)">
<path d="M0 63.5H67.5L102.5 15.5H156" stroke="currentColor" stroke-width="5"/>
<circle cx="166" cy="15.5" r="10" stroke="currentColor" stroke-width="5"/>
@@ -30,7 +29,7 @@
</svg>
{:else if type === "mirrorVH"}
<svg viewBox="0 0 182 66" class={className} fill="none" xmlns="http://www.w3.org/2000/svg">
<svg viewBox="0 0 182 66" class={$$props.class ?? ''} fill="none" xmlns="http://www.w3.org/2000/svg">
<g transform="scale(-1,-1) translate(-182,-66)">
<path d="M0 63.5H67.5L102.5 15.5H156" stroke="currentColor" stroke-width="5"/>
<circle cx="166" cy="15.5" r="10" stroke="currentColor" stroke-width="5"/>
@@ -38,14 +37,14 @@
</svg>
{:else if type === "branch"}
<svg viewBox="0 0 75 74" class={className} fill="none" xmlns="http://www.w3.org/2000/svg">
<svg viewBox="0 0 75 74" class={$$props.class ?? ''} fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 31.4784H46L68 1.47842M45.5 30.9784L66.5 63.9784"
stroke="currentColor"
stroke-width="5"/>
</svg>
{:else if type === "branchH"}
<svg viewBox="0 0 75 74" class={className} fill="none" xmlns="http://www.w3.org/2000/svg">
<svg viewBox="0 0 75 74" class={$$props.class ?? ''} fill="none" xmlns="http://www.w3.org/2000/svg">
<g transform="scale(-1,1) translate(-75,0)">
<path d="M0 31.4784H46L68 1.47842M45.5 30.9784L66.5 63.9784"
stroke="currentColor"
@@ -54,19 +53,19 @@
</svg>
{:else if type === "instagram"}
<svg class="w-8 h-8 {className}" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<svg class="w-8 h-8 {$$props.class ?? ''}" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/>
</svg>
{:else if type === "facebook"}
<svg class="w-8 h-8 {className}" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<svg class="w-8 h-8 {$$props.class ?? ''}" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/>
</svg>
{:else if type === "github"}
<svg class="w-8 h-8 {className}" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<svg class="w-8 h-8 {$$props.class ?? ''}" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
</svg>

View File

@@ -1,7 +1,10 @@
<script>
export let href = "";
export let variant = "default"; // 'default' | 'animated' | 'animated-neutral' | 'glass' | 'blur'
export let className = "";
let {
href = "",
variant = "default", // 'default' | 'animated' | 'animated-neutral' | 'glass' | 'blur'
class: className = "",
children,
} = $props();
const variantClasses = {
default: "card-default",
@@ -14,11 +17,11 @@
{#if href}
<a {href} class={`card ${variantClasses[variant]} ${className}`}>
<slot />
{@render children?.()}
</a>
{:else}
<div class={`card ${variantClasses[variant]} ${className}`}>
<slot />
{@render children?.()}
</div>
{/if}

View File

@@ -1,7 +1,10 @@
<script>
export let dir = "row"; // 'row' | 'col' (default: 'row')
export let gap = "gap-4";
export let className = "";
let {
dir = "row", // 'row' | 'col' (default: 'row')
gap = "gap-4",
class: className = "",
children,
} = $props();
</script>
<div
@@ -12,5 +15,5 @@
" " +
className}
>
<slot />
{@render children?.()}
</div>

View File

@@ -1,16 +1,19 @@
<!--
A responsive container that centers content and optionally
removes the max-width when `fluid` is true. Use `className` to
removes the max-width when `fluid` is true. Use the `class`
add additional CSS classes to the root element. Content is
projected via the default slot.
-->
<script>
export let maxWidth = false; // true removes max-width
export let center = true; // false prevents centering and removes horizontal padding
export let className = "";
let {
maxWidth = false, // true removes max-width
center = true, // false prevents centering and removes horizontal padding
class: className = "",
children,
} = $props();
</script>
<div class="w-full {center ? 'px-[var(--page-padding-inline)]' : ''} {maxWidth ? '' : 'max-w-[var(--page-max-width)]'} {center ? 'mx-auto' : ''} {className}">
<slot />
<div class="w-full {center ? 'px-(--page-padding-inline)' : ''} {maxWidth ? '' : 'max-w-(--page-max-width)'} {center ? 'mx-auto' : ''} {className}">
{@render children?.()}
</div>

View File

@@ -1,14 +1,19 @@
<script>
export let min = "220px"; // min column width (used when columns not set)
export let columns = null; // fixed number of columns for desktop
export let largeColumns = null; // fixed number of columns for large desktop
export let mobileColumns = null; // fixed number of columns for mobile
export let gap = "gap-3";
export let className = "";
let {
min = "220px", // min column width (used when columns not set)
columns = null, // fixed number of columns for desktop
largeColumns = null, // fixed number of columns for large desktop
mobileColumns = null, // fixed number of columns for mobile
gap = "gap-3",
class: className = "",
children,
} = $props();
$: desktopColumns = columns ? `repeat(${columns}, 1fr)` : '1fr';
$: largeDesktopColumns = largeColumns ? `repeat(${largeColumns}, 1fr)` : desktopColumns;
$: mobileCols = mobileColumns ? `repeat(${mobileColumns}, 1fr)` : '1fr';
const desktopColumns = $derived(columns ? `repeat(${columns}, 1fr)` : "1fr");
const largeDesktopColumns = $derived(
largeColumns ? `repeat(${largeColumns}, 1fr)` : desktopColumns
);
const mobileCols = $derived(mobileColumns ? `repeat(${mobileColumns}, 1fr)` : "1fr");
</script>
<div
@@ -21,7 +26,7 @@
grid-template-columns: var(--mobile-columns);
"
>
<slot />
{@render children?.()}
</div>
<style>

View File

@@ -5,8 +5,8 @@
padding = "normal",
fullWidth = false,
id = "",
className = "",
contentClassName = "",
class: className = "",
contentClass = "",
children
} = $props();
@@ -24,7 +24,7 @@
class="relative w-full {bg} {className}"
style={background ? `background: ${background};` : undefined}
>
<div class="w-full {fullWidth ? '' : 'max-w-(--page-max-width)'} mx-auto px-(--page-padding-inline) {paddingClasses[padding]} {contentClassName}">
<div class="w-full {fullWidth ? '' : 'max-w-(--page-max-width)'} mx-auto px-(--page-padding-inline) {paddingClasses[padding]} {contentClass}">
{@render children?.()}
</div>
</section>

View File

@@ -3,11 +3,14 @@ A simple stack/column layout that stacks children vertically.
-->
<script>
export let gap = "gap-3";
export let align = "stretch";
export let className = "";
let {
gap = "gap-3",
align = "stretch",
class: className = "",
children
} = $props();
</script>
<div class="flex flex-col {className} {gap}" style="align-items: {align};">
<slot />
{@render children?.()}
</div>

View File

@@ -9,7 +9,7 @@ import {
</script>
<Section bg="bg-gray-900" className="text-white">
<Section bg="bg-gray-900" class="text-white">
<Grid>
<div>
<h3 class="text-3xl font-light pb-4">MTÜ Lapikud</h3>

View File

@@ -103,16 +103,35 @@
.menu-closing {
animation: collapseToButton 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
.mobile-menu-overlay {
height: 100vh;
max-height: 100vh;
}
@supports (height: 100svh) {
.mobile-menu-overlay {
height: 100svh;
max-height: 100svh;
}
}
@supports (height: 100dvh) {
.mobile-menu-overlay {
height: 100dvh;
max-height: 100dvh;
}
}
</style>
<header class="fixed inset-x-0 top-0 z-50 text-white">
<Container maxWidth={true} center={false} className="py-0">
<Container maxWidth={true} center={false} class="py-0">
{#if $text && Object.keys($text).length > 0}
<div class="flex items-center w-full relative min-h-10">
<!-- Logo -->
{#if currentPath !== "/"}
<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">
<Button onClick={() => handleNavigation("/")}>
<Button onClick={() => handleNavigation("/")} class="border-transparent">
<img src="assets/LapLogo_black_white.png" alt="Lapikud Logo" class="h-14" />
</Button>
</div>
@@ -123,47 +142,47 @@
<nav class="z-10 hidden md:flex gap-1 justify-end text-lg">
<Dropdown
name={$text.about || 'Meist'}
buttonClass="rounded-[5px] hover:text-white"
panelClassName="bg-white text-black"
buttonClass="rounded-[5px] hover:text-white border-transparent"
panelClass="bg-white text-black"
>
<Button class="rounded-[5px] bg-transparent hover:text-orange-500" onClick={() => navigate("/lapikutest")}
<Button class="rounded-[5px] bg-transparent hover:text-orange-500 border-transparent" onClick={() => navigate("/lapikutest")}
>{$text.aboutPages.info}</Button
>
<Button class="rounded-[5px] bg-transparent hover:text-orange-500" onClick={() => navigate("/tudengile")}
<Button class="rounded-[5px] bg-transparent hover:text-orange-500 border-transparent" onClick={() => navigate("/tudengile")}
><Bot />{$text.aboutPages.join}</Button
>
<Button class="rounded-[5px] bg-transparent hover:text-orange-500" onClick={() => navigate("/mentorid")}
<Button class="rounded-[5px] bg-transparent hover:text-orange-500 border-transparent" onClick={() => navigate("/mentorid")}
><HandHeart />{$text.aboutPages.mentors}</Button
>
<Button class="rounded-[5px] bg-transparent hover:text-orange-500" onClick={() => navigate("/juhatus")}
<Button class="rounded-[5px] bg-transparent hover:text-orange-500 border-transparent" onClick={() => navigate("/juhatus")}
><Lectern />{$text.aboutPages.board}</Button
>
</Dropdown>
<Dropdown
name={$text.events}
buttonClass="rounded-[5px] hover:text-white"
panelClassName="bg-white text-black"
buttonClass="rounded-[5px] hover:text-white border-transparent"
panelClass="bg-white text-black"
>
<Button class="rounded-[5px] bg-transparent hover:text-orange-500" onClick={() => navigate("/koolitused")}
<Button class="rounded-[5px] bg-transparent hover:text-orange-500 border-transparent" onClick={() => navigate("/koolitused")}
><Presentation />{$text.eventsPages.workshops}</Button
>
<Button class="rounded-[5px] bg-transparent hover:text-orange-500" onClick={() => navigate("https://asikarikas.ee/", { external: true })}
<Button class="rounded-[5px] bg-transparent hover:text-orange-500 border-transparent" onClick={() => navigate("https://asikarikas.ee/", { external: true })}
><Trophy />ASI Karikas</Button
>
<Button class="rounded-[5px] bg-transparent hover:text-orange-500" onClick={() => navigate("https://remondikohvik.lapikud.ee/", { external: true })}
<Button class="rounded-[5px] bg-transparent hover:text-orange-500 border-transparent" onClick={() => navigate("https://remondikohvik.lapikud.ee/", { external: true })}
><Coffee />{$text.eventsPages.repair}</Button
>
</Dropdown>
<Button class="rounded-[5px] hover:text-white" onClick={() => navigate("/kontakt")}
<Button class="rounded-[5px] hover:text-white border-transparent" onClick={() => navigate("/kontakt")}
>{$text.contact}
</Button>
<Button class="rounded-[5px] hover:text-white" onClick={() => navigate("/helpdesk")}
<Button class="rounded-[5px] hover:text-white border-transparent" onClick={() => navigate("/helpdesk")}
>{$text.helpdesk}
</Button>
<!-- Language Switcher -->
<Button
class="rounded-[5px] px-3 py-1 text-sm ml-4 hover:text-white"
class="rounded-[5px] px-3 py-1 text-sm ml-4 hover:text-white border-transparent"
onClick={() => switchLanguageRoute($currentLang === 'est' ? 'en' : 'est')}
>
{$currentLang === 'est' ? 'EN' : 'EST'}
@@ -174,8 +193,8 @@
{#if !mobileMenuOpen}
<Button
onClick={toggleMobileMenu}
class="md:hidden p-2 text-white transition-colors bg-transparent absolute right-0 hover:text-white"
aria-label="Toggle menu"
class="mobile-only p-2 text-white transition-colors bg-transparent absolute right-0 hover:text-white border-transparent"
aria-label="Toggle navigation menu"
>
<Menu size={32} />
</Button>
@@ -189,15 +208,16 @@
<!-- Full Screen Mobile Menu -->
{#if mobileMenuOpen}
<div
class="fixed inset-0 z-100 bg-black/95 md:hidden overflow-y-auto"
class="mobile-menu-overlay fixed inset-0 z-100 bg-black/95 mobile-only overflow-y-auto"
data-animation
class:menu-opening={!isClosing}
class:menu-closing={isClosing}
>
<Stack className="min-h-full">
<Stack class="min-h-full">
<div class="absolute top-6 right-4">
<Button
onClick={closeMobileMenu}
class="ml-auto p-2 transition-colors flex bg-transparent hover:text-orange-500"
class="ml-auto p-2 transition-colors flex bg-transparent hover:text-orange-500 border-transparent"
aria-label="Close menu"
>
<X size={32} color="white" />
@@ -205,34 +225,34 @@
</div>
<!-- Menu Content -->
<Stack gap="gap-5" className="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">
<!-- About Section -->
<Stack gap="gap-3">
<h3 class="text-2xl font-bold text-orange-500">{$text.about}</h3>
<Stack gap="gap-2" className="pl-4">
<Stack gap="gap-2" class="pl-4">
<Button
onClick={() => handleNavigation("/lapikutest")}
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500"
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500 border-transparent"
>
{$text.aboutPages.info}
</Button>
<Button
onClick={() => handleNavigation("/tudengile")}
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500"
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500 border-transparent"
>
<Bot size={20} />
{$text.aboutPages.join}
</Button>
<Button
onClick={() => handleNavigation("/mentorid")}
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500"
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500 border-transparent"
>
<HandHeart size={20} />
{$text.aboutPages.mentors}
</Button>
<Button
onClick={() => handleNavigation("/juhatus")}
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500"
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500 border-transparent"
>
<Lectern size={20} />
{$text.aboutPages.board}
@@ -243,24 +263,24 @@
<!-- Events Section -->
<Stack gap="gap-3" >
<h3 class="text-2xl font-bold text-orange-500">{$text.events}</h3>
<Stack gap="gap-2" className="pl-4">
<Stack gap="gap-2" class="pl-4">
<Button
onClick={() => handleNavigation("/koolitused")}
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500"
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500 border-transparent"
>
<Presentation size={20} />
{$text.eventsPages.workshops}
</Button>
<Button
onClick={() => handleNavigation("https://asikarikas.ee/", { external: true })}
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500"
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500 border-transparent"
>
<Trophy size={20} />
ASI Karikas
</Button>
<Button
onClick={() => handleNavigation("https://remondikohvik.lapikud.ee/", { external: true })}
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500"
class="text-left transition-colors flex items-center gap-2 bg-transparent hover:text-orange-500 border-transparent"
>
<Coffee size={20} />
{$text.eventsPages.repair}
@@ -272,13 +292,13 @@
<Stack gap="gap-3">
<Button
onClick={() => handleNavigation("/kontakt")}
class="text-left text-2xl font-semibold transition-colors bg-transparent hover:text-orange-500"
class="text-left text-2xl font-semibold transition-colors bg-transparent hover:text-orange-500 border-transparent"
>
{$text.contact}
</Button>
<Button
onClick={() => handleNavigation("/helpdesk")}
class="text-left text-2xl font-semibold transition-colors bg-transparent hover:text-orange-500"
class="text-left text-2xl font-semibold transition-colors bg-transparent hover:text-orange-500 border-transparent"
>
{$text.helpdesk}
</Button>
@@ -286,7 +306,7 @@
<!-- Language Switcher -->
<Stack gap="gap-3">
<Button
class="w-full rounded-lg py-3 text-lg bg-orange-500 text-black"
class="w-full rounded-lg py-3 text-lg bg-orange-500 text-black border-transparent"
onClick={() => handleLanguageSwitch($currentLang === 'est' ? 'en' : 'est')}
>
{$currentLang === 'est' ? 'English' : 'Eesti'}

View File

@@ -1 +1,9 @@
{}
{
"homeAbout": {
"title": "About us",
"description": "Our main goal is to create professional added value for TalTech IT students. We involve students in practical solutions where ideas can be implemented in real life and technical skills can be used in meaningful ways. Our projects often grow into useful and exciting thesis topics with clear practical value.",
"moreInfo": "More info",
"contact": "Contact",
"imageAlt": "Lapikud students working on a project"
}
}

View File

@@ -1 +1,9 @@
{}
{
"homeAbout": {
"title": "Meist",
"description": "Meie põhieesmärgiks on Tallinna Tehnikaülikooli IT tudengitele erialase lisandväärtuse loomine. Kaasame tudengeid praktilistesse lahendustesse, kus saab ideid reaalselt ellu viia ja oma oskusi päriselt kasutada. Meie projektidest kasvavad välja huvitavad ja tarvilikud lõputööd, millel on selge praktiline väärtus.",
"moreInfo": "Rohkem infot",
"contact": "Kontakt",
"imageAlt": "Lapikute tudengid projekti kallal"
}
}

View File

@@ -11,7 +11,7 @@
<div bind:this={sectionElement}>
<Section >
<Center dir="col" className="w-full">
<Center dir="col" class="w-full">
<div class="w-full max-w-4xl">
<iframe
style="border: 0;"

View File

@@ -1,17 +1,31 @@
<script>
import {Section, Stack, Grid, Center, Image, Svg, Button} from "$components";
import { navigate } from "$lib/router/router.js";
import {Section, Stack, Grid, Center, Image, Svg, Button} from "$components";
import { navigate } from "$lib/router/router.js";
import { text, currentLang } from "$lib";
import { onMount } from "svelte";
import yaml from 'js-yaml';
import ArrowRight from "lucide-svelte/icons/arrow-right";
// Partners data
let partners = [];
onMount(async () => {
const response = await fetch('/_data/partners.yml');
const yamlText = await response.text();
partners = yaml.load(yamlText);
});
</script>
<!-- Hero Section -->
<Section className="relative min-h-screen overflow-hidden" padding="none" bg="bg-gray-900" id="hero">
<Section class="relative min-h-screen overflow-hidden" padding="none" bg="bg-gray-900" id="hero">
<div class="relative min-h-screen flex items-center">
<div class="absolute inset-0 left-1/2 w-screen -translate-x-1/2" aria-hidden="true">
<Image
src="/assets/hero.jpg"
alt="illustrative hero image"
objectFit="cover"
className="w-full h-full"
class="w-full h-full"
pictureClass="block w-full h-full"
/>
</div>
@@ -21,15 +35,15 @@ import { navigate } from "$lib/router/router.js";
>
<Svg
type="mirrorH"
className="absolute right-0 top-[16%] w-[clamp(8.125rem,14vw,14.375rem)] text-[#E18E38]"
class="absolute right-0 top-[16%] w-[clamp(8.125rem,14vw,14.375rem)] text-[#E18E38]"
/>
<Svg
type="branchH"
className="absolute right-0 top-[52%] -translate-y-1/2 w-[clamp(3.5rem,6vw,5.875rem)] text-[#E18E38]"
class="absolute right-0 top-[52%] -translate-y-1/2 w-[clamp(3.5rem,6vw,5.875rem)] text-[#E18E38]"
/>
<Svg
type="mirrorVH"
className="absolute right-0 bottom-[12%] w-[clamp(8.125rem,14vw,14.375rem)] text-[#E18E38]"
class="absolute right-0 bottom-[12%] w-[clamp(8.125rem,14vw,14.375rem)] text-[#E18E38]"
/>
</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>
@@ -53,63 +67,205 @@ import { navigate } from "$lib/router/router.js";
</div>
</Section>
<Section className="relative overflow-hidden">
<!-- Second Section -->
<Section class="relative overflow-hidden" id="services">
<div class="pointer-events-none absolute inset-x-0 left-1/2 top-15 z-0 w-screen -translate-x-1/2" aria-hidden="true">
<Svg
type="connector"
className="absolute left-0 w-[clamp(8.125rem,14vw,14.375rem)] text-orange-500"
class="absolute left-0 w-[clamp(8.125rem,14vw,14.375rem)] text-orange-500"
/>
<Svg
type="mirrorH"
className="absolute right-0 w-[clamp(8.125rem,14vw,14.375rem)] text-orange-500"
class="absolute right-0 w-[clamp(8.125rem,14vw,14.375rem)] text-orange-500"
/>
</div>
<Grid columns={2} largeColumns={3} mobileColumns={1} className="relative z-10 items-start mt-12 md:mt-20" gap="gap-12 md:gap-16 lg:gap-24">
<Center dir="col" className="w-full max-w-sm justify-start mx-auto">
<Grid columns={2} largeColumns={3} mobileColumns={1} class="relative z-10 items-start mt-12 md:mt-20" gap="gap-12 md:gap-16 lg:gap-24">
<Center dir="col" class="w-full max-w-sm justify-start mx-auto">
<div class="w-[min(72vw,240px)] md:w-[min(26vw,280px)] lg:w-[min(23vw,300px)] aspect-square rounded-full overflow-hidden">
<Image
src="/assets/student-images/image_1.jpg"
webpSrc=""
alt="Tudengile Pilt"
objectFit="cover"
className="w-full h-full rounded-full object-[center_35%]"
class="w-full h-full rounded-full object-[center_35%]"
pictureClass="block w-full h-full"
/>
</div>
<h3 class="w-full min-h-10 text-center text-2xl font-semibold flex items-center justify-center">Tudengile</h3>
<p class="w-full max-w-[26ch] text-center text-base leading-[160%]">Tule arenda oma oskuseid ja saa ägedaid sõpru! Omanda praktilist kogemust reaalsetest projektidest.</p>
<p class="w-full max-w-[26ch] text-center text-base">Tule arenda oma oskuseid ja saa ägedaid sõpru! Omanda praktilist kogemust reaalsetest projektidest.</p>
</Center>
<Center dir="col" className="w-full max-w-sm justify-start mx-auto">
<Center dir="col" class="w-full max-w-sm justify-start mx-auto">
<div class="w-[min(72vw,240px)] md:w-[min(26vw,280px)] lg:w-[min(23vw,300px)] aspect-square rounded-full overflow-hidden">
<Image
src="/assets/helpdesk/helpdesk_bg.jpg"
webpSrc=""
alt="Helpdesk Pilt"
objectFit="cover"
className="w-full h-full rounded-full object-[center_38%]"
class="w-full h-full rounded-full object-[center_38%]"
pictureClass="block w-full h-full"
/>
</div>
<h3 class="w-full min-h-10 text-center text-2xl font-semibold flex items-center justify-center">Helpdesk</h3>
<p class="w-full max-w-[26ch] text-center text-base leading-[160%]">HELPDESK on MTÜ Lapikute poolt pakutav arvutiabiteenus. Teenus on suunatud tudengitele, õppejõududele ning kõikidele huvilistele.</p>
<p class="w-full max-w-[26ch] text-center text-base">HELPDESK on MTÜ Lapikute poolt pakutav arvutiabiteenus. Teenus on suunatud tudengitele, õppejõududele ning kõikidele huvilistele.</p>
</Center>
<Center dir="col" className="w-full max-w-sm justify-start mx-auto md:col-span-2 lg:col-span-1">
<Center dir="col" class="w-full max-w-sm justify-start mx-auto md:col-span-2 lg:col-span-1">
<div class="w-[min(72vw,240px)] md:w-[min(26vw,280px)] lg:w-[min(23vw,300px)] aspect-square rounded-full overflow-hidden">
<Image
src="/assets/asi-karikas-2023-images/miina_harma.jpeg"
webpSrc=""
alt="Ettevõttele Pilt"
objectFit="cover"
className="w-full h-full rounded-full object-[center_25%]"
class="w-full h-full rounded-full object-[center_25%]"
pictureClass="block w-full h-full"
/>
</div>
<h3 class="w-full min-h-10 text-center text-2xl font-semibold flex items-center justify-center">Ettevõttele</h3>
<p class="w-full max-w-[26ch] text-center text-base leading-[160%]">Aitame sinu ideed ellu viia! Meie kogenud tudengid on valmis teie projekte realiseerima.</p>
<p class="w-full max-w-[26ch] text-center text-base">Aitame sinu ideed ellu viia! Meie kogenud tudengid on valmis teie projekte realiseerima.</p>
</Center>
</Grid>
</Section>
<!-- About Us Section -->
<Section
bg="bg-gray-900"
class="relative overflow-hidden text-white"
padding="none"
fullWidth={true}
contentClass="!px-0 !py-0"
>
<Grid
columns={2}
largeColumns={2}
mobileColumns={1}
gap="gap-y-0 md:gap-x-[clamp(5.75rem,9vw,9.75rem)] lg:gap-x-[clamp(6rem,9vw,10.5rem)]"
class=""
>
<div
class="relative flex items-center py-12 md:py-16 lg:py-20 pr-(--page-padding-inline)"
style="padding-left: max(var(--page-padding-inline), calc((100vw - var(--page-max-width)) / 2 + var(--page-padding-inline)));"
>
<div class="flex max-w-[54ch] flex-col justify-center gap-8">
<div class="space-y-5">
<h2 class="text-4xl font-semibold text-orange-500">
{$text["homeAbout"]?.title || "Meist"}
</h2>
<p class="text-base">
{$text["homeAbout"]?.description || "Viga teksti laadimisel. Palun proovi lehte uuesti laadida."}
</p>
</div>
<div class="flex flex-col items-start gap-6">
<Button
class="rounded-md border-3 border-orange-500 bg-transparent px-10 py-2 transition-colors hover:bg-orange-500/10"
onClick={() => navigate($currentLang === "en" ? "/aboutus" : "/lapikutest")}
>
{$text["homeAbout"]?.moreInfo || "Rohkem infot"}
</Button>
<div class="flex items-center gap-4">
<Button
class="rounded-md border-orange-500 bg-orange-500 px-20 py-2 transition-colors hover:border-orange-300 hover:bg-orange-300"
onClick={() => navigate($currentLang === "en" ? "/contact" : "/kontakt")}
>
{$text["homeAbout"]?.contact || "Kontakt"}
</Button>
<ArrowRight class="h-12 w-12 text-orange-500 md:h-14 md:w-14" strokeWidth={2.4} />
</div>
</div>
</div>
</div>
<div class="relative overflow-hidden min-h-80 md:min-h-0 md:h-full md:self-stretch">
<div class="absolute inset-0">
<Image
src="/assets/image.png"
alt={$text["homeAbout"]?.imageAlt || "Lapikud team"}
objectFit="cover"
class="h-full w-full max-w-none!"
pictureClass="block h-full w-full"
/>
</div>
<div class="pointer-events-none absolute inset-0 bg-black/50"></div>
<div class="pointer-events-none absolute bottom-3 inset-x-0 z-10 hidden w-full lg:block" aria-hidden="true">
<div class="ml-auto h-5 w-[84%] bg-orange-500 mb-3"></div>
<div class="ml-auto h-3 w-[96%] bg-orange-500"></div>
</div>
</div>
</Grid>
<div class="pointer-events-none absolute inset-y-0 left-1/2 z-20 hidden -translate-x-1/2 items-center gap-3 md:flex" aria-hidden="true">
<div class="h-[82%] w-3 bg-orange-500/50"></div>
<div class="h-[88%] w-8 bg-orange-500/50"></div>
</div>
</Section>
<!-- Spacer-->
<Section bg="bg-orange-500" class="h-3"/>
<!-- What we do -->
<Section>
</Section>
<!-- Partners Section -->
<Section>
<div class="text-center mb-12">
<h2 class="text-3xl text-orange-500">
Koostööpartnerid
</h2>
</div>
<Center class="flex-wrap">
{#each partners as partner}
{#if partner.url}
<a
href={partner.url}
target="_blank"
rel="noopener noreferrer"
class="flex h-[170px] items-center justify-center p-3 no-underline transition-all duration-300 hover:scale-105"
title={partner.name}
>
{#if partner.image}
<Image
src={`/assets/partners/${partner.image}`}
alt={partner.name}
objectFit="contain"
class="w-auto max-h-[150px] transition-all duration-300"
/>
{:else}
<span class="font-semibold text-center">{partner.name}</span>
{/if}
</a>
{:else}
<div class="flex h-[170px] items-center justify-center p-3 transition-all duration-300">
{#if partner.image}
<Image
src={`/assets/partners/${partner.image}`}
alt={partner.name}
objectFit="contain"
class="w-auto max-h-[150px] transition-all duration-300"
/>
{:else}
<span class="font-semibold text-center">{partner.name}</span>
{/if}
</div>
{/if}
{/each}
</Center>
<Center class="m-10">
<Button
class="rounded-md border-orange-500 bg-transparent px-20 py-3 transition-colors hover:bg-orange-500/10"
onClick={() => navigate("/partners")}
>
Rohkem infot partnerluste kohta
</Button>
</Center>
</Section>
<!-- Spacer-->
<Section bg="bg-orange-500" class="h-3"/>