From 23cf0ebff6c6df0cdbb6d190dbc1554f9a42f8fe Mon Sep 17 00:00:00 2001 From: SwagMuffin88 Date: Thu, 21 Aug 2025 16:22:08 +0300 Subject: [PATCH 1/4] make pathname naming more clear --- src/i18n/routing.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18n/routing.ts b/src/i18n/routing.ts index 07d8c6f..9e833ed 100644 --- a/src/i18n/routing.ts +++ b/src/i18n/routing.ts @@ -24,7 +24,7 @@ export const routing = defineRouting({ }, "/kodukord": { et: "/kodukord", - en: "/rules", + en: "/houserules", }, "/messiala": { et: "/messiala", @@ -36,7 +36,7 @@ export const routing = defineRouting({ }, "/reeglid": { et: "/reeglid", - en: "/regulations", + en: "/gamerules", }, "/striim": { et: "/striim", From 9906671cc0f11bf1e95f325e9116698bcccf14c4 Mon Sep 17 00:00:00 2001 From: SwagMuffin88 Date: Thu, 21 Aug 2025 17:38:12 +0300 Subject: [PATCH 2/4] fix variables in translation files --- src/app/[locale]/reeglid/page.tsx | 9 +++++---- translations/en.json | 6 +++--- translations/et.json | 3 ++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/app/[locale]/reeglid/page.tsx b/src/app/[locale]/reeglid/page.tsx index ba27e02..0886779 100644 --- a/src/app/[locale]/reeglid/page.tsx +++ b/src/app/[locale]/reeglid/page.tsx @@ -9,16 +9,17 @@ export default async function RulesMenu({ params: Promise<{ locale: string }>; }) { const { locale } = await params; + setRequestLocale(locale); + const t = await getTranslations({ locale }); + const headingStyle = `text-4xl md:text-5xl lg:text-6xl ${vipnagorgialla.className} font-bold italic text-[#2A2C3F] dark:text-[#EEE5E5] uppercase`; const boxStyle = `-skew-x-2 md:-skew-x-5 text-white md:px-12 hover:scale-103 transition-all duration-150 w-full md:w-xl lg:w-[400px]`; const boxTextStyle = `text-3xl ${vipnagorgialla.className} font-bold uppercase text-[#EEE5E5] pb-2`; - - // const SectionDivider = () =>
; - + return (
@@ -49,7 +50,7 @@ export default async function RulesMenu({ {/**/}

- {t("tournaments.mini.titleSingular")} {t("rules.title")} + {t("rules.miniRules")}

{/**/} diff --git a/translations/en.json b/translations/en.json index 73ec36e..566f638 100644 --- a/translations/en.json +++ b/translations/en.json @@ -6,7 +6,7 @@ "houserules": "House rules", "expo": "Expo", "tickets": "Tickets", - "rules": "Rules", + "rules": "Game rules", "stream": "Stream", "tournaments": "Tournaments" }, @@ -116,7 +116,6 @@ "buyTicket": "BUY TICKETS" }, "mini": { - "titleSingular": "Mini-tournament", "title": "Mini-tournaments", "timing": "Timing to be announced", "description1": "TipiLAN hosts various fun and competitive mini-tournaments. Mini-tournaments take place in the following games: SimRacing, Tekken, FIFA, Minecraft Bedwars, Buckshot Roulette, LostGamer and many more.", @@ -185,7 +184,8 @@ "title": "Rules", "houseRules": "House Rules", "cs2Rules": "CS2 Rules", - "lolRules": "LoL Rules" + "lolRules": "LoL Rules", + "miniRules": "Mini-tournament Rules" }, "admin": { "title": "Admin", diff --git a/translations/et.json b/translations/et.json index 40ba4f3..7c1818e 100644 --- a/translations/et.json +++ b/translations/et.json @@ -184,7 +184,8 @@ "title": "Reeglid", "houseRules": "Kodukord", "cs2Rules": "CS2 Reeglid", - "lolRules": "LoL Reeglid" + "lolRules": "LoL Reeglid", + "miniRules": "Miniturniiride Reeglid" }, "admin": { "title": "Haldus", From 1ef88c8b9aca4e4a900aa17f1dbcde4d44e2daea Mon Sep 17 00:00:00 2001 From: SwagMuffin88 Date: Fri, 22 Aug 2025 12:03:13 +0300 Subject: [PATCH 3/4] add more context in expo page buttons --- package.json | 32 ++++++++++++++++---------------- translations/en.json | 4 ++-- translations/et.json | 4 ++-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index ee82a4e..7ecec4f 100644 --- a/package.json +++ b/package.json @@ -15,20 +15,20 @@ "drizzle:studio": "drizzle-kit studio" }, "dependencies": { - "@libsql/client": "^0.15.9", + "@libsql/client": "^0.15.12", "@paralleldrive/cuid2": "^2.2.2", - "@radix-ui/react-alert-dialog": "^1.1.14", - "@radix-ui/react-dropdown-menu": "^2.1.15", - "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-alert-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.3", - "@radix-ui/react-tooltip": "^1.2.7", + "@radix-ui/react-tooltip": "^1.2.8", "@tanstack/react-table": "^8.21.3", "@types/three": "^0.178.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "drizzle-orm": "^0.44.2", + "drizzle-orm": "^0.44.4", "lucide-react": "^0.522.0", - "material-symbols": "^0.31.8", + "material-symbols": "^0.31.9", "next": "15.3.0", "next-intl": "^4.3.4", "next-themes": "^0.4.6", @@ -38,23 +38,23 @@ "react-markdown": "^10.1.0", "tailwind-merge": "^3.3.1", "three": "^0.178.0", - "tw-animate-css": "^1.3.4" + "tw-animate-css": "^1.3.7" }, "devDependencies": { "@eslint/eslintrc": "^3.3.1", - "@tailwindcss/postcss": "^4.1.10", - "@types/bun": "^1.2.18", - "@types/node": "^20.19.1", - "@types/react": "^19.1.9", + "@tailwindcss/postcss": "^4.1.12", + "@types/bun": "^1.2.20", + "@types/node": "^20.19.11", + "@types/react": "^19.1.10", "@types/react-dom": "^19.1.7", "autoprefixer": "^10.4.21", - "dotenv": "^16.3.1", + "dotenv": "^16.6.1", "drizzle-kit": "^0.31.4", - "eslint": "^9.29.0", + "eslint": "^9.33.0", "eslint-config-next": "15.3.0", "postcss": "^8.5.6", - "tailwindcss": "^4.1.10", + "tailwindcss": "^4.1.12", "ts-node": "^10.9.2", - "typescript": "^5.8.3" + "typescript": "^5.9.2" } } diff --git a/translations/en.json b/translations/en.json index 566f638..98e2422 100644 --- a/translations/en.json +++ b/translations/en.json @@ -177,8 +177,8 @@ "simRacing": "Red Bull Sim Racing", "fighting": "Fighting Games Area" }, - "hide": "Hide", - "show": "Show" + "hide": "Hide walls", + "show": "Show walls" }, "rules": { "title": "Rules", diff --git a/translations/et.json b/translations/et.json index 7c1818e..e5c7d53 100644 --- a/translations/et.json +++ b/translations/et.json @@ -177,8 +177,8 @@ "simRacing": "Red Bull Sim Racing", "fighting": "Võitlusmängu ala" }, - "hide": "Peida", - "show": "Näita" + "hide": "Peida seinad", + "show": "Näita seinu" }, "rules": { "title": "Reeglid", From 4f9a5812b55b08a6ebaf0f9fbf0a77d9a1147424 Mon Sep 17 00:00:00 2001 From: v4ltages Date: Mon, 25 Aug 2025 23:38:51 +0300 Subject: [PATCH 4/4] Add entrance hall to expo area (3d model made by v4ltages) --- public/spaces/fuajeeTalTech.glb | Bin 0 -> 11336 bytes src/app/[locale]/messiala/page.tsx | 714 +++++++++++++++++++++++------ src/components/ui/skeleton.tsx | 13 + translations/en.json | 13 +- translations/et.json | 13 +- 5 files changed, 619 insertions(+), 134 deletions(-) create mode 100644 public/spaces/fuajeeTalTech.glb create mode 100644 src/components/ui/skeleton.tsx diff --git a/public/spaces/fuajeeTalTech.glb b/public/spaces/fuajeeTalTech.glb new file mode 100644 index 0000000000000000000000000000000000000000..04d3effb55120ddcf7e491061590b053aaa8dc1d GIT binary patch literal 11336 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 IC($?YA?Knn{r~^~ literal 0 HcmV?d00001 diff --git a/src/app/[locale]/messiala/page.tsx b/src/app/[locale]/messiala/page.tsx index 782ac79..3000e55 100644 --- a/src/app/[locale]/messiala/page.tsx +++ b/src/app/[locale]/messiala/page.tsx @@ -2,6 +2,7 @@ import { vipnagorgialla } from "@/components/Vipnagorgialla"; import * as THREE from "three"; +import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; import { useEffect, useRef, useState, useMemo } from "react"; import { EyeClosed, Eye } from "lucide-react"; import SectionDivider from "@/components/SectionDivider"; @@ -10,6 +11,7 @@ import { useTranslations } from "next-intl"; // Define interface for the ref with toggle function interface MountRefCurrent extends HTMLDivElement { toggleDividers?: (show: boolean) => void; + switchView?: (view: "tudengimaja" | "fuajee") => void; } export default function Expo() { @@ -17,6 +19,10 @@ export default function Expo() { const [hoveredRoom, setHoveredRoom] = useState(null); const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 }); const [showDividers, setShowDividers] = useState(true); + const [currentView, setCurrentView] = useState<"tudengimaja" | "fuajee">( + "tudengimaja", + ); + const currentViewRef = useRef<"tudengimaja" | "fuajee">("tudengimaja"); const t = useTranslations(); // Define room names with translations @@ -29,6 +35,15 @@ export default function Expo() { fighting: t("expo.areas.fighting"), lvlup: "LVLup!", redbull: "Red Bull", + // fuajee rooms + ityk: t("expo.areas.ityk"), + estoniagamedev: t("expo.areas.estoniagamedev"), + info: t("expo.areas.info"), + tartuyk: t("expo.areas.tartuyk"), + tly: t("expo.areas.tly"), + gameup: "GameUP!", + ittk: t("expo.areas.ittk"), + photobooth: t("expo.areas.photobooth"), }), [t], ); @@ -39,6 +54,10 @@ export default function Expo() { // Copy ref to variable to avoid stale closure in cleanup const mountElement = mountRef.current; let dividersRef: THREE.Mesh[] = []; + const fuajeeMeshes: THREE.Mesh[] = []; + let tudengimajaObjects: THREE.Object3D[] = []; + let fuajeeMesh: THREE.Group | null = null; + const fuajeeRooms: THREE.Mesh[] = []; // Scene setup const scene = new THREE.Scene(); @@ -62,7 +81,7 @@ export default function Expo() { // Isometric camera setup with responsive sizing const aspect = width / height; const baseFrustumSize = 14; - const frustumSize = width < 600 ? baseFrustumSize * 0.8 : baseFrustumSize; // Smaller frustum for mobile + const frustumSize = baseFrustumSize; // Keep consistent frustum size const camera = new THREE.OrthographicCamera( (frustumSize * aspect) / -2, (frustumSize * aspect) / 2, @@ -72,9 +91,21 @@ export default function Expo() { 1000, ); - // Position camera for isometric view - camera.position.set(10, 10, 14); - camera.lookAt(-1.4, 0, 0); + // Camera positions for different views + const cameraPositions = { + tudengimaja: { + position: new THREE.Vector3(10, 10, 14), + lookAt: new THREE.Vector3(-1.4, 0, 0), + }, + fuajee: { + position: new THREE.Vector3(30, 20, 15), + lookAt: new THREE.Vector3(0, 0, 0), + }, + }; + + // Position camera for isometric view (default to tudengimaja) + camera.position.copy(cameraPositions.tudengimaja.position); + camera.lookAt(cameraPositions.tudengimaja.lookAt); // Renderer const renderer = new THREE.WebGLRenderer({ antialias: true }); @@ -118,6 +149,7 @@ export default function Expo() { name: string; originalColor: number; originalScale: THREE.Vector3; + view: "tudengimaja" | "fuajee"; }> = []; const dividers: THREE.Mesh[] = []; @@ -229,6 +261,7 @@ export default function Expo() { name: roomDef.name, originalColor: roomDef.color, originalScale: room.scale.clone(), + view: "tudengimaja", }); }); @@ -283,14 +316,168 @@ export default function Expo() { ground2.receiveShadow = true; scene.add(ground2); + // Store tudengimaja objects (rooms, ground, dividers) + tudengimajaObjects = [...rooms, ground, ground2, ...dividers]; + + // Load fuajee GLTF model + const loader = new GLTFLoader(); + loader.load( + "/spaces/fuajeeTalTech.glb", + (gltf) => { + fuajeeMesh = gltf.scene; + fuajeeMesh.position.set(-1.5, 1, 0); + fuajeeMesh.scale.set(0.3, 0.3, 0.3); + fuajeeMesh.visible = false; // Initially hidden + + // Traverse the model to collect meshes + fuajeeMesh.traverse((child) => { + if (child instanceof THREE.Mesh) { + child.castShadow = true; + child.receiveShadow = true; + fuajeeMeshes.push(child); + } + }); + + scene.add(fuajeeMesh); + + // Create example rooms for fuajee after the model loads + createfuajeeRooms(); + }, + (progress) => { + console.log( + "Loading progress:", + (progress.loaded / progress.total) * 100 + "%", + ); + }, + (error) => { + console.error("Error loading GLTF:", error); + }, + ); + + // Function to create example rooms for fuajee + const createfuajeeRooms = () => { + const fuajeeRoomColors = [ + 0x7b1642, // ITÜK - Cherry Red + 0x365591, // Light Blue - Tartu Ülikool + 0xa82838, // Red - Tallinna Ülikool + 0x183bbf, // Dark Blue - Eesti Gamedev + 0xd12e7d, // Purple - Taltech + 0x228b22, // Green - GameUP + 0xff6347, // Orange - Info + 0x20b2aa, // Light Sea Green - Photobooth + ]; + + const fuajeeRoomDefinitions = [ + { + width: 5, + height: 0.5, + depth: 3.5, + x: -6, + z: 2.8, + color: fuajeeRoomColors[0], + name: roomNames.ityk, + }, + { + width: 5, + height: 0.5, + depth: 2, + x: 2.2, + z: -1.5, + color: fuajeeRoomColors[1], + name: roomNames.tartuyk, + }, + { + width: 6, + height: 0.5, + depth: 2, + x: -5.8, + z: -1.2, + color: fuajeeRoomColors[3], + name: roomNames.estoniagamedev, + }, + { + width: 2, + height: 0.5, + depth: 2, + x: -1.5, + z: -1.5, + color: fuajeeRoomColors[6], + name: roomNames.info, + }, + { + width: 2, + height: 0.5, + depth: 1.5, + x: 6, + z: -1.7, + color: fuajeeRoomColors[2], + name: roomNames.tly, + }, + { + width: 2, + height: 0.5, + depth: 1.5, + x: 11, + z: -1.7, + color: fuajeeRoomColors[4], + name: roomNames.ittk, + }, + { + width: 2, + height: 0.5, + depth: 1.5, + x: 13.5, + z: -1.7, + color: fuajeeRoomColors[7], + name: roomNames.photobooth, + }, + { + width: 2, + height: 0.5, + depth: 1.5, + x: 8.5, + z: -1.7, + color: fuajeeRoomColors[5], + name: roomNames.gameup, + }, + ]; + + fuajeeRoomDefinitions.forEach((roomDef) => { + const geometry = new THREE.BoxGeometry( + roomDef.width, + roomDef.height, + roomDef.depth, + ); + const material = new THREE.MeshLambertMaterial({ + color: roomDef.color, + }); + + const room = new THREE.Mesh(geometry, material); + room.position.set(roomDef.x, roomDef.height / 2 + 2, roomDef.z); + room.castShadow = true; + room.receiveShadow = true; + room.userData = { name: roomDef.name, originalColor: roomDef.color }; + room.visible = false; // Initially hidden + + scene.add(room); + fuajeeRooms.push(room); + roomData.push({ + mesh: room, + name: roomDef.name, + originalColor: roomDef.color, + originalScale: room.scale.clone(), + view: "fuajee", + }); + }); + }; + // Resize handler const handleResize = () => { const { width: newWidth, height: newHeight } = getResponsiveDimensions(); // Update camera const newAspect = newWidth / newHeight; - const newFrustumSize = - newWidth < 600 ? baseFrustumSize * 0.8 : baseFrustumSize; + const newFrustumSize = baseFrustumSize; camera.left = (newFrustumSize * newAspect) / -2; camera.right = (newFrustumSize * newAspect) / 2; @@ -314,11 +501,121 @@ export default function Expo() { // Update mouse position for tooltip setMousePosition({ x: event.clientX, y: event.clientY }); - // Update raycaster - raycaster.setFromCamera(mouse, camera); - const intersects = raycaster.intersectObjects(rooms); + // Handle mouse interactions based on current view + if (currentViewRef.current === "tudengimaja") { + // Update raycaster + raycaster.setFromCamera(mouse, camera); + const intersects = raycaster.intersectObjects(rooms); + + // Reset all tudengimaja rooms to original state + roomData + .filter((r) => r.view === "tudengimaja") + .forEach(({ mesh, originalColor, originalScale }) => { + (mesh.material as THREE.MeshLambertMaterial).color.setHex( + originalColor, + ); + mesh.scale.copy(originalScale); + }); + + if (intersects.length > 0) { + const hoveredMesh = intersects[0].object as THREE.Mesh; + const roomInfo = roomData.find((r) => r.mesh === hoveredMesh); + + if (roomInfo) { + // Apply hover effects + (hoveredMesh.material as THREE.MeshLambertMaterial).color.setHex( + 0xffffff, + ); + hoveredMesh.scale.multiplyScalar(1.02); + setHoveredRoom(roomInfo.name); + } + } else { + setHoveredRoom(null); + } + } else if (currentViewRef.current === "fuajee") { + // Update raycaster for fuajee rooms + raycaster.setFromCamera(mouse, camera); + const intersects = raycaster.intersectObjects(fuajeeRooms); + + // Reset all fuajee rooms to original state + roomData + .filter((r) => r.view === "fuajee") + .forEach(({ mesh, originalColor, originalScale }) => { + (mesh.material as THREE.MeshLambertMaterial).color.setHex( + originalColor, + ); + + mesh.scale.copy(originalScale); + }); + + if (intersects.length > 0) { + const hoveredMesh = intersects[0].object as THREE.Mesh; + const roomInfo = roomData.find((r) => r.mesh === hoveredMesh); + + if (roomInfo) { + // Apply hover effects with better visibility + (hoveredMesh.material as THREE.MeshLambertMaterial).color.setHex( + 0xffffff, + ); + + hoveredMesh.scale.multiplyScalar(1.1); + setHoveredRoom(roomInfo.name); + } + } else { + setHoveredRoom(null); + } + } else { + setHoveredRoom(null); + } + }; + + // Add mouse event listener + renderer.domElement.addEventListener("mousemove", onMouseMove); + + // Function to switch camera views + const switchView = (view: "tudengimaja" | "fuajee") => { + const targetPosition = cameraPositions[view].position; + const targetLookAt = cameraPositions[view].lookAt; + + // Animate camera transition + const startPosition = camera.position.clone(); + const startLookAt = new THREE.Vector3(); + camera.getWorldDirection(startLookAt); + startLookAt.multiplyScalar(-1).add(camera.position); + + let progress = 0; + const animateCamera = () => { + progress += 0.05; + if (progress >= 1) { + progress = 1; + } + + // Smooth interpolation + const easeProgress = 1 - Math.cos(progress * Math.PI * 0.5); + + camera.position.lerpVectors( + startPosition, + targetPosition, + easeProgress, + ); + const currentLookAt = new THREE.Vector3().lerpVectors( + startLookAt, + targetLookAt, + easeProgress, + ); + camera.lookAt(currentLookAt); + + if (progress < 1) { + requestAnimationFrame(animateCamera); + } + }; + + animateCamera(); - // Reset all rooms to original state + // Reset hover state when switching views + setHoveredRoom(null); + + // Reset all room states to original roomData.forEach(({ mesh, originalColor, originalScale }) => { (mesh.material as THREE.MeshLambertMaterial).color.setHex( originalColor, @@ -326,38 +623,48 @@ export default function Expo() { mesh.scale.copy(originalScale); }); - if (intersects.length > 0) { - const hoveredMesh = intersects[0].object as THREE.Mesh; - const roomInfo = roomData.find((r) => r.mesh === hoveredMesh); - - if (roomInfo) { - // Apply hover effects - (hoveredMesh.material as THREE.MeshLambertMaterial).color.setHex( - 0xffffff, - ); - hoveredMesh.scale.multiplyScalar(1.02); - setHoveredRoom(roomInfo.name); + // Toggle visibility of objects based on view + if (view === "fuajee") { + tudengimajaObjects.forEach((obj) => (obj.visible = false)); + if (fuajeeMesh) { + fuajeeMesh.visible = true; } + fuajeeRooms.forEach((room) => (room.visible = true)); } else { - setHoveredRoom(null); + tudengimajaObjects.forEach((obj) => (obj.visible = true)); + if (fuajeeMesh) { + fuajeeMesh.visible = false; + } + fuajeeRooms.forEach((room) => (room.visible = false)); + // Re-apply divider visibility state + if (mountElement.toggleDividers) { + mountElement.toggleDividers(showDividers); + } } }; - // Add mouse event listener - renderer.domElement.addEventListener("mousemove", onMouseMove); - // Animation loop const animate = () => { requestAnimationFrame(animate); // Gentle floating animation for rooms - rooms.forEach((room, index) => { - const originalY = 0.25; // height / 2 for the room height of 0.5 - const baseY = originalY + Math.sin(Date.now() * 0.001 + index) * 0.05; - - // Maintain current scale while updating Y position - room.position.y = baseY; - }); + if (currentViewRef.current === "tudengimaja") { + rooms.forEach((room, index) => { + const originalY = 0.25; // height / 2 for the room height of 0.5 + const baseY = originalY + Math.sin(Date.now() * 0.001 + index) * 0.05; + + // Maintain current scale while updating Y position + room.position.y = baseY; + }); + } else if (currentViewRef.current === "fuajee") { + fuajeeRooms.forEach((room, index) => { + const originalY = 2.25; // height / 2 for the room height of 0.5 + 2 offset + const baseY = originalY + Math.sin(Date.now() * 0.001 + index) * 0.05; + + // Maintain current scale while updating Y position + room.position.y = baseY; + }); + } renderer.render(scene, camera); }; @@ -374,8 +681,9 @@ export default function Expo() { }); }; - // Expose toggle function to parent scope + // Expose functions to parent scope mountElement.toggleDividers = toggleDividers; + mountElement.switchView = switchView; // Cleanup return () => { @@ -395,6 +703,16 @@ export default function Expo() { } }, [showDividers]); + // Handle view switching + const handleViewSwitch = (view: "tudengimaja" | "fuajee") => { + setCurrentView(view); + currentViewRef.current = view; // Update ref immediately + setHoveredRoom(null); // Clear any existing hover state + if (mountRef.current?.switchView) { + mountRef.current.switchView(view); + } + }; + return (
@@ -405,112 +723,248 @@ export default function Expo() {

- {t("schedule.locations.studentHouse")} + {currentView === "tudengimaja" + ? t("schedule.locations.studentHouse") + : t("schedule.locations.entranceHall")}

-
-
-
- - {t("expo.areas.bar")} - -
-
-
- - EVAL - -
-
-
- - {t("expo.areas.boardGames")} - -
-
-
- - LVLup! - -
-
-
- - Red Bull - -
-
-
- - {t("expo.areas.simRacing")} - -
-
-
- - Sony - + + {currentView === "tudengimaja" && ( +
+
+
+ + {t("expo.areas.bar")} + +
+
+
+ + EVAL + +
+
+
+ + {t("expo.areas.boardGames")} + +
+
+
+ + LVLup! + +
+
+
+ + Red Bull + +
+
+
+ + {t("expo.areas.simRacing")} + +
+
+
+ + Sony + +
+
+
+ + {t("expo.areas.fighting")} + +
-
-
- - {t("expo.areas.fighting")} - + )} + + {currentView === "fuajee" && ( +
+
+
+ + {t("expo.areas.ityk")} + +
+
+
+ + {t("expo.areas.tartuyk")} + +
+
+
+ + {t("expo.areas.estoniagamedev")} + +
+
+
+ + {t("expo.areas.tly")} + +
+
+
+ + {t("expo.areas.ittk")} + +
+
+
+ + {t("expo.areas.info")} + +
+
+
+ + {t("expo.areas.gameup")} + +
+
+
+ + {t("expo.areas.photobooth")} + +
-
+ )} +
-
-
- )} - {showDividers ? t("expo.hide") : t("expo.show")} - + {/* Right Arrow - Only show when on tudengimaja to go to fuajee */} + {currentView === "tudengimaja" && ( + + )} + + {currentView === "tudengimaja" && ( + + )} +
- {/* Tooltip */} - {hoveredRoom && ( -
- {hoveredRoom} -
- )} + {/* Tooltip - only show for current view */} + {hoveredRoom && + ((currentView === "tudengimaja" && + [ + roomNames.boardGames, + roomNames.bar, + roomNames.eval, + roomNames.simRacing, + roomNames.fighting, + roomNames.lvlup, + roomNames.redbull, + ].includes(hoveredRoom)) || + (currentView === "fuajee" && + [ + roomNames.ityk, + roomNames.tartuyk, + roomNames.estoniagamedev, + roomNames.info, + roomNames.tly, + roomNames.ittk, + roomNames.photobooth, + roomNames.gameup, + ].includes(hoveredRoom))) && ( +
+ {hoveredRoom} +
+ )}
diff --git a/src/components/ui/skeleton.tsx b/src/components/ui/skeleton.tsx new file mode 100644 index 0000000..32ea0ef --- /dev/null +++ b/src/components/ui/skeleton.tsx @@ -0,0 +1,13 @@ +import { cn } from "@/lib/utils" + +function Skeleton({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { Skeleton } diff --git a/translations/en.json b/translations/en.json index 98e2422..6b96725 100644 --- a/translations/en.json +++ b/translations/en.json @@ -146,7 +146,8 @@ "registrationSetup": "Registration and setup in auditorium", "auditorium": "Auditorium", "studentHouse": "Student House (Tudengimaja)", - "auditoriumAndStudentHouse": "Auditorium and Student House" + "auditoriumAndStudentHouse": "Auditorium and Student House", + "entranceHall": "Entrance Hall" } }, "stream": { @@ -175,7 +176,15 @@ "bar": "Bar Area", "boardGames": "Board Games Area", "simRacing": "Red Bull Sim Racing", - "fighting": "Fighting Games Area" + "fighting": "Fighting Games Area", + "photobooth": "Photo booth", + "ityk": "TalTech IT Faculty Student Council", + "tartuyk": "Tartu University", + "estoniagamedev": "Estonia Gamedev", + "info": "Information booth", + "tly": "Tallinn University", + "ittk": "TalTech School of Information Technologies", + "gameup": "GameUP!" }, "hide": "Hide walls", "show": "Show walls" diff --git a/translations/et.json b/translations/et.json index e5c7d53..9269bb7 100644 --- a/translations/et.json +++ b/translations/et.json @@ -146,7 +146,8 @@ "registrationSetup": "Registreerimine ja setup aulas", "auditorium": "Aula", "studentHouse": "Tudengimaja", - "auditoriumAndStudentHouse": "Aula ja Tudengimaja" + "auditoriumAndStudentHouse": "Aula ja Tudengimaja", + "entranceHall": "Fuajee" } }, "stream": { @@ -175,7 +176,15 @@ "bar": "Baariala", "boardGames": "Lauamängude ala", "simRacing": "Red Bull Sim Racing", - "fighting": "Võitlusmängu ala" + "fighting": "Võitlusmängu ala", + "photobooth": "Fotoboks", + "ityk": "IT-teaduskonna üliõpilaskogu", + "tartuyk": "Tartu Ülikool", + "estoniagamedev": "Eesti Gamedev", + "info": "Infoboks", + "tly": "Tallinna Ülikool", + "ittk": "TalTech IT-Teaduskond", + "gameup": "GameUP!" }, "hide": "Peida seinad", "show": "Näita seinu"