From 334a4ed9d5286e42bb173e93e5d7ad0d9802fbd7 Mon Sep 17 00:00:00 2001 From: v4ltages Date: Wed, 9 Sep 2026 01:08:56 +0300 Subject: [PATCH] Add expo area, card zoom on mobile devices --- src/app/[locale]/messiala/page.tsx | 113 +++++++++++++++++++++++------ src/components/Header.tsx | 2 +- translations/en.json | 2 + translations/et.json | 2 + 4 files changed, 94 insertions(+), 25 deletions(-) diff --git a/src/app/[locale]/messiala/page.tsx b/src/app/[locale]/messiala/page.tsx index 93de3ba..c4f120d 100644 --- a/src/app/[locale]/messiala/page.tsx +++ b/src/app/[locale]/messiala/page.tsx @@ -1,13 +1,95 @@ +"use client"; + +import React from "react"; import { vipnagorgialla } from "@/components/Vipnagorgialla"; import Image from "next/image"; import Link from "next/link"; -import { getTranslations, setRequestLocale } from "next-intl/server"; +import { useTranslations } from "next-intl"; +import { useState } from "react"; import { developers, universities } from "@/data/expo"; /** 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-4 sm:px-8 lg:px-16"; +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 ( +
+ {/* Container for the map image - only shown in landscape */} +
e.stopPropagation()}> +
+ {label} +
+
+ {/* 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) => ( + + ))} +
+
+ {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 }) { @@ -149,20 +231,14 @@ function GameCard({ ); } -export default async function Expo({ - params, -}: { - params: Promise<{ locale: string }>; -}) { - const { locale } = await params; - setRequestLocale(locale); - const t = await getTranslations({ locale }); +export default function Expo() { + const t = useTranslations(); return (
-
+
{/* Page title */} -
+

@@ -171,18 +247,7 @@ export default async function Expo({

{/* Venue maps */} -
-
- - -
-
+ {/* Mini-tournaments feature (full-bleed) */}
{ 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/translations/en.json b/translations/en.json index f541ab3..da6c239 100644 --- a/translations/en.json +++ b/translations/en.json @@ -870,6 +870,8 @@ "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€.", diff --git a/translations/et.json b/translations/et.json index 0eb974d..a933b76 100644 --- a/translations/et.json +++ b/translations/et.json @@ -871,6 +871,8 @@ "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€.",