diff --git a/public/images/EXPO/baar.jpg b/public/images/EXPO/baar.jpg
index c38511b..95dc901 100644
Binary files a/public/images/EXPO/baar.jpg and b/public/images/EXPO/baar.jpg differ
diff --git a/public/images/EXPO/chill_ala.jpg b/public/images/EXPO/chill_ala.jpg
index 7352d14..0b0c385 100644
Binary files a/public/images/EXPO/chill_ala.jpg and b/public/images/EXPO/chill_ala.jpg differ
diff --git a/public/images/EXPO/console.jpg b/public/images/EXPO/console.jpg
new file mode 100644
index 0000000..de20a86
Binary files /dev/null and b/public/images/EXPO/console.jpg differ
diff --git a/public/images/EXPO/gamedev/bullosseum.png b/public/images/EXPO/gamedev/bullosseum.png
new file mode 100644
index 0000000..9c43327
Binary files /dev/null and b/public/images/EXPO/gamedev/bullosseum.png differ
diff --git a/public/images/EXPO/gamedev/eelloon.png b/public/images/EXPO/gamedev/eelloon.png
new file mode 100644
index 0000000..e51d5bb
Binary files /dev/null and b/public/images/EXPO/gamedev/eelloon.png differ
diff --git a/public/images/EXPO/gamedev/estonian_language.png b/public/images/EXPO/gamedev/estonian_language.png
new file mode 100644
index 0000000..89deca5
Binary files /dev/null and b/public/images/EXPO/gamedev/estonian_language.png differ
diff --git a/public/images/EXPO/gamedev/grandpas_bee_haven.png b/public/images/EXPO/gamedev/grandpas_bee_haven.png
new file mode 100644
index 0000000..faec50b
Binary files /dev/null and b/public/images/EXPO/gamedev/grandpas_bee_haven.png differ
diff --git a/public/images/EXPO/gamedev/hardwired.png b/public/images/EXPO/gamedev/hardwired.png
new file mode 100644
index 0000000..94c7444
Binary files /dev/null and b/public/images/EXPO/gamedev/hardwired.png differ
diff --git a/public/images/EXPO/gamedev/hearthland.png b/public/images/EXPO/gamedev/hearthland.png
new file mode 100644
index 0000000..1b80d28
Binary files /dev/null and b/public/images/EXPO/gamedev/hearthland.png differ
diff --git a/public/images/EXPO/gamedev/jazzwitch.png b/public/images/EXPO/gamedev/jazzwitch.png
new file mode 100644
index 0000000..3031254
Binary files /dev/null and b/public/images/EXPO/gamedev/jazzwitch.png differ
diff --git a/public/images/EXPO/gamedev/machine_party.png b/public/images/EXPO/gamedev/machine_party.png
new file mode 100644
index 0000000..19a03b4
Binary files /dev/null and b/public/images/EXPO/gamedev/machine_party.png differ
diff --git a/public/images/EXPO/gamedev/manala.png b/public/images/EXPO/gamedev/manala.png
new file mode 100644
index 0000000..aab9cd1
Binary files /dev/null and b/public/images/EXPO/gamedev/manala.png differ
diff --git a/public/images/EXPO/gamedev/midnight_clinic.png b/public/images/EXPO/gamedev/midnight_clinic.png
new file mode 100644
index 0000000..d383fbc
Binary files /dev/null and b/public/images/EXPO/gamedev/midnight_clinic.png differ
diff --git a/public/images/EXPO/gamedev/midnight_souvenirs.png b/public/images/EXPO/gamedev/midnight_souvenirs.png
new file mode 100644
index 0000000..633df63
Binary files /dev/null and b/public/images/EXPO/gamedev/midnight_souvenirs.png differ
diff --git a/public/images/EXPO/gamedev/multimatum.png b/public/images/EXPO/gamedev/multimatum.png
new file mode 100644
index 0000000..3f0fc1a
Binary files /dev/null and b/public/images/EXPO/gamedev/multimatum.png differ
diff --git a/public/images/EXPO/gamedev/orms.png b/public/images/EXPO/gamedev/orms.png
new file mode 100644
index 0000000..7fc2d5f
Binary files /dev/null and b/public/images/EXPO/gamedev/orms.png differ
diff --git a/public/images/EXPO/gamedev/osta.png b/public/images/EXPO/gamedev/osta.png
new file mode 100644
index 0000000..c37681a
Binary files /dev/null and b/public/images/EXPO/gamedev/osta.png differ
diff --git a/public/images/EXPO/gamedev/self_storm.svg b/public/images/EXPO/gamedev/self_storm.svg
new file mode 100644
index 0000000..71c5b7d
--- /dev/null
+++ b/public/images/EXPO/gamedev/self_storm.svg
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/images/EXPO/gamedev/toimkonna_simulator.png b/public/images/EXPO/gamedev/toimkonna_simulator.png
new file mode 100644
index 0000000..eff88ec
Binary files /dev/null and b/public/images/EXPO/gamedev/toimkonna_simulator.png differ
diff --git a/public/images/EXPO/gamedev/walk.png b/public/images/EXPO/gamedev/walk.png
new file mode 100644
index 0000000..d260680
Binary files /dev/null and b/public/images/EXPO/gamedev/walk.png differ
diff --git a/public/images/EXPO/gamedev/war_torn.png b/public/images/EXPO/gamedev/war_torn.png
new file mode 100644
index 0000000..094c776
Binary files /dev/null and b/public/images/EXPO/gamedev/war_torn.png differ
diff --git a/public/images/messiala/fuajee-kaart.svg b/public/images/messiala/fuajee-kaart.svg
new file mode 100644
index 0000000..9763d7a
--- /dev/null
+++ b/public/images/messiala/fuajee-kaart.svg
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/images/messiala/tudengimaja-kaart.svg b/public/images/messiala/tudengimaja-kaart.svg
new file mode 100644
index 0000000..1cb13e8
--- /dev/null
+++ b/public/images/messiala/tudengimaja-kaart.svg
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/[locale]/messiala/page.tsx b/src/app/[locale]/messiala/page.tsx
index 5721527..c4f120d 100644
--- a/src/app/[locale]/messiala/page.tsx
+++ b/src/app/[locale]/messiala/page.tsx
@@ -1,27 +1,343 @@
+"use client";
+
+import React from "react";
import { vipnagorgialla } from "@/components/Vipnagorgialla";
-import { getTranslations, setRequestLocale } from "next-intl/server";
+import Image from "next/image";
+import Link from "next/link";
+import { useTranslations } from "next-intl";
+import { useState } from "react";
+import { developers, universities } from "@/data/expo";
-export default async function Expo({
- params,
-}: {
- params: Promise<{ locale: string }>;
-}) {
- const { locale } = await params;
- setRequestLocale(locale);
- const t = await getTranslations({ locale });
+/** Thick semi-transparent cyan rule that separates the full-bleed sections. */
+const DIVIDER = "border-t-4 border-[rgba(0,163,224,0.5)]";
+/** Horizontal padding used by the padded sections (64px at the design width). */
+const GUTTER = "px-6 md:px-16";
+/** Map Modal Component */
+function MapModal({ onClose, imageSrc, label, rotateMessage }: { onClose: () => void; imageSrc: string; label: string; rotateMessage: string }) {
return (
-
-
- {t("expo.title")}
-
-
- {t("expo.comingSoon")}
-
+
+ {/* Container for the map image - only shown in landscape */}
+
e.stopPropagation()}>
+
+
+
+
+ {/* Portrait warning with border - only shown in portrait on small screens */}
+
e.stopPropagation()}>
+ {rotateMessage}
+
+
+ );
+}
+
+/** Client component for the maps section with modal functionality */
+function MapsSection({ gutter }: { gutter: string }) {
+ const t = useTranslations();
+ const [selectedMap, setSelectedMap] = useState<{ image: string; label: string } | null>(null);
+
+ React.useEffect(() => {
+ if (selectedMap) {
+ document.body.style.overflow = "hidden";
+ } else {
+ document.body.style.overflow = "";
+ }
+ return () => {
+ document.body.style.overflow = "";
+ };
+ }, [selectedMap]);
+
+ const maps = [
+ { image: "/images/messiala/fuajee-kaart.svg", label: t("expo.mapFoyer") },
+ { image: "/images/messiala/tudengimaja-kaart.svg", label: t("expo.mapStudentHouse") },
+ ];
+
+ return (
+ <>
+
+
+ {maps.map((map) => (
+
setSelectedMap(map)}
+ className="relative aspect-[3/2] md:aspect-[4/3] w-full cursor-zoom-in hover:brightness-110 transition"
+ aria-label={t("expo.viewMap")}
+ >
+
+
+ ))}
+
+
+ {selectedMap && (
+
setSelectedMap(null)}
+ imageSrc={selectedMap.image}
+ label={selectedMap.label}
+ rotateMessage={t("expo.rotateDevice")}
+ />
+ )}
+ >
+ );
+}
+
+/** Venue map card: the map SVG rendered transparent over the page background. */
+function MapCard({ image, label }: { image: string; label: string }) {
+ return (
+
+
+
+ );
+}
+
+/**
+ * Photo tile in the gallery band: the image is faded over the dark background
+ * (as in the design) with a large caption. Caption alignment is configurable so
+ * the middle tile can sit bottom-right like the mockup.
+ */
+function FadedPhoto({
+ image,
+ caption,
+ align = "left",
+ valign = "center",
+}: {
+ image: string;
+ caption: string;
+ align?: "left" | "right";
+ valign?: "center" | "bottom";
+}) {
+ return (
+
+ );
+}
+
+/** Skewed section heading (no rule underneath — sections are split by DIVIDER). */
+function SectionHeading({ children }: { children: React.ReactNode }) {
+ return (
+
+
+ {children}
+
+
+ );
+}
+
+/**
+ * One showcase card: a cyan-bordered logo box above a linked title and a
+ * studio/team line. Logos render object-contain; screenshots (`cover`) fill the
+ * box. Teams without a logo yet fall back to their name set inside the box.
+ */
+function GameCard({
+ image,
+ title,
+ subtitle,
+ url,
+ cover = false,
+}: {
+ image?: string;
+ title: string;
+ subtitle: string;
+ url?: string;
+ cover?: boolean;
+}) {
+ const titleEl = url ? (
+
+ {title}
+
+ ) : (
+
+ {title}
+
+ );
+
+ return (
+
+
+ {image ? (
+
+ ) : (
+
+ {title}
+
+ )}
+
+ {titleEl}
+
+ {subtitle}
+
+
+ );
+}
+
+export default function Expo() {
+ const t = useTranslations();
+
+ return (
+
+
+ {/* Page title */}
+
+
+ {t("expo.title")}
+
+
+
+ {/* Venue maps */}
+
+
+ {/* Mini-tournaments feature (full-bleed) */}
+
+
+
+
+
+ {t("expo.miniTournaments.title")}
+
+
+ {t("expo.miniTournaments.description")}
+
+
+
+ {t("expo.miniTournaments.cta")}
+
+
+
+
+
+ {/* Photo gallery: two faded tiles left, one tall faded tile right,
+ separated by thin cyan gaps (the band background shows through). */}
+
+
+ {/* Estonian game developers */}
+
+ {t("expo.developers")}
+
+ {developers.map((dev) => (
+
+ ))}
+
+
+
+ {/* Universities */}
+
+ {t("expo.universities")}
+
+ {universities.map((uni) => (
+
+ ))}
+
+
+
);
}
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index 9e619b4..ea021ea 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -41,7 +41,7 @@ const Header = ({ navItems }: HeaderProps) => {
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
// Header navigation should include all options except homepage and hidden items
- const hiddenNavHrefs: NavItem["href"][] = ["/messiala"];
+ const hiddenNavHrefs: NavItem["href"][] = [];
const mainNavItems = navItems.filter(
(item) => item.href !== "/" && !hiddenNavHrefs.includes(item.href),
);
diff --git a/src/data/expo.ts b/src/data/expo.ts
new file mode 100644
index 0000000..f897e0b
--- /dev/null
+++ b/src/data/expo.ts
@@ -0,0 +1,173 @@
+// Content for the Messiala (expo) page.
+//
+// Titles, studio and team names are proper nouns, so they live here as plain
+// strings rather than in the translation files. Section headings and captions
+// are translated (see the `expo` block in translations/et.json + en.json).
+//
+// The developer list is sourced from the TipiLAN 2026 game-dev showcase signup
+// sheet. University / TalTech GameCamp teams live in `universities` instead.
+//
+// Logos were downloaded from the signup sheet's Drive folder into
+// public/images/EXPO/gamedev/. `logo` / `image` stay optional (one team has no
+// logo yet); cards fall back to a text tile when absent.
+
+export interface DeveloperCard {
+ /** Game / product name (proper noun, shown as-is). */
+ title: string;
+ /** Studio / team behind it. */
+ studio: string;
+ /** External link for the game (Steam, itch.io, etc.). Omitted when none yet. */
+ url?: string;
+ /** Logo image under /public. Rendered object-contain. Optional. */
+ logo?: string;
+}
+
+export interface UniversityCard {
+ /** Game name (proper noun, shown as-is). */
+ title: string;
+ /** Team / course that made it. */
+ team: string;
+ /** External link for the game. Omitted when none. */
+ url?: string;
+ /** Thumbnail under /public. Optional. */
+ image?: string;
+ /** Render the image object-contain (a logo) instead of object-cover (a screenshot). */
+ contain?: boolean;
+}
+
+// Studio / commercial teams (order follows the signup sheet).
+export const developers: DeveloperCard[] = [
+ {
+ title: "ORMS",
+ studio: "Rhea Games",
+ url: "https://store.steampowered.com/app/3743150/ORMS/",
+ logo: "/images/EXPO/gamedev/orms.png",
+ },
+ {
+ title: "Grandpa's Bee Haven",
+ studio: "Kickstart Now",
+ url: "https://store.steampowered.com/app/3209160/Grandpas_Bee_Haven/",
+ logo: "/images/EXPO/gamedev/grandpas_bee_haven.png",
+ },
+ {
+ title: "walk",
+ studio: "bilge",
+ url: "https://store.steampowered.com/app/4563880/walk/",
+ logo: "/images/EXPO/gamedev/walk.png",
+ },
+ {
+ title: "War-Torn",
+ studio: "Moccer Interactive",
+ url: "https://kingoftheend.itch.io/war-torn",
+ logo: "/images/EXPO/gamedev/war_torn.png",
+ },
+ {
+ title: "Machine Party",
+ studio: "Mike Klubnika",
+ url: "https://store.steampowered.com/app/4108000/Machine_Party/",
+ logo: "/images/EXPO/gamedev/machine_party.png",
+ },
+ {
+ title: "Manala: Equinox War",
+ studio: "OÜ Kilbirivi",
+ url: "https://store.steampowered.com/app/4898080/Manala_Equinox_War/",
+ logo: "/images/EXPO/gamedev/manala.png",
+ },
+ {
+ title: "Toimkonna simulator",
+ studio: "M4rtenn",
+ url: "https://store.steampowered.com/app/4834280/Toimkonna_simulator/",
+ logo: "/images/EXPO/gamedev/toimkonna_simulator.png",
+ },
+ {
+ title: "MULTIMATUM",
+ studio: "DeepDevelopment Games",
+ logo: "/images/EXPO/gamedev/multimatum.png",
+ },
+ {
+ title: "SELF STORM",
+ studio: "Triple Trigger",
+ url: "https://taavippp.itch.io/self-storm",
+ logo: "/images/EXPO/gamedev/self_storm.svg",
+ },
+ {
+ title: "JazzWitch",
+ studio: "VuKaan",
+ url: "https://store.steampowered.com/app/4952960/JazzWitch/",
+ logo: "/images/EXPO/gamedev/jazzwitch.png",
+ },
+ {
+ title: "Hearthland",
+ studio: "Best mäng OÜ",
+ logo: "/images/EXPO/gamedev/hearthland.png",
+ },
+ {
+ title: "Bullosseum",
+ studio: "Pullivennad",
+ url: "https://bullosseum.richard.work/",
+ logo: "/images/EXPO/gamedev/bullosseum.png",
+ },
+ {
+ title: "Hardwired",
+ studio: "Lostbyte",
+ url: "https://store.steampowered.com/app/3682210/Hardwired/",
+ logo: "/images/EXPO/gamedev/hardwired.png",
+ },
+ {
+ title: "Osta",
+ studio: "Cup",
+ url: "https://store.steampowered.com/app/3997240/Osta/",
+ logo: "/images/EXPO/gamedev/osta.png",
+ },
+ {
+ title: "Midnight Clinic",
+ studio: "HRA Interactive",
+ logo: "/images/EXPO/gamedev/midnight_clinic.png",
+ },
+ {
+ title: "Midnight Souvenirs",
+ studio: "Path of Pixels",
+ url: "https://store.steampowered.com/app/3623230/Midnight_Souvenirs",
+ logo: "/images/EXPO/gamedev/midnight_souvenirs.png",
+ },
+ {
+ title: "Estonian Language Learning Games",
+ studio: "Estonian Language Self Study Club",
+ url: "https://www.instagram.com/estonian_studyclub/",
+ logo: "/images/EXPO/gamedev/estonian_language.png",
+ },
+];
+
+// University / TalTech GameCamp teams.
+export const universities: UniversityCard[] = [
+ {
+ title: "Dwarf Escape",
+ team: 'TalTech GameCamp ("Mõmmid")',
+ url: "https://ihorsylin.itch.io/dwarf-escape",
+ image: "/images/EXPO/ylikoolid/dwarf_escape.png",
+ },
+ {
+ title: "Packet Tracers",
+ team: "TalTech IT-teaduskond",
+ url: "https://alacrisdevs.itch.io/packet-tracers",
+ image: "/images/EXPO/ylikoolid/packet_tracers.png",
+ },
+ {
+ title: "OH CRAP!",
+ team: 'TalTech GameCamp ("Skill Issue")',
+ url: "https://heavybro.itch.io/oh-crap",
+ image: "/images/EXPO/ylikoolid/oh_crap.png",
+ },
+ {
+ title: "Void of Hermes",
+ team: 'TalTech GameCamp ("OnlyFun")',
+ url: "https://ron88.itch.io/voidofhermes",
+ image: "/images/EXPO/ylikoolid/void_of_hermes.png",
+ },
+ {
+ title: "Eelloon",
+ team: "TalTech",
+ image: "/images/EXPO/gamedev/eelloon.png",
+ contain: true,
+ },
+];
diff --git a/translations/en.json b/translations/en.json
index 8e0dcbc..75bd248 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -875,6 +875,22 @@
"title": "Expo Area",
"comingSoon": "Coming soon",
"description": "The TipiLAN expo area hosts companies, additional activities and lectures.",
+ "mapFoyer": "Foyer map",
+ "mapStudentHouse": "Student house map",
+ "viewMap": "View map",
+ "rotateDevice": "Please rotate your device to landscape for the best experience.",
+ "miniTournaments": {
+ "title": "Mini-tournaments",
+ "description": "TipiLAN hosts a variety of fun and competitive mini-tournaments. Regular visitors can take part too! The total prize pool across all tournaments is 1250€.",
+ "cta": "More about mini-tournaments"
+ },
+ "photos": {
+ "chill": "Chill area with live tournament broadcasts",
+ "console": "Lots of different video games and consoles",
+ "bar": "Bar area with drinks and snacks"
+ },
+ "developers": "Estonian game developers",
+ "universities": "Universities",
"areas": {
"bar": "Bar",
"boardGames": "Board Games Area",
diff --git a/translations/et.json b/translations/et.json
index f4eb401..03fbd77 100644
--- a/translations/et.json
+++ b/translations/et.json
@@ -876,6 +876,22 @@
"title": "Messiala",
"comingSoon": "Tuleb hiljem",
"description": "TipiLANi messialal paiknevad ettevõtted, lisategevused ja toimuvad loengud.",
+ "mapFoyer": "Fuajee kaart",
+ "mapStudentHouse": "Tudengimaja kaart",
+ "viewMap": "Vaata kaarti",
+ "rotateDevice": "Palun pöörake seade horisontaalasendisse parema vaate jaoks.",
+ "miniTournaments": {
+ "title": "Miniturniirid",
+ "description": "TipiLANil toimub mitmeid erinevaid lõbusaid ja võistlushimu tekitavaid miniturniire. Osaleda saavad ka niisama külastajad! Auhinnafond on kõigi turniiride peale 1250€.",
+ "cta": "Miniturniiridest lähemalt"
+ },
+ "photos": {
+ "chill": "Chill-ala koos turniiride otseülekandega",
+ "console": "Palju erinevaid videomänge ja konsoole",
+ "bar": "Baariala jookide ja snäkkidega"
+ },
+ "developers": "Eesti mänguarendajad",
+ "universities": "Ülikoolid",
"areas": {
"bar": "Baar",
"boardGames": "Lauamängude ala",