mirror of
https://github.com/Lapikud/tipilan.git
synced 2026-03-23 21:34:21 +00:00
Messiala & stream
This commit is contained in:
@@ -1,7 +1,24 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
async headers() {
|
||||
return [
|
||||
{
|
||||
source: "/(.*)",
|
||||
headers: [
|
||||
{
|
||||
key: "Content-Security-Policy",
|
||||
value:
|
||||
"frame-src 'self' https://player.twitch.tv https://embed.twitch.tv; frame-ancestors 'self';",
|
||||
},
|
||||
{
|
||||
key: "X-Frame-Options",
|
||||
value: "SAMEORIGIN",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
@@ -1,485 +1,499 @@
|
||||
"use client";
|
||||
|
||||
import {vipnagorgialla} from "@/components/Vipnagorgialla";
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import * as THREE from "three";
|
||||
import {useEffect, useRef, useState} from "react";
|
||||
import {EyeClosed, Eye} from "lucide-react";
|
||||
import SectionDivider from "@/components/SectionDivider";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { EyeClosed, Eye } from "lucide-react";
|
||||
|
||||
// Define interface for the ref with toggle function
|
||||
interface MountRefCurrent extends HTMLDivElement {
|
||||
toggleDividers?: (show: boolean) => void;
|
||||
toggleDividers?: (show: boolean) => void;
|
||||
}
|
||||
|
||||
export default function Expo() {
|
||||
const mountRef = useRef<MountRefCurrent | null>(null);
|
||||
const [hoveredRoom, setHoveredRoom] = useState<string | null>(null);
|
||||
const [mousePosition, setMousePosition] = useState({x: 0, y: 0});
|
||||
const [showDividers, setShowDividers] = useState<boolean>(true);
|
||||
const mountRef = useRef<MountRefCurrent | null>(null);
|
||||
const [hoveredRoom, setHoveredRoom] = useState<string | null>(null);
|
||||
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
|
||||
const [showDividers, setShowDividers] = useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (!mountRef.current) return;
|
||||
useEffect(() => {
|
||||
if (!mountRef.current) return;
|
||||
|
||||
// Copy ref to variable to avoid stale closure in cleanup
|
||||
const mountElement = mountRef.current;
|
||||
let dividersRef: THREE.Mesh[] = [];
|
||||
// Copy ref to variable to avoid stale closure in cleanup
|
||||
const mountElement = mountRef.current;
|
||||
let dividersRef: THREE.Mesh[] = [];
|
||||
|
||||
// Scene setup
|
||||
const scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color(0x0e0f19);
|
||||
// Scene setup
|
||||
const scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color(0x0e0f19);
|
||||
|
||||
// Get responsive dimensions
|
||||
const getResponsiveDimensions = () => {
|
||||
const container = mountRef.current;
|
||||
if (!container) return {width: 800, height: 600};
|
||||
// Get responsive dimensions
|
||||
const getResponsiveDimensions = () => {
|
||||
const container = mountRef.current;
|
||||
if (!container) return { width: 800, height: 600 };
|
||||
|
||||
const containerWidth = container.offsetWidth;
|
||||
const maxWidth = Math.min(containerWidth, 800);
|
||||
const width = Math.max(maxWidth, 300); // Minimum width
|
||||
const height = (width * 600) / 800; // Maintain aspect ratio
|
||||
const containerWidth = container.offsetWidth;
|
||||
const maxWidth = Math.min(containerWidth, 800);
|
||||
const width = Math.max(maxWidth, 300); // Minimum width
|
||||
const height = (width * 600) / 800; // Maintain aspect ratio
|
||||
|
||||
return {width, height};
|
||||
};
|
||||
return { width, height };
|
||||
};
|
||||
|
||||
const {width, height} = getResponsiveDimensions();
|
||||
const { width, height } = getResponsiveDimensions();
|
||||
|
||||
// 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 camera = new THREE.OrthographicCamera(
|
||||
(frustumSize * aspect) / -2,
|
||||
(frustumSize * aspect) / 2,
|
||||
frustumSize / 2,
|
||||
frustumSize / -2,
|
||||
1,
|
||||
1000,
|
||||
// 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 camera = new THREE.OrthographicCamera(
|
||||
(frustumSize * aspect) / -2,
|
||||
(frustumSize * aspect) / 2,
|
||||
frustumSize / 2,
|
||||
frustumSize / -2,
|
||||
1,
|
||||
1000,
|
||||
);
|
||||
|
||||
// Position camera for isometric view
|
||||
camera.position.set(10, 10, 14);
|
||||
camera.lookAt(-1.4, 0, 0);
|
||||
|
||||
// Renderer
|
||||
const renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||
renderer.setSize(width, height);
|
||||
renderer.shadowMap.enabled = true;
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
||||
mountElement.appendChild(renderer.domElement);
|
||||
|
||||
// Raycaster for mouse interactions
|
||||
const raycaster = new THREE.Raycaster();
|
||||
const mouse = new THREE.Vector2();
|
||||
|
||||
// Lighting
|
||||
const ambientLight = new THREE.AmbientLight(0x404040, 1.2);
|
||||
scene.add(ambientLight);
|
||||
|
||||
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5);
|
||||
directionalLight.position.set(10, 10, 5);
|
||||
directionalLight.castShadow = false;
|
||||
directionalLight.shadow.mapSize.width = 2048;
|
||||
directionalLight.shadow.mapSize.height = 2048;
|
||||
scene.add(directionalLight);
|
||||
|
||||
// Room colors and names
|
||||
const roomColors = [
|
||||
0x343434, // Gray - Lauamängude ala
|
||||
0x4ecdc4, // Turquoise - Baariala
|
||||
0xffe66d, // Yellow - EVAL
|
||||
0xff6600, // Orange - Redbull Sim Racing
|
||||
0xff1493, // Deep Pink - Võitlusmängu ala
|
||||
0x3498db, // Blue - Sony
|
||||
0x2ecc71, // Green - Lava
|
||||
0x080682, // Dark Blue - LVLup!
|
||||
0xc02841, // Red - RedBull
|
||||
];
|
||||
|
||||
// Create individual rooms as rectangles with custom positions
|
||||
const rooms: THREE.Mesh[] = [];
|
||||
const roomData: Array<{
|
||||
mesh: THREE.Mesh;
|
||||
name: string;
|
||||
originalColor: number;
|
||||
originalScale: THREE.Vector3;
|
||||
}> = [];
|
||||
const dividers: THREE.Mesh[] = [];
|
||||
|
||||
// Define rooms with custom positions, sizes and colors
|
||||
const roomDefinitions = [
|
||||
{
|
||||
width: 7,
|
||||
height: 0.7,
|
||||
depth: 3,
|
||||
x: 2.5,
|
||||
z: 4,
|
||||
color: roomColors[0],
|
||||
name: "Lauamängude ala",
|
||||
},
|
||||
{
|
||||
width: 3.5,
|
||||
height: 0.7,
|
||||
depth: 1.2,
|
||||
x: 0.7,
|
||||
z: -0.3,
|
||||
color: roomColors[1],
|
||||
name: "Baariala",
|
||||
},
|
||||
{
|
||||
width: 1.8,
|
||||
height: 0.7,
|
||||
depth: 1.5,
|
||||
x: 1,
|
||||
z: -3.5,
|
||||
color: roomColors[2],
|
||||
name: "EVAL",
|
||||
},
|
||||
{
|
||||
width: 2,
|
||||
height: 0.7,
|
||||
depth: 4.5,
|
||||
x: 5.2,
|
||||
z: -2,
|
||||
color: roomColors[3],
|
||||
name: "Red Bull Sim Racing",
|
||||
},
|
||||
{
|
||||
width: 3,
|
||||
height: 0.7,
|
||||
depth: 1.5,
|
||||
x: -1.7,
|
||||
z: -3.5,
|
||||
color: roomColors[4],
|
||||
name: "Võitlusmängu ala",
|
||||
},
|
||||
// {
|
||||
// width: 1.8,
|
||||
// height: 0.7,
|
||||
// depth: 1.5,
|
||||
// x: -4.3,
|
||||
// z: -3.5,
|
||||
// color: roomColors[5],
|
||||
// name: "Sony",
|
||||
// },
|
||||
{
|
||||
width: 3,
|
||||
height: 0.7,
|
||||
depth: 1.7,
|
||||
x: -3.5,
|
||||
z: -0.5,
|
||||
color: roomColors[7],
|
||||
name: "LVLup!",
|
||||
},
|
||||
//{
|
||||
// width: 2,
|
||||
// height: 0.7,
|
||||
// depth: 4,
|
||||
// x: -6.4,
|
||||
// z: -2.3,
|
||||
// color: roomColors[6],
|
||||
// name: "Lava",
|
||||
//},
|
||||
{
|
||||
width: 1.8,
|
||||
height: 0.7,
|
||||
depth: 1.5,
|
||||
x: 3,
|
||||
z: -3.5,
|
||||
color: roomColors[8],
|
||||
name: "Red Bull",
|
||||
},
|
||||
];
|
||||
|
||||
roomDefinitions.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, roomDef.z);
|
||||
room.castShadow = true;
|
||||
room.receiveShadow = true;
|
||||
room.userData = { name: roomDef.name, originalColor: roomDef.color };
|
||||
|
||||
scene.add(room);
|
||||
rooms.push(room);
|
||||
roomData.push({
|
||||
mesh: room,
|
||||
name: roomDef.name,
|
||||
originalColor: roomDef.color,
|
||||
originalScale: room.scale.clone(),
|
||||
});
|
||||
});
|
||||
|
||||
// Create toggleable room dividers
|
||||
const createTogglableDivider = (
|
||||
width: number,
|
||||
height: number,
|
||||
depth: number,
|
||||
x: number,
|
||||
z: number,
|
||||
) => {
|
||||
const wallGeometry = new THREE.BoxGeometry(width, height, depth);
|
||||
const wallMaterial = new THREE.MeshLambertMaterial({
|
||||
color: 0x555555,
|
||||
transparent: true,
|
||||
opacity: 0,
|
||||
});
|
||||
|
||||
const wall = new THREE.Mesh(wallGeometry, wallMaterial);
|
||||
wall.position.set(x, height / 2, z);
|
||||
wall.visible = false;
|
||||
scene.add(wall);
|
||||
dividers.push(wall);
|
||||
};
|
||||
|
||||
// Add strategic dividers between major areas
|
||||
createTogglableDivider(10, 2, 2, -2.5, 1.5); // Wall between main entrance
|
||||
createTogglableDivider(2, 2, 2, 5.5, 1.5); // Wall right next to Lauamängud & Redbull Sim Racing
|
||||
|
||||
// Store dividers reference for later access
|
||||
dividersRef = [...dividers];
|
||||
|
||||
// Ground plane
|
||||
const groundGeometry = new THREE.PlaneGeometry(14, 10.5);
|
||||
const groundMaterial = new THREE.MeshLambertMaterial({ color: 0xcccccc });
|
||||
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
|
||||
ground.rotation.x = -Math.PI / 2;
|
||||
ground.position.x = -1.1;
|
||||
ground.position.y = -0.5;
|
||||
ground.receiveShadow = true;
|
||||
scene.add(ground);
|
||||
|
||||
// Second ground plane
|
||||
const groundGeometry2 = new THREE.PlaneGeometry(2, 7);
|
||||
const groundMaterial2 = new THREE.MeshLambertMaterial({
|
||||
color: 0xcccccc,
|
||||
});
|
||||
const ground2 = new THREE.Mesh(groundGeometry2, groundMaterial2);
|
||||
ground2.rotation.x = -Math.PI / 2;
|
||||
ground2.position.x = -12.2;
|
||||
ground2.position.y = -5;
|
||||
ground2.receiveShadow = true;
|
||||
scene.add(ground2);
|
||||
|
||||
// Resize handler
|
||||
const handleResize = () => {
|
||||
const { width: newWidth, height: newHeight } = getResponsiveDimensions();
|
||||
|
||||
// Update camera
|
||||
const newAspect = newWidth / newHeight;
|
||||
const newFrustumSize =
|
||||
newWidth < 600 ? baseFrustumSize * 0.8 : baseFrustumSize;
|
||||
|
||||
camera.left = (newFrustumSize * newAspect) / -2;
|
||||
camera.right = (newFrustumSize * newAspect) / 2;
|
||||
camera.top = newFrustumSize / 2;
|
||||
camera.bottom = newFrustumSize / -2;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
// Update renderer
|
||||
renderer.setSize(newWidth, newHeight);
|
||||
};
|
||||
|
||||
// Add resize event listener
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
||||
// Mouse event handlers
|
||||
const onMouseMove = (event: MouseEvent) => {
|
||||
const rect = renderer.domElement.getBoundingClientRect();
|
||||
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
|
||||
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
|
||||
|
||||
// Update mouse position for tooltip
|
||||
setMousePosition({ x: event.clientX, y: event.clientY });
|
||||
|
||||
// Update raycaster
|
||||
raycaster.setFromCamera(mouse, camera);
|
||||
const intersects = raycaster.intersectObjects(rooms);
|
||||
|
||||
// Reset all rooms to original state
|
||||
roomData.forEach(({ mesh, originalColor, originalScale }) => {
|
||||
(mesh.material as THREE.MeshLambertMaterial).color.setHex(
|
||||
originalColor,
|
||||
);
|
||||
mesh.scale.copy(originalScale);
|
||||
});
|
||||
|
||||
// Position camera for isometric view
|
||||
camera.position.set(10, 10, 14);
|
||||
camera.lookAt(-1.4, 0, 0);
|
||||
if (intersects.length > 0) {
|
||||
const hoveredMesh = intersects[0].object as THREE.Mesh;
|
||||
const roomInfo = roomData.find((r) => r.mesh === hoveredMesh);
|
||||
|
||||
// Renderer
|
||||
const renderer = new THREE.WebGLRenderer({antialias: true});
|
||||
renderer.setSize(width, height);
|
||||
renderer.shadowMap.enabled = true;
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
||||
mountElement.appendChild(renderer.domElement);
|
||||
|
||||
// Raycaster for mouse interactions
|
||||
const raycaster = new THREE.Raycaster();
|
||||
const mouse = new THREE.Vector2();
|
||||
|
||||
// Lighting
|
||||
const ambientLight = new THREE.AmbientLight(0x404040, 1.2);
|
||||
scene.add(ambientLight);
|
||||
|
||||
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5);
|
||||
directionalLight.position.set(10, 10, 5);
|
||||
directionalLight.castShadow = false;
|
||||
directionalLight.shadow.mapSize.width = 2048;
|
||||
directionalLight.shadow.mapSize.height = 2048;
|
||||
scene.add(directionalLight);
|
||||
|
||||
// Room colors and names
|
||||
const roomColors = [
|
||||
0xff6b35, // Orange - Mänguklubi
|
||||
0x4ecdc4, // Turquoise - Baariala
|
||||
0xffe66d, // Yellow - EVAL
|
||||
0xe74c3c, // Red - Redbull
|
||||
0x9b59b6, // Purple - Võitlusmängu ala
|
||||
0x3498db, // Blue - Sony
|
||||
0x2ecc71, // Green - Chillimisala
|
||||
];
|
||||
|
||||
const roomNames = [
|
||||
"Mänguklubi",
|
||||
"Baariala",
|
||||
"EVAL",
|
||||
"Redbull",
|
||||
"Võitlusmängu ala",
|
||||
"Sony",
|
||||
"Chillimisala",
|
||||
];
|
||||
|
||||
// Create individual rooms as rectangles with custom positions
|
||||
const rooms: THREE.Mesh[] = [];
|
||||
const roomData: Array<{
|
||||
mesh: THREE.Mesh;
|
||||
name: string;
|
||||
originalColor: number;
|
||||
originalScale: THREE.Vector3;
|
||||
}> = [];
|
||||
const dividers: THREE.Mesh[] = [];
|
||||
|
||||
// Define rooms with custom positions, sizes and colors
|
||||
const roomDefinitions = [
|
||||
{
|
||||
width: 7,
|
||||
height: 0.7,
|
||||
depth: 3,
|
||||
x: 2.5,
|
||||
z: 4,
|
||||
color: roomColors[0],
|
||||
name: roomNames[0],
|
||||
}, // Mänguklubi
|
||||
// {
|
||||
// width: 2.5,
|
||||
// height: 0.7,
|
||||
// depth: 0.7,
|
||||
// x: 1,
|
||||
// z: 0,
|
||||
// color: roomColors[1],
|
||||
// name: roomNames[1],
|
||||
// }, // Baariala
|
||||
{
|
||||
width: 1.8,
|
||||
height: 0.7,
|
||||
depth: 1.5,
|
||||
x: 2.5,
|
||||
z: -3.5,
|
||||
color: roomColors[2],
|
||||
name: roomNames[2],
|
||||
}, // EVAL
|
||||
{
|
||||
width: 2.2,
|
||||
height: 0.7,
|
||||
depth: 4.5,
|
||||
x: 5,
|
||||
z: -2,
|
||||
color: roomColors[3],
|
||||
name: roomNames[3],
|
||||
}, // Redbull
|
||||
{
|
||||
width: 3,
|
||||
height: 0.7,
|
||||
depth: 1.3,
|
||||
x: 0,
|
||||
z: -3.5,
|
||||
color: roomColors[4],
|
||||
name: roomNames[4],
|
||||
}, // Võitlusmängu ala
|
||||
{
|
||||
width: 1.8,
|
||||
height: 0.7,
|
||||
depth: 1.5,
|
||||
x: -2.55,
|
||||
z: -3.5,
|
||||
color: roomColors[5],
|
||||
name: roomNames[5],
|
||||
}, // Sony
|
||||
{
|
||||
width: 4,
|
||||
height: 0.7,
|
||||
depth: 4,
|
||||
x: -5.5,
|
||||
z: -2.3,
|
||||
color: roomColors[6],
|
||||
name: roomNames[6],
|
||||
}, // Chillimisala
|
||||
];
|
||||
|
||||
roomDefinitions.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, roomDef.z);
|
||||
room.castShadow = true;
|
||||
room.receiveShadow = true;
|
||||
room.userData = {name: roomDef.name, originalColor: roomDef.color};
|
||||
|
||||
scene.add(room);
|
||||
rooms.push(room);
|
||||
roomData.push({
|
||||
mesh: room,
|
||||
name: roomDef.name,
|
||||
originalColor: roomDef.color,
|
||||
originalScale: room.scale.clone(),
|
||||
});
|
||||
});
|
||||
|
||||
// Create toggleable room dividers
|
||||
const createTogglableDivider = (
|
||||
width: number,
|
||||
height: number,
|
||||
depth: number,
|
||||
x: number,
|
||||
z: number,
|
||||
) => {
|
||||
const wallGeometry = new THREE.BoxGeometry(width, height, depth);
|
||||
const wallMaterial = new THREE.MeshLambertMaterial({
|
||||
color: 0x555555,
|
||||
transparent: true,
|
||||
opacity: 0,
|
||||
});
|
||||
|
||||
const wall = new THREE.Mesh(wallGeometry, wallMaterial);
|
||||
wall.position.set(x, height / 2, z);
|
||||
wall.visible = false;
|
||||
scene.add(wall);
|
||||
dividers.push(wall);
|
||||
};
|
||||
|
||||
// Add strategic dividers between major areas
|
||||
createTogglableDivider(10, 2, 2, -2.5, 1.5); // Wall between main entrance
|
||||
createTogglableDivider(2, 2, 2, 5.5, 1.5); // Wall right next to Mänguklubi & Redbull
|
||||
|
||||
// Store dividers reference for later access
|
||||
dividersRef = [...dividers];
|
||||
|
||||
// Ground plane
|
||||
const groundGeometry = new THREE.PlaneGeometry(14, 10.5);
|
||||
const groundMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc});
|
||||
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
|
||||
ground.rotation.x = -Math.PI / 2;
|
||||
ground.position.x = -1.1;
|
||||
ground.position.y = -0.5;
|
||||
ground.receiveShadow = true;
|
||||
scene.add(ground);
|
||||
|
||||
// Second ground plane
|
||||
const groundGeometry2 = new THREE.PlaneGeometry(2, 7);
|
||||
const groundMaterial2 = new THREE.MeshLambertMaterial({
|
||||
color: 0xcccccc,
|
||||
});
|
||||
const ground2 = new THREE.Mesh(groundGeometry2, groundMaterial2);
|
||||
ground2.rotation.x = -Math.PI / 2;
|
||||
ground2.position.x = -12.2;
|
||||
ground2.position.y = -5;
|
||||
ground2.receiveShadow = true;
|
||||
scene.add(ground2);
|
||||
|
||||
// Resize handler
|
||||
const handleResize = () => {
|
||||
const {width: newWidth, height: newHeight} = getResponsiveDimensions();
|
||||
|
||||
// Update camera
|
||||
const newAspect = newWidth / newHeight;
|
||||
const newFrustumSize =
|
||||
newWidth < 600 ? baseFrustumSize * 0.8 : baseFrustumSize;
|
||||
|
||||
camera.left = (newFrustumSize * newAspect) / -2;
|
||||
camera.right = (newFrustumSize * newAspect) / 2;
|
||||
camera.top = newFrustumSize / 2;
|
||||
camera.bottom = newFrustumSize / -2;
|
||||
camera.updateProjectionMatrix();
|
||||
|
||||
// Update renderer
|
||||
renderer.setSize(newWidth, newHeight);
|
||||
};
|
||||
|
||||
// Add resize event listener
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
||||
// Mouse event handlers
|
||||
const onMouseMove = (event: MouseEvent) => {
|
||||
const rect = renderer.domElement.getBoundingClientRect();
|
||||
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
|
||||
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
|
||||
|
||||
// Update mouse position for tooltip
|
||||
setMousePosition({x: event.clientX, y: event.clientY});
|
||||
|
||||
// Update raycaster
|
||||
raycaster.setFromCamera(mouse, camera);
|
||||
const intersects = raycaster.intersectObjects(rooms);
|
||||
|
||||
// Reset all rooms to original state
|
||||
roomData.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);
|
||||
}
|
||||
};
|
||||
|
||||
// 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;
|
||||
});
|
||||
|
||||
renderer.render(scene, camera);
|
||||
};
|
||||
|
||||
animate();
|
||||
|
||||
// Function to toggle dividers
|
||||
const toggleDividers = (show: boolean) => {
|
||||
dividersRef.forEach((divider) => {
|
||||
divider.visible = show;
|
||||
(divider.material as THREE.MeshLambertMaterial).opacity = show
|
||||
? 0.4
|
||||
: 0;
|
||||
});
|
||||
};
|
||||
|
||||
// Expose toggle function to parent scope
|
||||
mountElement.toggleDividers = toggleDividers;
|
||||
|
||||
// Cleanup
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleResize);
|
||||
renderer.domElement.removeEventListener("mousemove", onMouseMove);
|
||||
if (mountElement && renderer.domElement) {
|
||||
mountElement.removeChild(renderer.domElement);
|
||||
}
|
||||
renderer.dispose();
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Update dividers when showDividers state changes
|
||||
useEffect(() => {
|
||||
if (mountRef.current?.toggleDividers) {
|
||||
mountRef.current.toggleDividers(showDividers);
|
||||
if (roomInfo) {
|
||||
// Apply hover effects
|
||||
(hoveredMesh.material as THREE.MeshLambertMaterial).color.setHex(
|
||||
0xffffff,
|
||||
);
|
||||
hoveredMesh.scale.multiplyScalar(1.02);
|
||||
setHoveredRoom(roomInfo.name);
|
||||
}
|
||||
}, [showDividers]);
|
||||
} else {
|
||||
setHoveredRoom(null);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex flex-col min-h-[90vh] m-6 mt-16 md:m-16">
|
||||
<h1
|
||||
className={`text-4xl md:text-5xl lg:text-6xl ${vipnagorgialla.className} font-bold italic text-[#2A2C3F] dark:text-[#EEE5E5] mt-8 md:mt-16 mb-4 uppercase`}
|
||||
>
|
||||
Messiala
|
||||
</h1>
|
||||
<div className="mb-6">
|
||||
<h2 className="text-2xl text-[#2A2C3F] dark:text-[#EEE5E5] mb-3">
|
||||
Tudengimaja
|
||||
</h2>
|
||||
<div className="flex flex-wrap gap-4 pb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-4 h-4 border border-gray-300"
|
||||
style={{backgroundColor: "#ff6b35"}}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
Mänguklubi
|
||||
</span>
|
||||
</div>
|
||||
<div className="items-center gap-2 hidden">
|
||||
<div
|
||||
className="w-4 h-4 border border-gray-300"
|
||||
style={{backgroundColor: "#4ecdc4"}}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
// 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;
|
||||
});
|
||||
|
||||
renderer.render(scene, camera);
|
||||
};
|
||||
|
||||
animate();
|
||||
|
||||
// Function to toggle dividers
|
||||
const toggleDividers = (show: boolean) => {
|
||||
dividersRef.forEach((divider) => {
|
||||
divider.visible = show;
|
||||
(divider.material as THREE.MeshLambertMaterial).opacity = show
|
||||
? 0.4
|
||||
: 0;
|
||||
});
|
||||
};
|
||||
|
||||
// Expose toggle function to parent scope
|
||||
mountElement.toggleDividers = toggleDividers;
|
||||
|
||||
// Cleanup
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleResize);
|
||||
renderer.domElement.removeEventListener("mousemove", onMouseMove);
|
||||
if (mountElement && renderer.domElement) {
|
||||
mountElement.removeChild(renderer.domElement);
|
||||
}
|
||||
renderer.dispose();
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Update dividers when showDividers state changes
|
||||
useEffect(() => {
|
||||
if (mountRef.current?.toggleDividers) {
|
||||
mountRef.current.toggleDividers(showDividers);
|
||||
}
|
||||
}, [showDividers]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col min-h-[90vh] m-6 mt-16 md:m-16">
|
||||
<h1
|
||||
className={`text-4xl md:text-5xl lg:text-6xl ${vipnagorgialla.className} font-bold italic text-[#2A2C3F] dark:text-[#EEE5E5] mt-8 md:mt-16 mb-4 uppercase`}
|
||||
>
|
||||
Messiala
|
||||
</h1>
|
||||
<div className="mb-6">
|
||||
<h2 className="text-2xl text-[#2A2C3F] dark:text-[#EEE5E5] mb-3">
|
||||
Tudengimaja
|
||||
</h2>
|
||||
<div className="flex flex-wrap gap-4 pb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-4 h-4 border border-gray-300"
|
||||
style={{ backgroundColor: "#4ecdc4" }}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
Baariala
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-4 h-4 border border-gray-300"
|
||||
style={{backgroundColor: "#ffe66d"}}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-4 h-4 border border-gray-300"
|
||||
style={{ backgroundColor: "#ffe66d" }}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
EVAL
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-4 h-4 border border-gray-300"
|
||||
style={{backgroundColor: "#e74c3c"}}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
Redbull
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-4 h-4 border border-gray-300"
|
||||
style={{ backgroundColor: "#343434" }}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
Lauamängude ala
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-4 h-4 border border-gray-300"
|
||||
style={{backgroundColor: "#9b59b6"}}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
Võitlusmängu ala
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-4 h-4 border border-gray-300"
|
||||
style={{ backgroundColor: "#080682" }}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
LVLup!
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-4 h-4 border border-gray-300"
|
||||
style={{backgroundColor: "#3498db"}}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-4 h-4 border border-gray-300"
|
||||
style={{ backgroundColor: "#C02841" }}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
Red Bull
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-4 h-4 border border-gray-300"
|
||||
style={{ backgroundColor: "#ff6600" }}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
Red Bull Sim Racing
|
||||
</span>
|
||||
</div>
|
||||
<div className="items-center gap-2 hidden">
|
||||
<div
|
||||
className="w-4 h-4 border border-gray-300"
|
||||
style={{ backgroundColor: "#3498db" }}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
Sony
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-4 h-4 border border-gray-300"
|
||||
style={{backgroundColor: "#2ecc71"}}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
Chillimisala
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-4 h-4 border border-gray-300"
|
||||
style={{ backgroundColor: "#ff1493" }}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
Võitlusmängu ala
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col lg:flex-row gap-8 items-start">
|
||||
<div className="flex-shrink-0 border-3 border-[#1F5673] w-full max-w-[800px] relative">
|
||||
<div ref={mountRef} className="w-full"/>
|
||||
<button
|
||||
onClick={() => setShowDividers(!showDividers)}
|
||||
className={`absolute top-2 right-2 px-3 py-2 bg-[#1F5673] text-white hover:bg-[#2A7A9B] ${vipnagorgialla.className} uppercase italic text-sm font-semibold flex items-center transition-colors shadow-lg z-10`}
|
||||
>
|
||||
{showDividers ? (
|
||||
<EyeClosed className="w-6 h-6 mr-2"/>
|
||||
) : (
|
||||
<Eye className="w-6 h-6 mr-2"/>
|
||||
)}
|
||||
|
||||
{showDividers ? "Peida" : "Näita"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tooltip */}
|
||||
{hoveredRoom && (
|
||||
<div
|
||||
className="fixed bg-black bg-opacity-80 text-white px-3 py-2 rounded-lg text-sm pointer-events-none z-50"
|
||||
style={{
|
||||
left: mousePosition.x + 10,
|
||||
top: mousePosition.y - 10,
|
||||
}}
|
||||
>
|
||||
{hoveredRoom}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SectionDivider />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
<div className="flex flex-col lg:flex-row gap-8 items-start">
|
||||
<div className="flex-shrink-0 border-3 border-[#1F5673] w-full max-w-[800px] relative">
|
||||
<div ref={mountRef} className="w-full" />
|
||||
<button
|
||||
onClick={() => setShowDividers(!showDividers)}
|
||||
className={`absolute top-2 right-2 px-3 py-2 bg-[#1F5673] text-white hover:bg-[#2A7A9B] ${vipnagorgialla.className} uppercase italic text-sm font-semibold flex items-center transition-colors shadow-lg z-10`}
|
||||
>
|
||||
{showDividers ? (
|
||||
<EyeClosed className="w-6 h-6 mr-2" />
|
||||
) : (
|
||||
<Eye className="w-6 h-6 mr-2" />
|
||||
)}
|
||||
|
||||
{showDividers ? "Peida" : "Näita"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tooltip */}
|
||||
{hoveredRoom && (
|
||||
<div
|
||||
className="fixed bg-black bg-opacity-80 text-white px-3 py-2 rounded-lg text-sm pointer-events-none z-50"
|
||||
style={{
|
||||
left: mousePosition.x + 10,
|
||||
top: mousePosition.y - 10,
|
||||
}}
|
||||
>
|
||||
{hoveredRoom}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
210
src/app/striim/page.tsx
Normal file
210
src/app/striim/page.tsx
Normal file
@@ -0,0 +1,210 @@
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2">
|
||||
{/* Title */}
|
||||
<div className="grid grid-cols-1 items-center justify-between mt-18 gap-12 pt-8">
|
||||
<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"
|
||||
/>
|
||||
<Link
|
||||
href="/ajakava"
|
||||
className="px-8 md:px-12 py-8 flex flex-col gap-4 border-b-3 border-t-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
|
||||
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]`}
|
||||
>
|
||||
Ajakava
|
||||
</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]">
|
||||
event_note
|
||||
</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">
|
||||
TipiLAN on pungil põnevatest turniiridest, mini-võistlustest ja
|
||||
paljust muust.
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
{/* Stream iframe from Twitch */}
|
||||
<div className="border-[#1F5673] -ml-0.75 border-l-0 md:border-l-3 border-b-3 h-full pt-0 md:pt-16">
|
||||
<iframe
|
||||
src="https://player.twitch.tv/?channel=shroud&parent=localhost&parent=tipilan.ee"
|
||||
height="100%"
|
||||
width="100%"
|
||||
className="w-full h-full min-h-[400px]"
|
||||
allow="autoplay; encrypted-media"
|
||||
></iframe>
|
||||
</div>
|
||||
</div>
|
||||
{/* Grid of buttons */}
|
||||
<div className="grid grid-cols-1 xl:grid-cols-2 border-[#1F5673]">
|
||||
<Link
|
||||
href="/turniirid"
|
||||
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
|
||||
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`}
|
||||
>
|
||||
Turniirid
|
||||
</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]">
|
||||
trophy
|
||||
</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">
|
||||
TipiLANil toimuvad suurejoonelised CS2 ja LoL turniirid, mille
|
||||
auhinnafond on 10 000€.
|
||||
</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`}
|
||||
>
|
||||
Messiala
|
||||
</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">
|
||||
TipiLANi messialal paiknevad ettevõtted, lisategevused ja toimuvad
|
||||
loengud.
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
{/* Date */}
|
||||
<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">
|
||||
Bro­neeri oma koht juba täna!
|
||||
</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]">
|
||||
24.-26. okt.
|
||||
</h2>
|
||||
</Link>
|
||||
{/* Sponsors */}
|
||||
<div
|
||||
className={`p-12 flex flex-col ${vipnagorgialla.className} font-bold italic border-b-3 border-[#1F5673]`}
|
||||
>
|
||||
<div className="text-left flex flex-col justify-between xl:justify-start">
|
||||
<h3 className="text-4xl md:text-5xl dark:text-[#EEE5E5] text-[#2A2C3F] group-hover:text-black pb-8">
|
||||
TipiLANi tõmbab käima...
|
||||
</h3>
|
||||
<div className="flex flex-row flex-wrap gap-8 md:gap-18 items-center">
|
||||
<Link href="https://taltech.ee" target="_blank">
|
||||
<Image
|
||||
src="/sponsors/taltech-color.png"
|
||||
alt="Taltech (Tallinna Tehnikaülikool)"
|
||||
width={192}
|
||||
height={192}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<Link href="https://www.redbull.com/ee-et/" target="_blank">
|
||||
<Image
|
||||
src="/sponsors/redbull.png"
|
||||
alt="Redbull"
|
||||
width={80}
|
||||
height={80}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<Link href="https://www.alecoq.ee" target="_blank">
|
||||
<Image
|
||||
src="/sponsors/alecoq.svg"
|
||||
alt="Alecoq"
|
||||
width={200}
|
||||
height={200}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<Link href="https://www.simracing.ee/" target="_blank">
|
||||
<Image
|
||||
src="/sponsors/EVAL.png"
|
||||
alt="EVAL"
|
||||
width={200}
|
||||
height={200}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<Link href="https://balsnack.ee" target="_blank">
|
||||
<Image
|
||||
src="/sponsors/balsnack.svg"
|
||||
alt="Balsnack"
|
||||
width={200}
|
||||
height={200}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<Link
|
||||
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"
|
||||
/>
|
||||
</Link>
|
||||
<Link href="https://www.facebook.com/bfglOfficial" target="_blank">
|
||||
<Image
|
||||
src="/sponsors/BFGL.png"
|
||||
alt="BFGL"
|
||||
width={192}
|
||||
height={192}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user