17 Commits

Author SHA1 Message Date
c9a8c56a4a Merge pull request #120 from Lapikud/workflow
Forgot to change migrations
2026-04-30 17:19:09 +03:00
a0d2b4933e Forgot to change migrations 2026-04-30 17:18:08 +03:00
64e138299a Merge pull request #119 from Lapikud/workflow
Only allow development branch to be built & deploy
2026-04-30 17:07:50 +03:00
f62f9ae299 Only allow development branch to be built & deploy 2026-04-30 17:05:49 +03:00
2a7424efae Merge pull request #118 from Lapikud/workflow
Main.yml fix
2026-04-30 16:58:42 +03:00
84d2012875 main fix 2026-04-30 16:57:14 +03:00
a2e062596c Merge pull request #117 from Lapikud/workflow
Change workflow to allow dev env
2026-04-30 16:56:04 +03:00
426f71e425 Workflow 2026-04-30 16:54:34 +03:00
Renkar
80f79e1784 Merge pull request #113 from Lapikud/workflow-update
Remove .next cache clear in workflow
2026-03-31 19:09:57 +03:00
c76c50a304 Remove .next cache clear in workflow 2026-03-31 19:08:01 +03:00
Renkar
bdab1b71f1 Merge pull request #112 from Lapikud/workflow-update
Ignore drizzle if branch is not main
2026-03-31 17:53:11 +03:00
fc33c899e2 Ignore drizzle if branch is not main 2026-03-31 17:31:43 +03:00
Renkar
cdbecf4b32 Merge pull request #111 from Lapikud/workflow-update
Attempt 2 for workflow
2026-03-31 17:23:43 +03:00
3b5f0dc2e5 Attempt 2 for workflow 2026-03-31 17:21:33 +03:00
Renkar
7570e6f287 Merge pull request #110 from Lapikud/workflow-update
Change workflow to build teaser-2026 page
2026-03-31 17:16:21 +03:00
7d45acc26f Build teaser-2026 into prod 2026-03-31 16:56:45 +03:00
Renkar
9e9d2c774c Merge pull request #109 from Lapikud/development
one more picture
2026-03-31 09:50:28 +03:00
21 changed files with 416 additions and 475 deletions

View File

@@ -2,21 +2,24 @@ name: build
on: on:
workflow_call: workflow_call:
inputs:
ref:
description: Branch or tag to checkout
required: false
default: development
type: string
secrets: secrets:
USER_AUTH: USER_AUTH:
required: true required: true
jobs: jobs:
build: build:
runs-on: prox-1 runs-on: prox-2
steps: steps:
- name: Clear .next cache
env:
SUDO_PASSWORD: ${{ secrets.USER_AUTH }}
run: echo "$SUDO_PASSWORD" | sudo -S rm -rf $GITHUB_WORKSPACE/.next
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
ref: ${{ inputs.ref }}
- name: Setup Bun - name: Setup Bun
uses: oven-sh/setup-bun@v2 uses: oven-sh/setup-bun@v2
@@ -28,13 +31,15 @@ jobs:
- name: Ensure symlink to database before Drizzle migrations - name: Ensure symlink to database before Drizzle migrations
run: | run: |
rm -rf $GITHUB_WORKSPACE/data rm -rf "$GITHUB_WORKSPACE/data"
ln -s ~/data $GITHUB_WORKSPACE/data ln -s /home/github/data "$GITHUB_WORKSPACE/data"
- name: Generate Drizzle schema - name: Generate Drizzle schema
if: ${{ inputs.ref == 'main' }}
run: bun drizzle-kit generate run: bun drizzle-kit generate
- name: Run Drizzle migrations - name: Run Drizzle migrations
if: ${{ inputs.ref == 'main' }}
run: bun drizzle-kit migrate run: bun drizzle-kit migrate
- name: Build project - name: Build project

View File

@@ -8,7 +8,7 @@ on:
jobs: jobs:
deploy: deploy:
runs-on: prox-1 runs-on: prox-2
steps: steps:
- name: Restart NextJS service - name: Restart NextJS service
env: env:

View File

@@ -3,7 +3,8 @@ name: main
on: on:
push: push:
branches: branches:
- main - development
workflow_dispatch:
jobs: jobs:
build: build:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 634 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1024 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -1,9 +1,8 @@
import { vipnagorgialla } from "@/components/Vipnagorgialla"; import { vipnagorgialla } from "@/components/Vipnagorgialla";
import Sponsors from "@/components/Sponsors"; import Sponsors from "@/components/Sponsors";
import HeroSection from "@/components/HeroSection";
import TeaserCarousel from "@/components/TeaserCarousel";
import { Link } from "@/i18n/routing"; import { Link } from "@/i18n/routing";
import { getTranslations, setRequestLocale } from "next-intl/server"; import { getTranslations, setRequestLocale } from "next-intl/server";
import Image from "next/image";
export default async function Home({ export default async function Home({
params, params,
@@ -16,22 +15,58 @@ export default async function Home({
return ( return (
<div> <div>
{/* Hero */} {/* Title */}
<div className="mt-18"> <div className="border-b-3 border-[#1F5673] grid grid-cols-1 md:grid-cols-[2fr_1fr] items-center justify-between mt-18 gap-12 py-8">
<HeroSection /> <Image
src="/tipilan-white.svg"
width={850}
height={120}
alt="TipiLAN Logo"
className="px-8 py-8 md:px-12 md:py-14 dark:hidden w-[max(300px,min(100%,850px))] h-auto"
/>
<Image
src="/tipilan-dark.svg"
width={850}
height={120}
alt="TipiLAN Logo"
className="px-8 py-8 md:px-12 md:py-14 not-dark:hidden w-[max(300px,min(100%,850px))] h-auto2"
/>
<div className="pr-12 hidden md:block text-right">
<h3
className={`text-[clamp(1.25rem,0.75rem+2.5vw,3.75rem)] ${vipnagorgialla.className} leading-[90%] font-bold italic uppercase dark:text-[#EEE5E5] text-[#2A2C3F]`}
>
{t("tournaments.prizePool")}
</h3>
<h2
className={`text-[clamp(2rem,1.2rem+4vw,6rem)] ${vipnagorgialla.className} leading-[90%] font-bold italic text-[#007CAB] dark:text-[#00A3E0]`}
>
10 000
</h2>
</div>
</div> </div>
{/* Nav cards: Piletid + Turniirid */} {/* Farewell message */}
<div className="grid grid-cols-1 md:grid-cols-2 md:h-[260px] border-b-3 border-[#1F5673]"> <div>
<Link <section
href="/piletid" className={`p-8 md:p-12 flex flex-col ${vipnagorgialla.className} font-bold italic border-b-3 border-[#1F5673] hover:bg-[#007CAB] dark:hover:bg-[#00A3E0] group transition`}
className="px-8 md:px-12 py-8 flex flex-col justify-center gap-4 border-b-3 md:border-b-0 md:border-r-3 group border-[#1F5673] hover:bg-[#007CAB] dark:hover:bg-[#00A3E0] transition"
> >
<div className="flex flex-row justify-between gap-4 items-center"> <h2 className="text-[clamp(2rem,1.5rem+0.5vw,3rem)] text-[#007CAB] dark:text-[#00A3E0] dark:group-hover:text-[#EEE5E5] group-hover:text-[#EEE5E5]">
{t("home.sections.farewellMessage")} <span className="not-italic">🩵</span>
</h2>
</section>
</div>
{/* Grid of buttons */}
<div className="grid grid-cols-1 xl:grid-cols-3 border-[#1F5673]">
<Link
href="/ajakava"
className="px-8 md:px-12 py-8 flex flex-col gap-4 border-b-3 lg:border-r-3 group border-[#1F5673] hover:bg-[#007CAB] dark:hover:bg-[#00A3E0] transition"
>
<div className="cursor-pointer flex flex-row justify-between gap-4 items-center">
<h2 <h2
className={`text-[clamp(2rem,1.8rem+1vw,3rem)] ${vipnagorgialla.className} font-bold italic uppercase dark:text-[#EEE5E5] text-[#2A2C3F] group-hover:text-black dark:group-hover:text-[#2A2C3F]`} className={`text-[clamp(2rem,1.8rem+1vw,3rem)] ${vipnagorgialla.className} font-bold italic uppercase dark:text-[#EEE5E5] text-[#2A2C3F] group-hover:text-black dark:group-hover:text-[#2A2C3F]`}
> >
{t("navigation.tickets")} {t("navigation.schedule")}
</h2> </h2>
<span className="material-symbols-outlined !text-[clamp(2rem,1.5rem+1.5vw,3.5rem)] !font-bold text-[#007CAB] dark:text-[#00A3E0] group-hover:translate-x-2 dark:group-hover:text-[#EEE5E5] group-hover:text-[#EEE5E5] transition"> <span className="material-symbols-outlined !text-[clamp(2rem,1.5rem+1.5vw,3.5rem)] !font-bold text-[#007CAB] dark:text-[#00A3E0] group-hover:translate-x-2 dark:group-hover:text-[#EEE5E5] group-hover:text-[#EEE5E5] transition">
arrow_right_alt arrow_right_alt
@@ -39,18 +74,20 @@ export default async function Home({
</div> </div>
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<span className="material-symbols-outlined !text-[clamp(2rem,1.5rem+1.5vw,3.5rem)] text-[#007CAB] dark:text-[#00A3E0] dark:group-hover:text-[#EEE5E5] group-hover:text-[#EEE5E5]"> <span className="material-symbols-outlined !text-[clamp(2rem,1.5rem+1.5vw,3.5rem)] text-[#007CAB] dark:text-[#00A3E0] dark:group-hover:text-[#EEE5E5] group-hover:text-[#EEE5E5]">
confirmation_number event_note
</span> </span>
<p className="text-[clamp(0.875rem,0.75rem+0.5vw,1.25rem)] tracking-[-0.045rem] dark:group-hover:text-[#2A2C3F] group-hover:text-black">
{t("home.sections.schedule.description")}
</p>
</div> </div>
</Link> </Link>
<Link <Link
href="/turniirid" href="/turniirid"
className="px-8 md:px-12 py-8 flex flex-col justify-center gap-4 group border-[#1F5673] hover:bg-[#007CAB] dark:hover:bg-[#00A3E0] transition" className="px-8 md:px-12 py-8 flex flex-col gap-4 border-b-3 lg:border-r-3 group border-[#1F5673] hover:bg-[#007CAB] dark:hover:bg-[#00A3E0] transition"
> >
<div className="flex flex-row justify-between gap-4 items-center"> <div className="cursor-pointer flex flex-row justify-between gap-4 items-center">
<h2 <h2
className={`text-[clamp(2rem,1.8rem+1vw,3rem)] ${vipnagorgialla.className} font-bold italic uppercase dark:text-[#EEE5E5] text-[#2A2C3F] dark:group-hover:text-[#2A2C3F] group-hover:text-black`} className={`text-[clamp(2rem,1.8rem+1vw,3rem)] ${vipnagorgialla.className} font-bold italic break-normal uppercase dark:text-[#EEE5E5] text-[#2A2C3F] dark:group-hover:text-[#2A2C3F] group-hover:text-black`}
> >
{t("navigation.tournaments")} {t("navigation.tournaments")}
</h2> </h2>
@@ -58,16 +95,62 @@ export default async function Home({
arrow_right_alt arrow_right_alt
</span> </span>
</div> </div>
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<span className="material-symbols-outlined !text-[clamp(2rem,1.5rem+1.5vw,3.5rem)] text-[#007CAB] dark:text-[#00A3E0] dark:group-hover:text-[#EEE5E5] group-hover:text-[#EEE5E5]"> <span className="material-symbols-outlined !text-[clamp(2rem,1.5rem+1.5vw,3.5rem)] text-[#007CAB] dark:text-[#00A3E0] dark:group-hover:text-[#EEE5E5] group-hover:text-[#EEE5E5]">
trophy trophy
</span> </span>
<p className="text-[clamp(0.875rem,0.75rem+0.5vw,1.25rem)] tracking-[-0.045rem] dark:group-hover:text-[#2A2C3F] group-hover:text-black">
{t("home.sections.tournaments.description")}
</p>
</div>
</Link>
<Link
href="/messiala"
className="px-8 md:px-12 py-8 flex flex-col gap-4 border-b-3 border-[#1F5673] group hover:bg-[#007CAB] dark:hover:bg-[#00A3E0] transition-all"
>
<div className="cursor-pointer flex flex-row justify-between gap-4 items-center">
<h2
className={`text-[clamp(2rem,1.8rem+1vw,3rem)] ${vipnagorgialla.className} font-bold italic uppercase dark:text-[#EEE5E5] text-[#2A2C3F] dark:group-hover:text-[#2A2C3F] group-hover:text-black`}
>
{t("navigation.expo")}
</h2>
<span className="material-symbols-outlined !text-[clamp(2rem,1.5rem+1.5vw,3.5rem)] !font-bold text-[#007CAB] dark:text-[#00A3E0] group-hover:translate-x-2 dark:group-hover:text-[#EEE5E5] group-hover:text-[#EEE5E5] transition">
arrow_right_alt
</span>
</div>
<div className="flex flex-col gap-4">
<span className="material-symbols-outlined !text-[clamp(2rem,1.5rem+1.5vw,3.5rem)] text-[#007CAB] dark:text-[#00A3E0] dark:group-hover:text-[#EEE5E5] group-hover:text-[#EEE5E5]">
weekend
</span>
<p className="text-[clamp(0.875rem,0.75rem+0.5vw,1.25rem)] tracking-[-0.045rem] dark:group-hover:text-[#2A2C3F] group-hover:text-black">
{t("home.sections.expo.description")}
</p>
</div> </div>
</Link> </Link>
</div> </div>
{/* Teaser carousel */} {/* Section preserved for next year development */}
<TeaserCarousel /> {/* Date */}
{/* <div>*/}
{/* <Link*/}
{/* href="/piletid"*/}
{/* className={`p-8 md:p-12 flex flex-col ${vipnagorgialla.className} font-bold italic border-b-3 border-[#1F5673] hover:bg-[#007CAB] dark:hover:bg-[#00A3E0] group transition`}*/}
{/* >*/}
{/* <div className="cursor-pointer text-left flex flex-row justify-between xl:justify-start gap-8">*/}
{/* <h3 className="text-4xl md:text-5xl dark:text-[#EEE5E5] dark:group-hover:text-[#2A2C3F] text-[#2A2C3F] group-hover:text-black">*/}
{/* {t("home.sections.reserveSpot")}*/}
{/* </h3>*/}
{/* <span*/}
{/* className="material-symbols-outlined !text-[clamp(2rem,1.5rem+1.5vw,3.5rem)] !font-bold text-[#007CAB] dark:text-[#00A3E0] hidden md:block group-hover:translate-x-2 group-hover:text-[#EEE5E5] dark:group-hover:text-[#EEE5E5] transition">*/}
{/* arrow_right_alt*/}
{/* </span>*/}
{/* </div>*/}
{/* <h2 className="text-[clamp(2.5rem,2.25rem+1.25vw,3.75rem)] text-[#007CAB] dark:text-[#00A3E0] dark:group-hover:text-[#EEE5E5] group-hover:text-[#EEE5E5]">*/}
{/* {t("home.sections.dateAndLocation")}*/}
{/* </h2>*/}
{/* </Link>*/}
{/* </div>*/}
{/* Sponsors */} {/* Sponsors */}
<Sponsors /> <Sponsors />

View File

@@ -8,8 +8,8 @@ const workSans = Work_Sans({
}); });
export const metadata: Metadata = { export const metadata: Metadata = {
title: "TipiLAN 2026", title: "TipiLAN 2025",
description: "TipiLAN 2026 Eesti suurim tudengite korraldatud LAN!", description: "TipiLAN 2025 Eesti suurim tudengite korraldatud LAN!",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -1,4 +1,5 @@
import { SiDiscord, SiInstagram, SiFacebook } from "react-icons/si"; import { SiDiscord, SiInstagram, SiFacebook } from "react-icons/si";
import Image from "next/image";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
// Fonts // Fonts
@@ -8,82 +9,122 @@ const Footer = () => {
const t = useTranslations(); const t = useTranslations();
return ( return (
<div className="flex flex-col justify-center sm:justify-between px-6 py-6 md:px-12 md:py-8 gap-4"> <div className="flex flex-col justify-center sm:justify-between px-6 py-8 md:px-12 md:py-16 gap-4 md:gap-8">
<div className="flex md:items-center gap-8 md:gap-0 justify-between flex-col md:flex-row">
<div className="flex flex-col items-start md:items-center">
<Image
src="/tipilan-white.svg"
width={250}
height={36}
alt="TipiLAN Logo"
className="h-9 dark:hidden"
/>
<Image
src="/tipilan-dark.svg"
width={250}
height={36}
alt="TipiLAN Logo"
className="h-9 not-dark:hidden"
/>
</div>
{/* Social media */}
<div className="flex flex-row">
<a
href="https://discord.gg/pPhhatZAfA"
target="_blank"
className="mx-4 ml-0 md:ml-4"
rel="noopener noreferrer"
>
<SiDiscord
title="Discord"
size={"2em"}
className="text-[#2A2C3F] dark:text-[#EEE5E5] hover:text-[#007CAB] hover:dark:text-[#00A3E0] transition"
/>
</a>
<a
href="https://instagram.com/tipilan.ee"
target="_blank"
className="mx-4"
rel="noopener noreferrer"
>
<SiInstagram
title="Instagram"
size={"2em"}
className="text-[#2A2C3F] dark:text-[#EEE5E5] hover:text-[#007CAB] hover:dark:text-[#00A3E0] transition"
/>
</a>
<a
href="https://facebook.com/tipilan.ee"
target="_blank"
className="mx-4"
rel="noopener noreferrer"
>
<SiFacebook
title="Facebook"
size={"2em"}
className="text-[#2A2C3F] dark:text-[#EEE5E5] hover:text-[#007CAB] hover:dark:text-[#00A3E0] transition"
/>
</a>
</div>
</div>
<div className="flex flex-col"> <div className="flex flex-col">
<h2 <h2
className={`text-3xl sm:text-4xl ${vipnagorgialla.className} font-bold italic uppercase text-[#2A2C3F] dark:text-[#EEE5E5] mb-4`} className={`text-3xl sm:text-4xl ${vipnagorgialla.className} font-bold italic uppercase text-[#2A2C3F] dark:text-[#EEE5E5] mt-8 mb-4`}
> >
{t("footer.contact")} {t("footer.contact")}
</h2> </h2>
<div className="flex flex-row justify-between gap-8 items-start"> <div className="flex flex-row justify-between gap-4 items-center">
<div> <div>
<h3 className="text-xl font-bold"> <h3 className="text-xl font-bold">{t("footer.studentUnion")}</h3>
MTÜ Lapikud
</h3>
<div className="flex flex-col gap-2 mt-2"> <div className="flex flex-col gap-2 mt-2">
<div className="flex flex-row gap-2">
<span className="material-symbols-outlined !font-bold text-[#007CAB] dark:text-[#00A3E0]">
mail
</span>
<a href="mailto:tipilan@ituk.ee" className="underline">
tipilan@ituk.ee
</a>
</div>
<div className="flex flex-row gap-2">
<span className="material-symbols-outlined !font-bold text-[#007CAB] dark:text-[#00A3E0]">
phone
</span>
<a href="tel:+37256931193" className="underline">
+372 5693 1193
</a>
</div>
</div>
<h3 className="text-xl font-bold pt-4">
{t("footer.organization")}
</h3>
<div>
<p> <p>
{t("footer.registrationCode")}:{" "} {t("footer.registrationCode")}:{" "}
<span className="font-semibold text-[#007CAB] dark:text-[#00A3E0]"> <span className="font-semibold text-[#007CAB] dark:text-[#00A3E0]">
80167145 80391807
</span> </span>
</p> </p>
<p className="">Swedbank EE842200221094704780</p> <p className="">ICO-210, Raja tn 4c, Tallinn, Harjumaa, 12616</p>
</div> </div>
</div> </div>
<div className="flex flex-col gap-2 items-center"> </div>
<div className="flex flex-row gap-2"> <div className="block align-middle text-center pt-16">
<span className="material-symbols-outlined !font-bold text-[#007CAB] dark:text-[#00A3E0]"> {t("footer.madeBy")}{" "}
mail <a
</span> target="_blank"
<a href="mailto:tipilaninfo@gmail.com" className="underline"> href="https://lapikud.ee/"
tipilaninfo@gmail.com className="text-[#E3983E] font-bold"
</a> >
</div> MTÜ Lapikud
<div className="flex flex-row gap-2"> </a>{" "}
<span className="material-symbols-outlined !font-bold text-[#007CAB] dark:text-[#00A3E0]"> {t("footer.withHelpFrom")}{" "}
phone <a
</span> target="_blank"
<a href="tel:+37256931193" className="underline"> href="https://ituk.ee/"
+372 5693 1193 className="bg-[#7B1642] font-bold not-dark:text-white"
</a> >
</div> MTÜ For Tsükkel/ITÜK
</div> </a>
{/* Social media */}
<div className="flex flex-row gap-4">
<a
href="https://discord.gg/pPhhatZAfA"
target="_blank"
rel="noopener noreferrer"
>
<SiDiscord
title="Discord"
size={"2em"}
className="text-[#2A2C3F] dark:text-[#EEE5E5] hover:text-[#007CAB] hover:dark:text-[#00A3E0] transition"
/>
</a>
<a
href="https://instagram.com/tipilan.ee"
target="_blank"
rel="noopener noreferrer"
>
<SiInstagram
title="Instagram"
size={"2em"}
className="text-[#2A2C3F] dark:text-[#EEE5E5] hover:text-[#007CAB] hover:dark:text-[#00A3E0] transition"
/>
</a>
<a
href="https://facebook.com/tipilan.ee"
target="_blank"
rel="noopener noreferrer"
>
<SiFacebook
title="Facebook"
size={"2em"}
className="text-[#2A2C3F] dark:text-[#EEE5E5] hover:text-[#007CAB] hover:dark:text-[#00A3E0] transition"
/>
</a>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,75 +0,0 @@
import Image from "next/image";
import { Link } from "@/i18n/routing";
import { vipnagorgialla } from "@/components/Vipnagorgialla";
import { useTranslations } from "next-intl";
export default function HeroSection() {
const t = useTranslations("home");
return (
<section className="relative h-[569px] overflow-hidden border-b-3 border-[#1F5673]">
{/* Background image */}
<Image
src="/images/landing/main_teaser.jpg"
alt=""
fill
className="object-cover object-center"
priority
/>
{/* Dark overlay */}
<div className="absolute inset-0 bg-[#0E0F19]/75" />
{/* Content */}
<div className="relative h-full grid grid-cols-1 md:grid-cols-[3fr_2fr] items-center gap-8 px-8 md:px-12">
{/* Left: logo + info + CTA */}
<div className="flex flex-col gap-5">
<Image
src="/tipilan-dark.svg"
width={750}
height={106}
alt="TipiLAN Logo"
className="w-[max(260px,min(100%,750px))] h-auto"
/>
<div className={`${vipnagorgialla.className} font-bold italic`}>
<p className="text-[clamp(1.1rem,0.9rem+1vw,1.75rem)] text-[#00A3E0] uppercase tracking-wide">
{t("hero.date")}
</p>
<p className="text-[clamp(0.9rem,0.75rem+0.75vw,1.25rem)] text-[#EEE5E5] uppercase tracking-wide">
{t("hero.location")}
</p>
</div>
<Link
href="/piletid"
className={`self-start px-6 py-3 bg-[#007CAB] hover:bg-[#00A3E0] text-[#EEE5E5] ${vipnagorgialla.className} font-bold italic text-[clamp(1rem,0.8rem+0.8vw,1.5rem)] uppercase transition`}
>
{t("hero.buyTicket")}
</Link>
</div>
{/* Right: prize pool + award */}
<div className="flex flex-col items-start md:items-end gap-3">
<div className={`${vipnagorgialla.className} font-bold italic text-right`}>
<p className="text-[64px] leading-none tracking-normal uppercase text-[#EEE5E5]">
{t("hero.prizePool")}
</p>
<h2 className="text-[clamp(3rem,2rem+4vw,6rem)] leading-none text-[#00A3E0]">
10 000
</h2>
</div>
<div className="flex flex-row items-center md:items-center gap-0 mt-2">
<Image
src="/images/landing/student_award.webp"
width={180}
height={180}
alt="TalTech student award"
className="object-contain"
/>
<p className={`text-[32px] leading-none tracking-normal uppercase text-right align-middle text-[#EEE5E5] ${vipnagorgialla.className} font-bold italic`}>
{t("hero.awardPrefix")} <span className="text-[#00A3E0]">{t("hero.awardHighlight")}</span> {t("hero.awardSuffix")}
</p>
</div>
</div>
</div>
</section>
);
}

View File

@@ -1,39 +1,8 @@
"use client";
import { useState, useEffect, useCallback } from "react";
import { vipnagorgialla } from "@/components/Vipnagorgialla"; import { vipnagorgialla } from "@/components/Vipnagorgialla";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import Image from "next/image"; import Image from "next/image";
import NextLink from "next/link"; import NextLink from "next/link";
interface Sponsor {
href: string;
src: string;
alt: string;
width: number;
height: number;
className?: string;
}
const sponsors: Sponsor[] = [
{ href: "https://taltech.ee", src: "/sponsors/taltech-color.png", alt: "Taltech (Tallinna Tehnikaülikool)", width: 192, height: 192 },
{ href: "https://www.redbull.com/ee-et/", src: "/sponsors/redbull.png", alt: "Redbull", width: 80, height: 80 },
{ href: "https://www.simracing.ee/", src: "/sponsors/EVAL.png", alt: "EVAL", width: 200, height: 200 },
{ href: "https://www.facebook.com/bfglOfficial", src: "/sponsors/BFGL.png", alt: "BFGL", width: 192, height: 192 },
{ href: "https://www.tomorrow.ee/", src: "/sponsors/nt.png", alt: "Network Tomorrow", width: 300, height: 200 },
{ href: "https://k-space.ee/", src: "/sponsors/k-space_ee-white.png", alt: "K-Space", width: 200, height: 200, className: "not-dark:invert" },
{ href: "https://globalproductions.ee/", src: "/sponsors/Global-productions.png", alt: "Global Productions", width: 200, height: 200 },
{ href: "https://www.linkedin.com/company/gamedev-guild/", src: "/sponsors/estonian_gamedev_guild.png", alt: "Estonian Gamedev Guild", width: 200, height: 200, className: "not-dark:invert" },
{ href: "https://alzgamer.ee/", src: "/sponsors/alzgamer.png", alt: "AlzGamer", width: 200, height: 200 },
];
// Split sponsors into slides (6 per slide)
const SPONSORS_PER_SLIDE = 6;
const slides: Sponsor[][] = [];
for (let i = 0; i < sponsors.length; i += SPONSORS_PER_SLIDE) {
slides.push(sponsors.slice(i, i + SPONSORS_PER_SLIDE));
}
interface SponsorsProps { interface SponsorsProps {
showTitle?: boolean; showTitle?: boolean;
className?: string; className?: string;
@@ -44,65 +13,191 @@ export default function Sponsors({
className = "", className = "",
}: SponsorsProps) { }: SponsorsProps) {
const t = useTranslations(); const t = useTranslations();
const [current, setCurrent] = useState(0);
const next = useCallback(() => setCurrent((c) => (c + 1) % slides.length), []);
useEffect(() => {
const id = setInterval(next, 5000);
return () => clearInterval(id);
}, [next]);
return ( return (
<div <div
className={`flex flex-col max-w-[1920px] h-[414px] mx-auto ${vipnagorgialla.className} font-bold italic border-b-3 border-[#1F5673] ${className}`} className={`p-12 flex flex-col ${vipnagorgialla.className} font-bold italic border-b-3 border-[#1F5673] ${className}`}
> >
{showTitle && ( <div className="text-left flex flex-col justify-between xl:justify-start">
<h3 className="text-4xl md:text-5xl dark:text-[#EEE5E5] text-[#2A2C3F] px-12 pt-8 pb-4"> {showTitle && (
{t("home.sections.poweredBy")} <h3 className="text-4xl md:text-5xl dark:text-[#EEE5E5] text-[#2A2C3F] group-hover:text-black pb-8">
</h3> {t("home.sections.poweredBy")}
)} </h3>
)}
{/* Carousel container */} <div className="flex flex-col sm:flex-row flex-wrap gap-8 md:gap-18 items-center justify-center xl:justify-start">
<div className="relative flex-1 overflow-hidden"> <NextLink href="https://taltech.ee" target="_blank">
<div <Image
className="flex h-full transition-transform duration-500 ease-in-out" src="/sponsors/taltech-color.png"
style={{ transform: `translateX(-${current * 100}%)` }} alt="Taltech (Tallinna Tehnikaülikool)"
> width={192}
{slides.map((slideSponsors, slideIndex) => ( height={192}
<div className="object-contain"
key={slideIndex} />
className="flex-none w-full h-full flex items-center justify-center gap-8 md:gap-12 px-12" </NextLink>
> <NextLink href="https://www.redbull.com/ee-et/" target="_blank">
{slideSponsors.map((sponsor, i) => ( <Image
<NextLink key={i} href={sponsor.href} target="_blank"> src="/sponsors/redbull.png"
<Image alt="Redbull"
src={sponsor.src} width={80}
alt={sponsor.alt} height={80}
width={sponsor.width} className="object-contain"
height={sponsor.height} />
className={`object-contain max-h-[180px] ${sponsor.className || ""}`} </NextLink>
/> <NextLink href="https://www.alecoq.ee" target="_blank">
</NextLink> <Image
))} src="/sponsors/alecoq.svg"
</div> alt="Alecoq"
))} width={200}
height={200}
className="object-contain"
/>
</NextLink>
<NextLink href="https://www.simracing.ee/" target="_blank">
<Image
src="/sponsors/EVAL.png"
alt="EVAL"
width={200}
height={200}
className="object-contain"
/>
</NextLink>
<NextLink href="https://balsnack.ee" target="_blank">
<Image
src="/sponsors/balsnack.svg"
alt="Balsnack"
width={200}
height={200}
className="object-contain"
/>
</NextLink>
<NextLink
href="https://www.rara.ee/sundmused/interaktiivne-videomangude-muuseum-lvlup/"
target="_blank"
>
<Image
src="/sponsors/lvlup_logo_export.svg"
alt="LVLup!"
width={192}
height={192}
className="object-contain"
/>
</NextLink>
<NextLink
href="https://www.facebook.com/bfglOfficial"
target="_blank"
>
<Image
src="/sponsors/BFGL.png"
alt="BFGL"
width={192}
height={192}
className="object-contain"
/>
</NextLink>
<NextLink href="https://www.tallinn.ee/et/haridus" target="_blank">
<Image
src="/sponsors/Tallinna_Haridusamet_logo_RGB.svg"
alt="Tallinna Haridusamet"
width={292}
height={292}
className="object-contain"
/>
</NextLink>
<NextLink href="https://www.militaarseiklus.ee/" target="_blank">
<Image
src="/sponsors/militaarseiklus.png"
alt="Militaarseiklus"
width={200}
height={200}
className="object-contain"
/>
</NextLink>
<NextLink
href="https://www.linkedin.com/company/gamedev-guild/"
target="_blank"
>
<Image
src="/sponsors/estonian_gamedev_guild.png"
alt="Estonian Gamedev Guild"
width={200}
height={200}
className="object-contain not-dark:invert"
/>
</NextLink>
<NextLink href="https://thotell.ee/" target="_blank">
<Image
src="/sponsors/thotell.png"
alt="Tahentorni Hotell (Tähentorni Hotel)"
width={200}
height={200}
className="object-contain"
/>
</NextLink>
<NextLink href="https://www.dominos.ee/" target="_blank">
<Image
src="/sponsors/dominos.png"
alt="Domino's Pizza"
width={250}
height={250}
className="object-contain"
/>
</NextLink>
<NextLink href="https://www.tomorrow.ee/" target="_blank">
<Image
src="/sponsors/nt.png"
alt="Network Tomorrow"
width={300}
height={200}
className="object-contain"
/>
</NextLink>
<NextLink href="https://driftikeskus.ee/" target="_blank">
<Image
src="/sponsors/driftikeskus.png"
alt="Driftikeskus"
width={300}
height={200}
className="object-contain"
/>
</NextLink>
<NextLink href="https://ingame.ee/" target="_blank">
<Image
src="/sponsors/ingame.png"
alt="Ingame"
width={200}
height={200}
className="object-contain"
/>
</NextLink>
<NextLink href="https://alzgamer.ee/" target="_blank">
<Image
src="/sponsors/alzgamer.png"
alt="AlzGamer"
width={200}
height={200}
className="object-contain"
/>
</NextLink>
<NextLink href="https://k-space.ee/" target="_blank">
<Image
src="/sponsors/k-space_ee-white.png"
alt="K-Space"
width={200}
height={200}
className="object-contain not-dark:invert"
/>
</NextLink>
<NextLink href="https://globalproductions.ee/" target="_blank">
<Image
src="/sponsors/Global-productions.png"
alt="Global Productions"
width={200}
height={200}
className="object-contain"
/>
</NextLink>
</div> </div>
</div> </div>
{/* Navigation dots */}
<div className="flex justify-center gap-3 py-4">
{slides.map((_, i) => (
<button
key={i}
onClick={() => setCurrent(i)}
className={`w-3 h-3 rounded-full transition ${
i === current ? "bg-[#007CAB]" : "bg-[#1F5673] hover:bg-[#007CAB]/60"
}`}
aria-label={`Slide ${i + 1}`}
/>
))}
</div>
</div> </div>
); );
} }

View File

@@ -1,143 +0,0 @@
"use client";
import { useState, useEffect, useCallback } from "react";
import Image from "next/image";
import { Link } from "@/i18n/routing";
import { vipnagorgialla } from "@/components/Vipnagorgialla";
import { useTranslations } from "next-intl";
type Slide = {
key: "compete" | "play" | "explore";
image: string;
imageAlt: string;
hero: string;
href: "/turniirid" | "/piletid" | "/messiala";
flip?: boolean;
fullBrightness?: boolean;
};
// Helper to highlight "LAN" in "TIPILAN" with blue color
function highlightLAN(text: string) {
const parts = text.split(/(TIPILAN\w*)/gi);
return parts.map((part, i) => {
const upper = part.toUpperCase();
if (upper.startsWith("TIPILAN")) {
const suffix = part.slice(7); // Everything after "TIPILAN"
return (
<span key={i}>
TIPI<span className="text-[#00A3E0]">LAN</span>{suffix.toUpperCase()}
</span>
);
}
return part;
});
}
const slides: Slide[] = [
{ key: "compete", image: "/images/landing/compete_teaser.jpg", imageAlt: "Võistle", hero: "/images/landing/compete_hero.png", href: "/turniirid" },
{ key: "play", image: "/images/landing/play_teaser.png", imageAlt: "Mängi", hero: "/images/landing/play_hero.png", href: "/piletid", flip: true, fullBrightness: true },
{ key: "explore", image: "/images/landing/explore_teaser.png", imageAlt: "Avasta", hero: "/images/landing/explore_hero.png", href: "/messiala", fullBrightness: true },
];
export default function TeaserCarousel() {
const t = useTranslations("home.teaser");
const [current, setCurrent] = useState(0);
const next = useCallback(() => setCurrent((c) => (c + 1) % slides.length), []);
const prev = () => setCurrent((c) => (c - 1 + slides.length) % slides.length);
useEffect(() => {
const id = setInterval(next, 5000);
return () => clearInterval(id);
}, [next]);
return (
<div className="border-b-3 border-[#1F5673]">
{/* Sliding track */}
<div className="relative h-[729px] overflow-hidden">
<div
className="flex h-full transition-transform duration-500 ease-in-out"
style={{ transform: `translateX(-${current * 100}%)` }}
>
{slides.map((slide) => {
const title = t(`${slide.key}.title`);
const description = t(`${slide.key}.description`);
return (
<div key={slide.key} className="relative flex-none w-full h-full">
{/* Background image */}
<Image
src={slide.image}
alt={slide.imageAlt}
fill
className="object-cover object-center"
/>
{/* Overlay */}
<div className={`absolute inset-0 ${slide.fullBrightness ? "" : "bg-gradient-to-r from-[#0E0F19]/90 via-[#0E0F19]/60 to-[#0E0F19]/20"}`} />
{/* Content */}
<div className={`relative grid grid-cols-1 md:grid-cols-2 h-full ${slide.flip ? "md:[direction:rtl]" : ""}`}>
<div className={`flex flex-col justify-between px-8 py-8 md:px-12 md:py-10 ${slide.flip ? "md:[direction:ltr]" : ""}`}>
{/* Heading at top */}
<h2 className={`${vipnagorgialla.className} font-bold italic text-[64px] leading-none tracking-normal uppercase text-[#EEE5E5]`}>
{highlightLAN(t("heading"))}
</h2>
{/* Title + description at bottom */}
<div className="flex flex-col gap-3 pb-16">
<Link href={slide.href}>
<h3 className={`${vipnagorgialla.className} font-bold italic text-[clamp(2.5rem,2rem+2.5vw,5rem)] leading-none text-[#EEE5E5] hover:text-[#00A3E0] transition`}>
{title}
</h3>
</Link>
<p className="text-[clamp(0.875rem,0.75rem+0.5vw,1.1rem)] text-[#EEE5E5] max-w-prose">
{description}
</p>
</div>
</div>
{/* Hero image */}
<div className={`hidden md:block relative ${slide.flip ? "md:[direction:ltr]" : ""}`}>
<Image
src={slide.hero}
alt={slide.imageAlt}
fill
className="object-contain object-bottom"
/>
</div>
</div>
</div>
);
})}
</div>
{/* Arrow buttons */}
<button
onClick={prev}
className="absolute left-4 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center bg-[#0E0F19]/50 hover:bg-[#007CAB] text-[#EEE5E5] transition"
aria-label="Previous slide"
>
<span className="material-symbols-outlined">chevron_left</span>
</button>
<button
onClick={next}
className="absolute right-4 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center bg-[#0E0F19]/50 hover:bg-[#007CAB] text-[#EEE5E5] transition"
aria-label="Next slide"
>
<span className="material-symbols-outlined">chevron_right</span>
</button>
</div>
{/* Navigation dots */}
<div className="flex justify-center gap-3 py-5">
{slides.map((_, i) => (
<button
key={i}
onClick={() => setCurrent(i)}
className={`w-3 h-3 rounded-full transition ${
i === current ? "bg-[#007CAB]" : "bg-[#1F5673] hover:bg-[#007CAB]/60"
}`}
aria-label={`Slide ${i + 1}`}
/>
))}
</div>
</div>
);
}

View File

@@ -35,37 +35,10 @@
} }
}, },
"home": { "home": {
"title": "TipiLAN 2026", "title": "TipiLAN 2025",
"subtitle": "Estonia's largest student-organized LAN event!", "subtitle": "Estonia's largest student-organized LAN event!",
"welcome": "Welcome to TipiLAN 2026!", "welcome": "Welcome to TipiLAN 2025!",
"description": "Join us at Estonia's largest student-organized LAN event. Games, competitions and much more await you!", "description": "Join us at Estonia's largest student-organized LAN event. Games, competitions and much more await you!",
"hero": {
"date": "1113 OCTOBER 2026",
"location": "TALTECH, EHITAJATE TEE 5",
"buyTicket": "BUY TICKETS",
"prizePool": "PRIZE POOL",
"awardPrefix": "TALTECH",
"awardHighlight": "STUDENT ACT OF THE YEAR",
"awardSuffix": "2025"
},
"teaser": {
"heading": "COME TO TIPILAN AND...",
"compete": {
"title": "COMPETE",
"description": "Prove yourself in TipiLAN's CS2 and LoL tournaments: thousands in prize money, players from across Europe, and HLTV-ranked competition that could put you on the map.",
"link": "/turniirid"
},
"play": {
"title": "PLAY",
"description": "Enjoy the TipiLAN atmosphere — bring your computer, relax, play with friends and experience one of Estonia's largest gaming events.",
"link": "/piletid"
},
"explore": {
"title": "EXPLORE",
"description": "Explore the TipiLAN expo area where companies, mini-competitions and lots more exciting things await you.",
"link": "/messiala"
}
},
"sections": { "sections": {
"schedule": { "schedule": {
"description": "TipiLAN is packed with exciting tournaments, mini-competitions and much more." "description": "TipiLAN is packed with exciting tournaments, mini-competitions and much more."
@@ -78,7 +51,8 @@
}, },
"reserveSpot": "Reserve your spot today!", "reserveSpot": "Reserve your spot today!",
"poweredBy": "TipiLAN is powered by...", "poweredBy": "TipiLAN is powered by...",
"dateAndLocation": "11th13th Oct. @ TalTech" "dateAndLocation": "24th-26th Oct. @ TalTech main building",
"farewellMessage": "Thank you for partici\u00ADpating in TipiLAN 2025! We hope to see you again next time!"
} }
}, },
"tickets": { "tickets": {

View File

@@ -35,37 +35,10 @@
} }
}, },
"home": { "home": {
"title": "TipiLAN 2026", "title": "TipiLAN 2025",
"subtitle": "Eesti suurim tudengite korraldatud LAN!", "subtitle": "Eesti suurim tudengite korraldatud LAN!",
"welcome": "Tere tulemast TipiLAN 2026 sündmusele!", "welcome": "Tere tulemast TipiLAN 2025 sündmusele!",
"description": "Liitu meiega Eesti suurimal tudengite korraldatud LAN-üritusel. Mängud, võistlused ja palju muud ootavad sind!", "description": "Liitu meiega Eesti suurimal tudengite korraldatud LAN-üritusel. Mängud, võistlused ja palju muud ootavad sind!",
"hero": {
"date": "11.13. OKTOOBER 2026",
"location": "TALTECH, EHITAJATE TEE 5",
"buyTicket": "OSTA PILET",
"prizePool": "AUHINNAFOND",
"awardPrefix": "TALTECHI",
"awardHighlight": "AASTA TUDENGITEGU",
"awardSuffix": "2025"
},
"teaser": {
"heading": "TULE TIPILANILE JA...",
"compete": {
"title": "VÕISTLE",
"description": "Tõesta end TipiLANi CS2 ja LoL featurniiridel: tuhanded eurod auhinnarahas, mängijad üle kogu Euroopa ja HLTV-reitinguga võistlus, mis viib sind maailmakaardile.",
"link": "/turniirid"
},
"play": {
"title": "MÄNGI",
"description": "Naudi TipiLANi atmosfääri too kaasa arvuti, istutle mugavalt, mängi sõpradega ja koge ühte Eesti suurimat mänguüritust.",
"link": "/piletid"
},
"explore": {
"title": "AVASTA",
"description": "Avasta TipiLANi messialat, kus ootavad sind erinevad ettevõtted, mini-võistlused ja palju muud põnevat.",
"link": "/messiala"
}
},
"sections": { "sections": {
"schedule": { "schedule": {
"description": "TipiLAN on pungil põnevatest turniiridest, mini-võistlustest ja paljust muust." "description": "TipiLAN on pungil põnevatest turniiridest, mini-võistlustest ja paljust muust."
@@ -78,7 +51,8 @@
}, },
"reserveSpot": "Broneeri oma koht juba täna!", "reserveSpot": "Broneeri oma koht juba täna!",
"poweredBy": "TipiLANi tõmbab käima...", "poweredBy": "TipiLANi tõmbab käima...",
"dateAndLocation": "11.13. okt. TalTechis" "dateAndLocation": "24.-26. okt. TalTechi peahoones",
"farewellMessage": "Aitäh, et olite osa TipiLAN 2025-st! Ootame teid tagasi järgmisele!"
} }
}, },
"tickets": { "tickets": {

View File

@@ -1,11 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES2017", "target": "ES2017",
"lib": [ "lib": ["dom", "dom.iterable", "esnext"],
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true, "allowJs": true,
"skipLibCheck": true, "skipLibCheck": true,
"strict": true, "strict": true,
@@ -15,7 +11,7 @@
"moduleResolution": "bundler", "moduleResolution": "bundler",
"resolveJsonModule": true, "resolveJsonModule": true,
"isolatedModules": true, "isolatedModules": true,
"jsx": "react-jsx", "jsx": "preserve",
"incremental": true, "incremental": true,
"plugins": [ "plugins": [
{ {
@@ -23,19 +19,9 @@
} }
], ],
"paths": { "paths": {
"@/*": [ "@/*": ["./src/*"]
"./src/*"
]
} }
}, },
"include": [ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"next-env.d.ts", "exclude": ["node_modules"]
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": [
"node_modules"
]
} }