mirror of
https://github.com/Lapikud/tipilan.git
synced 2026-03-23 13:24:21 +00:00
Merge pull request #48 from Lapikud/development
Add English translation, schedule program
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
import type { NextConfig } from "next";
|
||||
import createNextIntlPlugin from "next-intl/plugin";
|
||||
|
||||
const withNextIntl = createNextIntlPlugin("./src/i18n/request.ts");
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
async headers() {
|
||||
@@ -21,4 +24,4 @@ const nextConfig: NextConfig = {
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
export default withNextIntl(nextConfig);
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"lucide-react": "^0.522.0",
|
||||
"material-symbols": "^0.31.8",
|
||||
"next": "15.3.0",
|
||||
"next-intl": "^4.3.4",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
|
||||
81
src/app/[locale]/ajakava/page.tsx
Normal file
81
src/app/[locale]/ajakava/page.tsx
Normal file
@@ -0,0 +1,81 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import { scheduleData } from "@/data/timetable";
|
||||
import SectionDivider from "@/components/SectionDivider";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
const tabs = Object.keys(scheduleData);
|
||||
|
||||
export default function Timetable() {
|
||||
const [activeTab, setActiveTab] = useState(tabs[0]);
|
||||
const schedule = scheduleData[activeTab];
|
||||
const t = useTranslations();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex flex-col min-h-[90vh] m-6 mt-16 md:m-16">
|
||||
<h1
|
||||
className={`text-5xl sm:text-6xl ${vipnagorgialla.className} font-bold italic uppercase text-[#2A2C3F] dark:text-[#EEE5E5] mt-8 md:mt-16 mb-8`}
|
||||
>
|
||||
{t("schedule.title")}
|
||||
</h1>
|
||||
|
||||
{/* Tab menu */}
|
||||
<div className="flex space-x-4 mb-8">
|
||||
{tabs.map((tab) => (
|
||||
<button
|
||||
key={tab}
|
||||
onClick={() => setActiveTab(tab)}
|
||||
className={`${vipnagorgialla.className} cursor-pointer uppercase italic px-4 py-2 text-lg font-semibold ${
|
||||
activeTab === tab
|
||||
? "bg-[#00A3E0] text-white"
|
||||
: "bg-[#007CAB] dark:bg-[#007CAB] text-[#EEE5E5] hover:bg-[#00A3E0] dark:hover:bg-[#007CAB]"
|
||||
} transition-colors`}
|
||||
>
|
||||
{t(`schedule.${tab}`)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Schedule entries */}
|
||||
<div className="space-y-6">
|
||||
{schedule.map((item, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className="border-l-3 border-[#007CAB] pl-4 flex flex-row flex-wrap gap-5 items-stretch"
|
||||
>
|
||||
<div
|
||||
className={`${vipnagorgialla.className} text-[#00A3E0] text-4xl font-bold italic flex-shrink-0 flex items-center justify-center`}
|
||||
style={{ width: "180px", minWidth: "180px" }}
|
||||
>
|
||||
{item.time}
|
||||
</div>
|
||||
<div
|
||||
className="flex-1 flex flex-col justify-center min-h-[120px]"
|
||||
style={{ minWidth: "0" }}
|
||||
>
|
||||
<div
|
||||
className={`${vipnagorgialla.className} text-3xl italic font-bold text-[#2A2C3F] dark:text-[#EEE5E5] text-balance`}
|
||||
>
|
||||
{t(item.titleKey)}
|
||||
</div>
|
||||
{item.description && (
|
||||
<div className="text-2xl text-[#938BA1] dark:text-[#938BA1] text-balance">
|
||||
{item.description}
|
||||
</div>
|
||||
)}
|
||||
<div className="text-2xl text-[#938BA1] dark:text-[#938BA1] text-balance">
|
||||
{t(item.locationKey)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SectionDivider />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -7,7 +7,8 @@ import { db } from "@/db/drizzle";
|
||||
// Types
|
||||
import type { TeamWithMembers, MemberWithUser } from "@/types/database";
|
||||
|
||||
import Link from "next/link";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
|
||||
// User interface
|
||||
import {
|
||||
@@ -19,19 +20,26 @@ import {
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
|
||||
// Later on we can use a i8 solution?
|
||||
function translateRole(role: string): string {
|
||||
// Function to translate roles using i18n
|
||||
function translateRole(role: string, t: (key: string) => string): string {
|
||||
switch (role) {
|
||||
case "CAPTAIN":
|
||||
return "Kapten";
|
||||
return t("admin.roles.captain");
|
||||
case "TEAMMATE":
|
||||
return "Meeskonnaliige";
|
||||
return t("admin.roles.teammate");
|
||||
default:
|
||||
return role;
|
||||
}
|
||||
}
|
||||
|
||||
export default async function AdminTeams() {
|
||||
export default async function AdminTeams({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { locale } = await params;
|
||||
setRequestLocale(locale);
|
||||
const t = await getTranslations({ locale });
|
||||
// Fetch teams with their members and member users
|
||||
const teams = await db.query.teams.findMany({
|
||||
with: {
|
||||
@@ -54,7 +62,7 @@ export default async function AdminTeams() {
|
||||
<h1
|
||||
className={`text-5xl sm:text-6xl ${vipnagorgialla.className} font-bold italic uppercase text-[#2A2C3F] dark:text-[#EEE5E5] mt-8 mb-4`}
|
||||
>
|
||||
Haldus - Meeskonnad
|
||||
{t("admin.title")} - {t("admin.teams")}
|
||||
</h1>
|
||||
</div>
|
||||
<div className="text-2xl text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
@@ -63,8 +71,8 @@ export default async function AdminTeams() {
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[100px]">ID</TableHead>
|
||||
<TableHead>Nimi</TableHead>
|
||||
<TableHead>Liikmed</TableHead>
|
||||
<TableHead>{t("admin.table.name")}</TableHead>
|
||||
<TableHead>{t("admin.table.members")}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
@@ -84,12 +92,14 @@ export default async function AdminTeams() {
|
||||
{member.user.firstName} {member.user.lastName}
|
||||
</span>
|
||||
<span className="text-gray-500">
|
||||
({translateRole(member.role)})
|
||||
({translateRole(member.role, t)})
|
||||
</span>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<span className="text-gray-500">Liikmeid puuduvad</span>
|
||||
<span className="text-gray-500">
|
||||
{t("admin.table.noMembers")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
@@ -17,9 +17,10 @@ import {
|
||||
X,
|
||||
} from "lucide-react";
|
||||
|
||||
import Link from "next/link";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { redirect, RedirectType } from "next/navigation";
|
||||
import NextLink from "next/link";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
@@ -53,13 +54,13 @@ async function dismissAlert() {
|
||||
redirect("/haldus", RedirectType.replace);
|
||||
}
|
||||
|
||||
const SuccessAlertDB = () => {
|
||||
const SuccessAlertDB = ({ t }: { t: (key: string) => string }) => {
|
||||
return (
|
||||
<Alert className="flex items-start mt-8">
|
||||
<CheckCircle2Icon className="mt-0.5" />
|
||||
<div className="flex-1">
|
||||
<AlertTitle>Toiming oli edukas!</AlertTitle>
|
||||
<AlertDescription>Andmebaasi andmed on uuendatud.</AlertDescription>
|
||||
<AlertTitle>{t("admin.success.title")}</AlertTitle>
|
||||
<AlertDescription>{t("admin.success.description")}</AlertDescription>
|
||||
</div>
|
||||
<form action={dismissAlert} className="ml-2">
|
||||
<Button
|
||||
@@ -76,10 +77,15 @@ const SuccessAlertDB = () => {
|
||||
};
|
||||
|
||||
export default async function Admin({
|
||||
params,
|
||||
searchParams,
|
||||
}: {
|
||||
params: Promise<{ locale: string }>;
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
||||
}) {
|
||||
const { locale } = await params;
|
||||
setRequestLocale(locale);
|
||||
const t = await getTranslations({ locale });
|
||||
const alarmStatus = await searchParams;
|
||||
const showSuccess = alarmStatus.success === "true";
|
||||
|
||||
@@ -97,31 +103,31 @@ export default async function Admin({
|
||||
|
||||
return (
|
||||
<div className="flex flex-col min-h-[90vh] m-6 mt-16 md:m-16">
|
||||
{showSuccess && <SuccessAlertDB />}
|
||||
{showSuccess && <SuccessAlertDB t={t} />}
|
||||
<div className="flex items-center gap-4">
|
||||
<Link href={"/"}>
|
||||
<NextLink href={"/"}>
|
||||
<span className="material-symbols-outlined !text-[clamp(2rem,1.5rem+1.5vw,3.5rem)] !font-bold text-[#007CAB] dark:text-[#00A3E0] translate-y-2.5 hover:-translate-x-2 dark:hover:text-[#EEE5E5] hover:text-[#2A2C3F] transition">
|
||||
arrow_left_alt
|
||||
</span>
|
||||
</Link>
|
||||
</NextLink>
|
||||
<h1
|
||||
className={`text-5xl sm:text-6xl ${vipnagorgialla.className} font-bold italic uppercase text-[#2A2C3F] dark:text-[#EEE5E5] mt-8 mb-4`}
|
||||
>
|
||||
Haldus
|
||||
{t("admin.title")}
|
||||
</h1>
|
||||
</div>
|
||||
<div className="text-2xl text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
<div className="pl-2 flex gap-8 pb-4">
|
||||
<div className="flex text-lg md:text-2xl flex-row items-center">
|
||||
<Users className="mr-2" />
|
||||
Kasutajaid: {usersData.length}
|
||||
{t("admin.users")}: {usersData.length}
|
||||
</div>
|
||||
<Link href="/haldus/meeskonnad" className="flex items-center">
|
||||
<NextLink href="/haldus/meeskonnad" className="flex items-center">
|
||||
<div className="flex text-lg md:text-2xl flex-row items-center">
|
||||
<IdCardLanyard className="mr-2" />
|
||||
Meeskondasid: {teamsData.length}
|
||||
{t("admin.teams")}: {teamsData.length}
|
||||
</div>
|
||||
</Link>
|
||||
</NextLink>
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<div className="ml-auto">
|
||||
@@ -135,24 +141,24 @@ export default async function Admin({
|
||||
</div>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogTitle>
|
||||
Kas soovite värskendada andmebaasi?
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogTitle>{t("admin.sync.title")}</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
See tõmbab Fientast praegused andmed ning asendab{" "}
|
||||
<span className="text-red-600 font-semibold">KÕIK</span>{" "}
|
||||
olemasolevad andmed andmebaasis!
|
||||
{t("admin.sync.description1")}{" "}
|
||||
<span className="text-red-600 font-semibold">
|
||||
{t("admin.sync.all")}
|
||||
</span>{" "}
|
||||
{t("admin.sync.description2")}
|
||||
<br />
|
||||
<br />
|
||||
Kui sa ei ole kindel, vajuta "Tühista".
|
||||
{t("admin.sync.warning")}
|
||||
</AlertDialogDescription>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel className="cursor-pointer">
|
||||
Tühista
|
||||
{t("common.cancel")}
|
||||
</AlertDialogCancel>
|
||||
<form action={syncAction}>
|
||||
<AlertDialogAction type="submit" className="cursor-pointer">
|
||||
Värskenda
|
||||
{t("admin.sync.update")}
|
||||
</AlertDialogAction>
|
||||
</form>
|
||||
</AlertDialogFooter>
|
||||
@@ -2,8 +2,16 @@
|
||||
import ReactMarkdown, { Components } from "react-markdown";
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import SectionDivider from "@/components/SectionDivider";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
|
||||
export default async function Page() {
|
||||
export default async function Page({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { locale } = await params;
|
||||
setRequestLocale(locale);
|
||||
const t = await getTranslations({ locale });
|
||||
const file = Bun.file("src/data/kodukord.md");
|
||||
const content = await file.text();
|
||||
|
||||
@@ -14,7 +22,7 @@ export default async function Page() {
|
||||
<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`}
|
||||
>
|
||||
Kodukord
|
||||
{t("rules.houseRules")}
|
||||
</h1>
|
||||
|
||||
<div className="prose prose-lg dark:prose-invert max-w-none">
|
||||
38
src/app/[locale]/layout.tsx
Normal file
38
src/app/[locale]/layout.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import { NextIntlClientProvider } from "next-intl";
|
||||
import { setRequestLocale, getMessages } from "next-intl/server";
|
||||
import { ThemeProvider } from "@/components/Theme-provider";
|
||||
import SidebarParent from "@/components/SidebarParent";
|
||||
import Footer from "@/components/Footer";
|
||||
|
||||
export default async function LocaleLayout({
|
||||
children,
|
||||
params,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
params: Promise<{ locale: string }>;
|
||||
}>) {
|
||||
const { locale } = await params;
|
||||
|
||||
// Enable static rendering
|
||||
setRequestLocale(locale);
|
||||
|
||||
// Provide messages for client-side components
|
||||
const messages = await getMessages();
|
||||
|
||||
return (
|
||||
<div lang={locale}>
|
||||
<NextIntlClientProvider messages={messages}>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
<SidebarParent />
|
||||
{children}
|
||||
<Footer />
|
||||
</ThemeProvider>
|
||||
</NextIntlClientProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import * as THREE from "three";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useEffect, useRef, useState, useMemo } from "react";
|
||||
import { EyeClosed, Eye } from "lucide-react";
|
||||
import SectionDivider from "@/components/SectionDivider";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
// Define interface for the ref with toggle function
|
||||
interface MountRefCurrent extends HTMLDivElement {
|
||||
@@ -15,6 +17,21 @@ export default function Expo() {
|
||||
const [hoveredRoom, setHoveredRoom] = useState<string | null>(null);
|
||||
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
|
||||
const [showDividers, setShowDividers] = useState<boolean>(true);
|
||||
const t = useTranslations();
|
||||
|
||||
// Define room names with translations
|
||||
const roomNames = useMemo(
|
||||
() => ({
|
||||
boardGames: t("expo.areas.boardGames"),
|
||||
bar: t("expo.areas.bar"),
|
||||
eval: "EVAL",
|
||||
simRacing: t("expo.areas.simRacing"),
|
||||
fighting: t("expo.areas.fighting"),
|
||||
lvlup: "LVLup!",
|
||||
redbull: "Red Bull",
|
||||
}),
|
||||
[t],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!mountRef.current) return;
|
||||
@@ -113,7 +130,7 @@ export default function Expo() {
|
||||
x: 2.5,
|
||||
z: 4,
|
||||
color: roomColors[0],
|
||||
name: "Lauamängude ala",
|
||||
name: roomNames.boardGames,
|
||||
},
|
||||
{
|
||||
width: 3.5,
|
||||
@@ -122,7 +139,7 @@ export default function Expo() {
|
||||
x: 0.7,
|
||||
z: -0.3,
|
||||
color: roomColors[1],
|
||||
name: "Baariala",
|
||||
name: roomNames.bar,
|
||||
},
|
||||
{
|
||||
width: 1.8,
|
||||
@@ -131,7 +148,7 @@ export default function Expo() {
|
||||
x: 1,
|
||||
z: -3.5,
|
||||
color: roomColors[2],
|
||||
name: "EVAL",
|
||||
name: roomNames.eval,
|
||||
},
|
||||
{
|
||||
width: 2,
|
||||
@@ -140,7 +157,7 @@ export default function Expo() {
|
||||
x: 5.2,
|
||||
z: -2,
|
||||
color: roomColors[3],
|
||||
name: "Red Bull Sim Racing",
|
||||
name: roomNames.simRacing,
|
||||
},
|
||||
{
|
||||
width: 3,
|
||||
@@ -149,7 +166,7 @@ export default function Expo() {
|
||||
x: -1.7,
|
||||
z: -3.5,
|
||||
color: roomColors[4],
|
||||
name: "Võitlusmängu ala",
|
||||
name: roomNames.fighting,
|
||||
},
|
||||
// {
|
||||
// width: 1.8,
|
||||
@@ -167,7 +184,7 @@ export default function Expo() {
|
||||
x: -3.5,
|
||||
z: -0.5,
|
||||
color: roomColors[7],
|
||||
name: "LVLup!",
|
||||
name: roomNames.lvlup,
|
||||
},
|
||||
//{
|
||||
// width: 2,
|
||||
@@ -185,7 +202,7 @@ export default function Expo() {
|
||||
x: 3,
|
||||
z: -3.5,
|
||||
color: roomColors[8],
|
||||
name: "Red Bull",
|
||||
name: roomNames.redbull,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -369,7 +386,7 @@ export default function Expo() {
|
||||
}
|
||||
renderer.dispose();
|
||||
};
|
||||
}, []);
|
||||
}, [roomNames]);
|
||||
|
||||
// Update dividers when showDividers state changes
|
||||
useEffect(() => {
|
||||
@@ -379,15 +396,16 @@ export default function Expo() {
|
||||
}, [showDividers]);
|
||||
|
||||
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
|
||||
{t("expo.title")}
|
||||
</h1>
|
||||
<div className="mb-6">
|
||||
<h2 className="text-2xl text-[#2A2C3F] dark:text-[#EEE5E5] mb-3">
|
||||
Tudengimaja
|
||||
{t("schedule.locations.studentHouse")}
|
||||
</h2>
|
||||
<div className="flex flex-wrap gap-4 pb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -396,7 +414,7 @@ export default function Expo() {
|
||||
style={{ backgroundColor: "#4ecdc4" }}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
Baariala
|
||||
{t("expo.areas.bar")}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -414,7 +432,7 @@ export default function Expo() {
|
||||
style={{ backgroundColor: "#343434" }}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
Lauamängude ala
|
||||
{t("expo.areas.boardGames")}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -441,7 +459,7 @@ export default function Expo() {
|
||||
style={{ backgroundColor: "#ff6600" }}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
Red Bull Sim Racing
|
||||
{t("expo.areas.simRacing")}
|
||||
</span>
|
||||
</div>
|
||||
<div className="items-center gap-2 hidden">
|
||||
@@ -459,7 +477,7 @@ export default function Expo() {
|
||||
style={{ backgroundColor: "#ff1493" }}
|
||||
></div>
|
||||
<span className="text-sm text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
Võitlusmängu ala
|
||||
{t("expo.areas.fighting")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -476,7 +494,7 @@ export default function Expo() {
|
||||
<Eye className="w-6 h-6 mr-2" />
|
||||
)}
|
||||
|
||||
{showDividers ? "Peida" : "Näita"}
|
||||
{showDividers ? t("expo.hide") : t("expo.show")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -495,5 +513,8 @@ export default function Expo() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SectionDivider />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
19
src/app/[locale]/not-found.tsx
Normal file
19
src/app/[locale]/not-found.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
|
||||
export default async function NotFound() {
|
||||
const t = await getTranslations("notFound");
|
||||
|
||||
return (
|
||||
<div className="flex flex-col min-h-[90vh] p-12 justify-center items-center">
|
||||
<h1
|
||||
className={`text-7xl ${vipnagorgialla.className} font-bold italic uppercase text-[#2A2C3F] dark:text-[#EEE5E5] mt-8 mb-4`}
|
||||
>
|
||||
{t("title")}
|
||||
</h1>
|
||||
<p className="text-2xl text-[#2A2C3F] dark:text-[#EEE5E5] mb-8">
|
||||
{t("message")}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,8 +1,18 @@
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import Link from "next/link";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
import Image from "next/image";
|
||||
import NextLink from "next/link";
|
||||
|
||||
export default async function Home({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { locale } = await params;
|
||||
setRequestLocale(locale);
|
||||
const t = await getTranslations({ locale });
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div>
|
||||
{/* Title */}
|
||||
@@ -25,7 +35,7 @@ export default function Home() {
|
||||
<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]`}
|
||||
>
|
||||
Auhinnafond
|
||||
{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]`}
|
||||
@@ -44,7 +54,7 @@ export default function Home() {
|
||||
<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
|
||||
{t("navigation.schedule")}
|
||||
</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
|
||||
@@ -55,8 +65,7 @@ export default function Home() {
|
||||
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.
|
||||
{t("home.sections.schedule.description")}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
@@ -66,9 +75,9 @@ export default function Home() {
|
||||
>
|
||||
<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`}
|
||||
className={`text-[clamp(2rem,1.8rem+1vw,3rem)] ${vipnagorgialla.className} font-bold italic break-all uppercase dark:text-[#EEE5E5] text-[#2A2C3F] dark:group-hover:text-[#2A2C3F] group-hover:text-black`}
|
||||
>
|
||||
Turniirid
|
||||
{t("navigation.tournaments")}
|
||||
</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
|
||||
@@ -80,8 +89,7 @@ export default function Home() {
|
||||
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€.
|
||||
{t("home.sections.tournaments.description")}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
@@ -93,7 +101,7 @@ export default function Home() {
|
||||
<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
|
||||
{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
|
||||
@@ -104,8 +112,7 @@ export default function Home() {
|
||||
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.
|
||||
{t("home.sections.expo.description")}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
@@ -117,7 +124,7 @@ export default function Home() {
|
||||
>
|
||||
<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!
|
||||
{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
|
||||
@@ -133,10 +140,10 @@ export default function Home() {
|
||||
>
|
||||
<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...
|
||||
{t("home.sections.poweredBy")}
|
||||
</h3>
|
||||
<div className="flex flex-row flex-wrap gap-8 md:gap-18 items-center">
|
||||
<Link href="https://taltech.ee" target="_blank">
|
||||
<NextLink href="https://taltech.ee" target="_blank">
|
||||
<Image
|
||||
src="/sponsors/taltech-color.png"
|
||||
alt="Taltech (Tallinna Tehnikaülikool)"
|
||||
@@ -144,8 +151,8 @@ export default function Home() {
|
||||
height={192}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<Link href="https://www.redbull.com/ee-et/" target="_blank">
|
||||
</NextLink>
|
||||
<NextLink href="https://www.redbull.com/ee-et/" target="_blank">
|
||||
<Image
|
||||
src="/sponsors/redbull.png"
|
||||
alt="Redbull"
|
||||
@@ -153,8 +160,8 @@ export default function Home() {
|
||||
height={80}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<Link href="https://www.alecoq.ee" target="_blank">
|
||||
</NextLink>
|
||||
<NextLink href="https://www.alecoq.ee" target="_blank">
|
||||
<Image
|
||||
src="/sponsors/alecoq.svg"
|
||||
alt="Alecoq"
|
||||
@@ -162,8 +169,8 @@ export default function Home() {
|
||||
height={200}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<Link href="https://www.simracing.ee/" target="_blank">
|
||||
</NextLink>
|
||||
<NextLink href="https://www.simracing.ee/" target="_blank">
|
||||
<Image
|
||||
src="/sponsors/EVAL.png"
|
||||
alt="EVAL"
|
||||
@@ -171,8 +178,8 @@ export default function Home() {
|
||||
height={200}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<Link href="https://balsnack.ee" target="_blank">
|
||||
</NextLink>
|
||||
<NextLink href="https://balsnack.ee" target="_blank">
|
||||
<Image
|
||||
src="/sponsors/balsnack.svg"
|
||||
alt="Balsnack"
|
||||
@@ -180,8 +187,8 @@ export default function Home() {
|
||||
height={200}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<Link
|
||||
</NextLink>
|
||||
<NextLink
|
||||
href="https://www.rara.ee/sundmused/interaktiivne-videomangude-muuseum-lvlup/"
|
||||
target="_blank"
|
||||
>
|
||||
@@ -192,8 +199,11 @@ export default function Home() {
|
||||
height={192}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
<Link href="https://www.facebook.com/bfglOfficial" target="_blank">
|
||||
</NextLink>
|
||||
<NextLink
|
||||
href="https://www.facebook.com/bfglOfficial"
|
||||
target="_blank"
|
||||
>
|
||||
<Image
|
||||
src="/sponsors/BFGL.png"
|
||||
alt="BFGL"
|
||||
@@ -201,7 +211,7 @@ export default function Home() {
|
||||
height={192}
|
||||
className="object-contain"
|
||||
/>
|
||||
</Link>
|
||||
</NextLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
114
src/app/[locale]/piletid/page.tsx
Normal file
114
src/app/[locale]/piletid/page.tsx
Normal file
@@ -0,0 +1,114 @@
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import Link from "next/link";
|
||||
import SectionDivider from "@/components/SectionDivider";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
|
||||
export default async function Tickets({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { locale } = await params;
|
||||
setRequestLocale(locale);
|
||||
const t = await getTranslations({ locale });
|
||||
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`}
|
||||
>
|
||||
{t("tickets.title")}
|
||||
</h1>
|
||||
<div className="flex justify-center lg:items-center flex-col lg:flex-row gap-8 md:gap-12 flex-grow mb-16 md:mt-8 lg:mt-0">
|
||||
<div className="bg-[#007CAB] -skew-x-2 md:-skew-x-5 text-white px-8 md:px-12 py-16 hover:scale-103 transition-all duration-150 w-full md:w-xl lg:w-[400px]">
|
||||
<h2
|
||||
className={`text-6xl ${vipnagorgialla.className} font-bold italic text-[#EEE5E5] pb-2`}
|
||||
>
|
||||
{t("tickets.computerParticipant.price")}
|
||||
</h2>
|
||||
<h3
|
||||
className={`text-3xl ${vipnagorgialla.className} font-bold italic text-[#EEE5E5] pb-4`}
|
||||
>
|
||||
{t("tickets.computerParticipant.title")}
|
||||
</h3>
|
||||
<ul className="pl-4 mb-8 list-[square] marker:text-[#1F5673]">
|
||||
{t
|
||||
.raw("tickets.computerParticipant.features")
|
||||
.map((feature: string, index: number) => (
|
||||
<li key={index} className="text-xl italic">
|
||||
{feature}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Link href="https://fienta.com/et/tipilan" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#1F5673] cursor-pointer ${vipnagorgialla.className} font-bold italic`}
|
||||
>
|
||||
{t("tickets.buyTicket")}
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="bg-[#1F5673] -skew-x-2 md:-skew-x-5 text-white px-8 md:px-12 py-16 hover:scale-103 transition-all duration-150 w-full md:w-xl lg:w-[400px]">
|
||||
<h2
|
||||
className={`text-6xl ${vipnagorgialla.className} font-bold italic text-[#EEE5E5] pb-2`}
|
||||
>
|
||||
{t("tickets.competitor.price")}
|
||||
</h2>
|
||||
<h3
|
||||
className={`text-3xl ${vipnagorgialla.className} font-bold italic text-[#EEE5E5] pb-4`}
|
||||
>
|
||||
{t("tickets.competitor.title")}
|
||||
</h3>
|
||||
<ul className="pl-4 mb-8 list-[square] marker:text-[#007CAB]">
|
||||
{t
|
||||
.raw("tickets.competitor.features")
|
||||
.map((feature: string, index: number) => (
|
||||
<li key={index} className="text-xl">
|
||||
{feature}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Link href="https://fienta.com/et/tipilan" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#007CAB] cursor-pointer ${vipnagorgialla.className} font-bold italic`}
|
||||
>
|
||||
{t("tickets.buyTicket")}
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="bg-[#007CAB] -skew-x-2 md:-skew-x-5 text-white px-8 md:px-12 py-16 hover:scale-103 transition-all duration-150 w-full md:w-xl lg:w-[400px]">
|
||||
<h2
|
||||
className={`text-6xl ${vipnagorgialla.className} font-bold italic text-[#EEE5E5] pb-2`}
|
||||
>
|
||||
{t("tickets.visitor.price")}
|
||||
</h2>
|
||||
<h3
|
||||
className={`text-3xl ${vipnagorgialla.className} font-bold italic text-[#EEE5E5] pb-4`}
|
||||
>
|
||||
{t("tickets.visitor.title")}
|
||||
</h3>
|
||||
<ul className="pl-4 mb-8 list-[square] marker:text-[#1F5673]">
|
||||
{t
|
||||
.raw("tickets.visitor.features")
|
||||
.map((feature: string, index: number) => (
|
||||
<li key={index} className="text-xl">
|
||||
{feature}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Link href="https://fienta.com/et/tipilan" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#1F5673] cursor-pointer ${vipnagorgialla.className} font-bold italic`}
|
||||
>
|
||||
{t("tickets.buyTicket")}
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SectionDivider />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -2,23 +2,24 @@ import { notFound } from "next/navigation";
|
||||
import ReactMarkdown, { Components } from "react-markdown";
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import SectionDivider from "@/components/SectionDivider";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
|
||||
// Map of valid slugs to their corresponding file paths and titles
|
||||
// Map of valid slugs to their corresponding file paths and translation keys
|
||||
const rulesMap = {
|
||||
lol: {
|
||||
filePath: "src/data/rules/lol.md",
|
||||
title: "LOL Reeglid",
|
||||
titleKey: "rules.lolRules",
|
||||
},
|
||||
cs2: {
|
||||
filePath: "src/data/rules/cs2.md",
|
||||
title: "CS2 Reeglid",
|
||||
titleKey: "rules.cs2Rules",
|
||||
},
|
||||
} as const;
|
||||
|
||||
type RuleSlug = keyof typeof rulesMap;
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{ slug: string }>;
|
||||
params: Promise<{ slug: string; locale: string }>;
|
||||
}
|
||||
|
||||
async function getRuleContent(slug: string) {
|
||||
@@ -33,7 +34,7 @@ async function getRuleContent(slug: string) {
|
||||
const content = await file.text();
|
||||
return {
|
||||
content,
|
||||
title: ruleConfig.title,
|
||||
titleKey: ruleConfig.titleKey,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`Error reading rule file for slug ${slug}:`, error);
|
||||
@@ -42,7 +43,9 @@ async function getRuleContent(slug: string) {
|
||||
}
|
||||
|
||||
export default async function RulePage({ params }: PageProps) {
|
||||
const { slug } = await params;
|
||||
const { slug, locale } = await params;
|
||||
setRequestLocale(locale);
|
||||
const t = await getTranslations({ locale });
|
||||
const ruleData = await getRuleContent(slug);
|
||||
|
||||
if (!ruleData) {
|
||||
@@ -55,7 +58,7 @@ export default async function RulePage({ params }: PageProps) {
|
||||
<div>
|
||||
<div className="flex flex-col min-h-[90vh] m-6 mt-16 md:m-16">
|
||||
<h1 className={`${headingStyle} mt-8 md:mt-16 mb-4`}>
|
||||
{ruleData.title}
|
||||
{t(ruleData.titleKey)}
|
||||
</h1>
|
||||
|
||||
<div className="prose prose-lg dark:prose-invert max-w-none">
|
||||
@@ -1,8 +1,16 @@
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import Link from "next/link";
|
||||
import SectionDivider from "@/components/SectionDivider";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
import NextLink from "next/link";
|
||||
|
||||
export default function RulesMenu() {
|
||||
export default async function RulesMenu({
|
||||
params,
|
||||
}: {
|
||||
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]`;
|
||||
@@ -15,32 +23,34 @@ export default function RulesMenu() {
|
||||
<div>
|
||||
<div className="flex flex-col md:m-16">
|
||||
<h1 className={`${headingStyle} ml-3 mt-24 md:ml-0 md:mt-16 mb-4 px-4`}>
|
||||
REEGLID
|
||||
{t("rules.title")}
|
||||
</h1>
|
||||
|
||||
<div className="flex flex-wrap flex-row lg:mt-16 justify-center lg:items-start gap-12 flex-grow mb-8">
|
||||
<Link href="/kodukord">
|
||||
<NextLink href="/kodukord">
|
||||
<div className={`${boxStyle} bg-[#007CAB] py-20 px-8`}>
|
||||
<h2 className={`${boxTextStyle}`}>Kodukord</h2>
|
||||
<h2 className={`${boxTextStyle}`}>{t("rules.houseRules")}</h2>
|
||||
</div>
|
||||
</Link>
|
||||
</NextLink>
|
||||
|
||||
<Link href="/reeglid/cs2">
|
||||
<NextLink href="/reeglid/cs2">
|
||||
<div className={`${boxStyle} bg-[#1F5673] py-20 px-8`}>
|
||||
<h2 className={`${boxTextStyle}`}>CS2 reeglid</h2>
|
||||
<h2 className={`${boxTextStyle}`}>{t("rules.cs2Rules")}</h2>
|
||||
</div>
|
||||
</Link>
|
||||
</NextLink>
|
||||
|
||||
<Link href="reeglid/lol">
|
||||
<NextLink href="reeglid/lol">
|
||||
<div className={`${boxStyle} bg-[#007CAB] py-20 px-8`}>
|
||||
<h2 className={`${boxTextStyle}`}>LoL reeglid</h2>
|
||||
<h2 className={`${boxTextStyle}`}>{t("rules.lolRules")}</h2>
|
||||
</div>
|
||||
</Link>
|
||||
</NextLink>
|
||||
|
||||
{/* Minitourn. link coming soon*/}
|
||||
{/*<Link href="">*/}
|
||||
<div className={`${boxStyle} bg-[#1F5673] py-16 px-8`}>
|
||||
<h2 className={`${boxTextStyle}`}>Miniturniiride reeglid</h2>
|
||||
<h2 className={`${boxTextStyle}`}>
|
||||
{t("tournaments.mini.titleSingular")} {t("rules.title")}
|
||||
</h2>
|
||||
</div>
|
||||
{/*</Link>*/}
|
||||
</div>
|
||||
@@ -1,8 +1,16 @@
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
|
||||
export default function Home() {
|
||||
export default async function Home({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { locale } = await params;
|
||||
setRequestLocale(locale);
|
||||
const t = await getTranslations({ locale });
|
||||
return (
|
||||
<div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2">
|
||||
@@ -30,7 +38,7 @@ export default function Home() {
|
||||
<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
|
||||
{t("navigation.schedule")}
|
||||
</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
|
||||
@@ -41,8 +49,7 @@ export default function Home() {
|
||||
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.
|
||||
{t("home.sections.schedule.description")}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
@@ -68,7 +75,7 @@ export default function Home() {
|
||||
<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
|
||||
{t("navigation.tournaments")}
|
||||
</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
|
||||
@@ -80,8 +87,7 @@ export default function Home() {
|
||||
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€.
|
||||
{t("home.sections.tournaments.description")}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
@@ -93,7 +99,7 @@ export default function Home() {
|
||||
<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
|
||||
{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
|
||||
@@ -104,8 +110,7 @@ export default function Home() {
|
||||
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.
|
||||
{t("home.sections.expo.description")}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
@@ -117,7 +122,7 @@ export default function Home() {
|
||||
>
|
||||
<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!
|
||||
{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
|
||||
@@ -133,7 +138,7 @@ export default function Home() {
|
||||
>
|
||||
<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...
|
||||
{t("home.sections.poweredBy")}
|
||||
</h3>
|
||||
<div className="flex flex-row flex-wrap gap-8 md:gap-18 items-center">
|
||||
<Link href="https://taltech.ee" target="_blank">
|
||||
188
src/app/[locale]/turniirid/page.tsx
Normal file
188
src/app/[locale]/turniirid/page.tsx
Normal file
@@ -0,0 +1,188 @@
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||
|
||||
export default async function Tourney({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ locale: string }>;
|
||||
}) {
|
||||
const { locale } = await params;
|
||||
setRequestLocale(locale);
|
||||
const t = await getTranslations({ locale });
|
||||
const headingStyle = `text-3xl md:text-5xl lg:text-5xl ${vipnagorgialla.className} font-bold uppercase text-[#2A2C3F] dark:text-[#EEE5E5] -skew-x-2 md:-skew-x-5`;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col min-h-[90vh] mt-16">
|
||||
<h1
|
||||
className={`text-4xl md:text-5xl lg:text-6xl ${vipnagorgialla.className} font-bold italic uppercase
|
||||
text-[#2A2C3F] dark:text-[#EEE5E5] md:m-16`}
|
||||
>
|
||||
{t("tournaments.title")}
|
||||
</h1>
|
||||
|
||||
<div className="flex flex-col">
|
||||
{/* CS2 turniir */}
|
||||
<div className="hover:bg-[#007CAB] py-8 md:py-16 transition group">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-16 items-center mx-8 md:mx-16 lg:mx-32 xl:mx-48">
|
||||
<div className="-skew-x-2 md:-skew-x-5">
|
||||
<h2 className={`${headingStyle}`}>
|
||||
{t("tournaments.cs2.title")}
|
||||
</h2>
|
||||
<p
|
||||
className={
|
||||
"text-2xl mb-4 text-neutral-500 group-hover:text-black"
|
||||
}
|
||||
>
|
||||
{t("tournaments.cs2.timing")}
|
||||
</p>
|
||||
<p className="text-balance">
|
||||
{t("tournaments.cs2.description1")}
|
||||
</p>
|
||||
<br />
|
||||
<p className="text-balance">
|
||||
{t("tournaments.cs2.description2")}
|
||||
</p>
|
||||
<br />
|
||||
|
||||
<div className={"flex flex-row flex-wrap gap-8"}>
|
||||
<Link href="/reeglid/cs2" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#1F5673] cursor-pointer ${vipnagorgialla.className} font-bold italic text-[#ECE5E5]`}
|
||||
>
|
||||
{t("tournaments.cs2.readRules")}
|
||||
</button>
|
||||
</Link>
|
||||
<a href="https://fienta.com/et/tipilan" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#007CAB] group-hover:bg-black cursor-pointer ${vipnagorgialla.className} font-bold italic text-[#ECE5E5]`}
|
||||
>
|
||||
{t("tournaments.cs2.buyTicket")}
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="hidden md:block">
|
||||
<div>
|
||||
{/* Outside div needs to remain so that overflow won't occur*/}
|
||||
<Image
|
||||
src="/images/cs2_tournament_logo.png"
|
||||
alt="CS2 tournament"
|
||||
width={600}
|
||||
height={400}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* LoL turniir */}
|
||||
<div className="hover:bg-[#007CAB] py-8 md:py-16 border-t-[3px] border-[#1F5673] transition group">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-16 items-center mx-8 md:mx-16 lg:mx-32 xl:mx-48">
|
||||
<div className="hidden md:block">
|
||||
<div>
|
||||
{/* Outside div needs to remain so that overflow won't occur*/}
|
||||
<Image
|
||||
src="/images/lol_tournament_logo.png"
|
||||
alt="LoL tournament"
|
||||
width={600}
|
||||
height={400}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-auto text-right -skew-x-2 md:-skew-x-5">
|
||||
<h2 className={`${headingStyle}`}>
|
||||
{t("tournaments.lol.title")}
|
||||
</h2>
|
||||
<p
|
||||
className={
|
||||
"text-2xl mb-4 text-neutral-500 group-hover:text-black"
|
||||
}
|
||||
>
|
||||
{t("tournaments.lol.timing")}
|
||||
</p>
|
||||
<p className="text-balance">
|
||||
{t("tournaments.lol.description1")}
|
||||
</p>
|
||||
<br />
|
||||
<p className="text-balance">
|
||||
{t("tournaments.lol.description2")}
|
||||
</p>
|
||||
<br />
|
||||
<div className="flex flex-row flex-wrap gap-4 md:gap-8 justify-end">
|
||||
<Link href="/reeglid/lol" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#1F5673] cursor-pointer ${vipnagorgialla.className} font-bold italic text-[#ECE5E5]`}
|
||||
>
|
||||
{t("tournaments.lol.readRules")}
|
||||
</button>
|
||||
</Link>
|
||||
<a href="https://fienta.com/et/tipilan" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#007CAB] group-hover:bg-black cursor-pointer ${vipnagorgialla.className} font-bold italic text-[#ECE5E5]`}
|
||||
>
|
||||
{t("tournaments.lol.buyTicket")}
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mini-turniirid */}
|
||||
<div className="hover:bg-[#007CAB] py-8 md:py-16 border-t-[3px] border-b-[3px] border-[#1F5673] transition group">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-16 items-center mx-8 md:mx-16 lg:mx-32 xl:mx-48">
|
||||
<div className="-skew-x-2 md:-skew-x-5">
|
||||
<h2 className={`${headingStyle}`}>
|
||||
{t("tournaments.mini.title")}
|
||||
</h2>
|
||||
<p
|
||||
className={
|
||||
"text-2xl mb-4 text-neutral-500 group-hover:text-black"
|
||||
}
|
||||
>
|
||||
{t("tournaments.mini.timing")}
|
||||
</p>
|
||||
<p className="text-balance">
|
||||
{t("tournaments.mini.description1")}
|
||||
</p>
|
||||
<br />
|
||||
<p className="text-balance">
|
||||
{t("tournaments.mini.description2")}
|
||||
</p>
|
||||
<br />
|
||||
<div className="flex flex-row flex-wrap gap-4 md:gap-8">
|
||||
<Link href="/kodukord" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#1F5673] cursor-pointer ${vipnagorgialla.className} font-bold italic text-[#ECE5E5]`}
|
||||
>
|
||||
{t("tournaments.mini.readRules")}
|
||||
</button>
|
||||
</Link>
|
||||
<a href="https://fienta.com/et/tipilan" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#007CAB] group-hover:bg-black cursor-pointer ${vipnagorgialla.className} font-bold italic text-[#ECE5E5]`}
|
||||
>
|
||||
{t("tournaments.mini.buyTicket")}
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="hidden md:block">
|
||||
<div>
|
||||
{/* Outside div needs to remain so that overflow won't occur*/}
|
||||
<Image
|
||||
src="/images/minitournament_logo.png"
|
||||
alt="mini tournaments"
|
||||
width={600}
|
||||
height={400}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import {useState} from "react";
|
||||
import {vipnagorgialla} from "@/components/Vipnagorgialla";
|
||||
import {scheduleData} from "@/data/timetable";
|
||||
import SectionDivider from "@/components/SectionDivider";
|
||||
|
||||
const tabs = Object.keys(scheduleData);
|
||||
|
||||
export default function Timetable() {
|
||||
const [activeTab, setActiveTab] = useState(tabs[0]);
|
||||
const schedule = scheduleData[activeTab];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex flex-col min-h-[90vh] m-6 mt-16 md:m-16">
|
||||
<h1
|
||||
className={`text-5xl sm:text-6xl ${vipnagorgialla.className} font-bold italic uppercase text-[#2A2C3F] dark:text-[#EEE5E5] mt-8 md:mt-16 mb-8`}
|
||||
>
|
||||
Ajakava
|
||||
</h1>
|
||||
|
||||
{/* Tab menu */}
|
||||
<div className="flex space-x-4 mb-8">
|
||||
{tabs.map((tab) => (
|
||||
<button
|
||||
key={tab}
|
||||
onClick={() => setActiveTab(tab)}
|
||||
className={`${vipnagorgialla.className} uppercase italic px-4 py-2 text-lg font-semibold ${
|
||||
activeTab === tab
|
||||
? "bg-[#00A3E0] text-white"
|
||||
: "bg-[#007CAB] dark:bg-[#007CAB] text-[#EEE5E5] hover:bg-[#00A3E0] dark:hover:bg-[#007CAB]"
|
||||
} transition-colors`}
|
||||
>
|
||||
{tab}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Schedule entries */}
|
||||
<div className="space-y-6">
|
||||
{schedule.map((item, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className="border-l-3 border-[#007CAB] pl-4 flex flex-row gap-12"
|
||||
>
|
||||
<div
|
||||
className={` ${vipnagorgialla.className} text-[#00A3E0] text-5xl font-bold italic`}
|
||||
>
|
||||
{item.time}
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
className={`${vipnagorgialla.className} text-4xl italic font-bold text-[#2A2C3F] dark:text-[#EEE5E5]`}
|
||||
>
|
||||
{item.title}
|
||||
</div>
|
||||
{item.description && (
|
||||
<div className="text-2xl text-[#938BA1] dark:text-[#938BA1]">
|
||||
{item.description}
|
||||
</div>
|
||||
)}
|
||||
{item.location && (
|
||||
<div className="text-2xl text-[#938BA1] dark:text-[#938BA1]">
|
||||
{item.location}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SectionDivider/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,18 +1,8 @@
|
||||
// Head metadata
|
||||
import type { Metadata } from "next";
|
||||
import Head from "next/head";
|
||||
|
||||
// Provides the theme context to the app
|
||||
import { ThemeProvider } from "@/components/Theme-provider";
|
||||
import { Work_Sans } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import "material-symbols";
|
||||
|
||||
// Fonts
|
||||
import { Work_Sans } from "next/font/google";
|
||||
|
||||
import SidebarParent from "@/components/SidebarParent";
|
||||
import Footer from "@/components/Footer";
|
||||
|
||||
const workSans = Work_Sans({
|
||||
subsets: ["latin"],
|
||||
});
|
||||
@@ -24,32 +14,15 @@ export const metadata: Metadata = {
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
}) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<Head>
|
||||
<title>TipiLAN</title>
|
||||
<meta property="og:title" content="TipiLAN 2025" key="title" />
|
||||
<meta
|
||||
name="description"
|
||||
content="TipiLAN 2025 – Eesti suurim tudengite korraldatud LAN!"
|
||||
/>
|
||||
</Head>
|
||||
<html suppressHydrationWarning>
|
||||
<body
|
||||
className={`${workSans.className} antialiased bg-[#EEE5E5] dark:bg-[#0E0F19]`}
|
||||
>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
<SidebarParent />
|
||||
{children}
|
||||
<Footer />
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import { ThemeProvider } from "@/components/Theme-provider";
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
<div className="flex flex-col min-h-[90vh] p-12 justify-center items-center">
|
||||
<h1 className={`text-7xl ${vipnagorgialla.className} font-bold italic uppercase text-[#2A2C3F] dark:text-[#EEE5E5] mt-8 mb-4`}>404</h1>
|
||||
<p className="text-2xl text-[#2A2C3F] dark:text-[#EEE5E5]">Seda lehte me ei leidnud.</p>
|
||||
<h1
|
||||
className={`text-7xl ${vipnagorgialla.className} font-bold italic uppercase text-[#2A2C3F] dark:text-[#EEE5E5] mt-8 mb-4`}
|
||||
>
|
||||
404
|
||||
</h1>
|
||||
<div className="text-center">
|
||||
<p className="text-2xl text-[#2A2C3F] dark:text-[#EEE5E5] mb-2">
|
||||
Lehte ei leitud!
|
||||
</p>
|
||||
<p className="text-lg text-[#2A2C3F]/80 dark:text-[#EEE5E5]/80">
|
||||
Page not found!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
import {vipnagorgialla} from "@/components/Vipnagorgialla";
|
||||
import Link from "next/link";
|
||||
import SectionDivider from "@/components/SectionDivider";
|
||||
|
||||
export default function Tickets() {
|
||||
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`}
|
||||
>
|
||||
PILETID JA REGIS­TREERIMINE
|
||||
</h1>
|
||||
<div
|
||||
className="flex justify-center lg:items-center flex-col lg:flex-row gap-8 md:gap-12 flex-grow mb-16 md:mt-8 lg:mt-0">
|
||||
<div
|
||||
className="bg-[#007CAB] -skew-x-2 md:-skew-x-5 text-white px-8 md:px-12 py-16 hover:scale-103 transition-all duration-150 w-full md:w-xl lg:w-[400px]">
|
||||
<h2
|
||||
className={`text-6xl ${vipnagorgialla.className} font-bold italic text-[#EEE5E5] pb-2`}
|
||||
>
|
||||
8€
|
||||
</h2>
|
||||
<h3
|
||||
className={`text-3xl ${vipnagorgialla.className} font-bold italic text-[#EEE5E5] pb-4`}
|
||||
>
|
||||
Arvutiga osaleja
|
||||
</h3>
|
||||
<ul className="pl-4 mb-8 list-[square] marker:text-[#1F5673]">
|
||||
<li className="text-xl italic">
|
||||
Isiklik laud, voolu- ja internetiühendus
|
||||
</li>
|
||||
<li className="text-xl">Ligipääs demoalale</li>
|
||||
<li className="text-xl">Turniiride pealt vaatamine</li>
|
||||
<li className="text-xl">Võimalus osaleda miniturniiridel</li>
|
||||
</ul>
|
||||
<Link href="https://fienta.com/et/tipilan" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#1F5673] cursor-pointer ${vipnagorgialla.className} font-bold italic`}
|
||||
>
|
||||
OSTA PILET
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
<div
|
||||
className="bg-[#1F5673] -skew-x-2 md:-skew-x-5 text-white px-8 md:px-12 py-16 hover:scale-103 transition-all duration-150 w-full md:w-xl lg:w-[400px]">
|
||||
<h2
|
||||
className={`text-6xl ${vipnagorgialla.className} font-bold italic text-[#EEE5E5] pb-2`}
|
||||
>
|
||||
12-15€
|
||||
</h2>
|
||||
<h3
|
||||
className={`text-3xl ${vipnagorgialla.className} font-bold italic text-[#EEE5E5] pb-4`}
|
||||
>
|
||||
Võistleja
|
||||
</h3>
|
||||
<ul className="pl-4 mb-8 list-[square] marker:text-[#007CAB]">
|
||||
<li className="text-xl">Võimalus osaleda CS2 või LoL turniiril</li>
|
||||
<li className="text-xl">
|
||||
Isiklik laud, voolu- ja internetiühendus
|
||||
</li>
|
||||
<li className="text-xl">Ligipääs demoalale</li>
|
||||
<li className="text-xl">Turniiride pealt vaatamine</li>
|
||||
<li className="text-xl">Võimalus osaleda miniturniiridel</li>
|
||||
</ul>
|
||||
<Link href="https://fienta.com/et/tipilan" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#007CAB] cursor-pointer ${vipnagorgialla.className} font-bold italic`}
|
||||
>
|
||||
OSTA PILET
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="bg-[#007CAB] -skew-x-2 md:-skew-x-5 text-white px-8 md:px-12 py-16 hover:scale-103 transition-all duration-150 w-full md:w-xl lg:w-[400px]">
|
||||
<h2
|
||||
className={`text-6xl ${vipnagorgialla.className} font-bold italic text-[#EEE5E5] pb-2`}
|
||||
>
|
||||
6€
|
||||
</h2>
|
||||
<h3
|
||||
className={`text-3xl ${vipnagorgialla.className} font-bold italic text-[#EEE5E5] pb-4`}
|
||||
>
|
||||
Külastaja
|
||||
</h3>
|
||||
<ul className="pl-4 mb-8 list-[square] marker:text-[#1F5673]">
|
||||
<li className="text-xl">Ligipääs demoalale</li>
|
||||
<li className="text-xl">Turniiride pealt vaatamine</li>
|
||||
<li className="text-xl">Võimalus osaleda miniturniiridel</li>
|
||||
</ul>
|
||||
<Link href="https://fienta.com/et/tipilan" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#1F5673] cursor-pointer ${vipnagorgialla.className} font-bold italic`}
|
||||
>
|
||||
OSTA PILET
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SectionDivider />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import SectionDivider from "@/components/SectionDivider";
|
||||
|
||||
export default function Tourney() {
|
||||
const headingStyle = `text-3xl md:text-5xl lg:text-5xl ${vipnagorgialla.className} font-bold uppercase text-[#2A2C3F] dark:text-[#EEE5E5] -skew-x-2 md:-skew-x-5`;
|
||||
|
||||
// const SectionDivider = () => <hr className="border-t-[3px] border-[#1F5673]" />;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col min-h-[90vh] mt-16">
|
||||
<h1
|
||||
className={`text-4xl md:text-5xl lg:text-6xl ${vipnagorgialla.className} font-bold italic uppercase text-[#2A2C3F] dark:text-[#EEE5E5] mt-8 md:mt-16 mb-4 m-6 md:m-16`}
|
||||
>
|
||||
Turniirid
|
||||
</h1>
|
||||
|
||||
{/*<p className="text-2xl text-[#2A2C3F] dark:text-[#EEE5E5]">*/}
|
||||
{/* Kui tahate oma oskusi proovile panna, siis vaadake siia tagasi! Rohkem*/}
|
||||
{/* infot lähiajal.*/}
|
||||
{/*</p>*/}
|
||||
|
||||
<div className="flex flex-col gap-8 md:gap-16">
|
||||
{/* CS2 turniir */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-16 items-center mx-8 md:mx-16 lg:mx-32 xl:mx-48">
|
||||
<div className="-skew-x-2 md:-skew-x-5">
|
||||
<h2 className={`${headingStyle}`}>CS2 turniir</h2>
|
||||
<p className={"text-2xl mb-4 text-neutral-500"}>
|
||||
Toimumisaeg veel selgumisel
|
||||
</p>
|
||||
<p className="text-balance">
|
||||
TipiLANil toimub Eesti ühe suurima auhinnafondiga CS2 turniire
|
||||
juba sel sügisel. Haara kaasa sõbrad ja saa osa adrenaliinirohkest
|
||||
kogemusest!
|
||||
</p>
|
||||
<br />
|
||||
<p className="text-balance">
|
||||
Auhinnafond on suuruses 5250€, mis jaotatakse TOP3 meeskonna vahel
|
||||
ära. Iga tiimiliige saab vastavalt saavutatud kohale auhinnaks kas
|
||||
600€, 300€ või 150€.
|
||||
</p>
|
||||
<br />
|
||||
|
||||
<div className={"flex flex-row flex-wrap gap-8"}>
|
||||
<Link href="/reeglid/cs2" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#1F5673] cursor-pointer ${vipnagorgialla.className} font-bold italic text-[#ECE5E5]`}
|
||||
>
|
||||
LOE REEGLEID
|
||||
</button>
|
||||
</Link>
|
||||
<a href="https://fienta.com/et/tipilan" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#007CAB] cursor-pointer ${vipnagorgialla.className} font-bold italic text-[#ECE5E5]`}
|
||||
>
|
||||
OSTA PILET
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="hidden md:block">
|
||||
<div>
|
||||
{/* Outside div needs to remain so that overflow won't occur*/}
|
||||
<Image
|
||||
src="/images/cs2_tournament_logo.png"
|
||||
alt="CS2 tournament"
|
||||
width={600}
|
||||
height={400}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SectionDivider />
|
||||
|
||||
{/* LoL turniir */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-16 items-center mx-8 md:mx-16 lg:mx-32 xl:mx-48">
|
||||
<div className="hidden md:block">
|
||||
<div>
|
||||
{/* Outside div needs to remain so that overflow won't occur*/}
|
||||
<Image
|
||||
src="/images/lol_tournament_logo.png"
|
||||
alt="LoL tournament"
|
||||
width={600}
|
||||
height={400}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-auto text-right -skew-x-2 md:-skew-x-5">
|
||||
<h2 className={`${headingStyle}`}>LoL turniir</h2>
|
||||
<p className={"text-2xl mb-4 text-neutral-500"}>
|
||||
Toimumisaeg veel selgumisel
|
||||
</p>
|
||||
<p className="text-balance">
|
||||
TipiLANil toimub Eesti ühe suurima auhinnafondiga LoL turniire
|
||||
juba sel sügisel. Haara kaasa sõbrad ja saa osa adrenaliinirohkest
|
||||
kogemusest!
|
||||
</p>
|
||||
<br />
|
||||
<p className="text-balance">
|
||||
Auhinnafond on suuruses 3500€, mis jaotatakse TOP3 meeskonna vahel
|
||||
ära. Iga tiimiliige saab vastavalt saavutatud kohale auhinnaks kas
|
||||
400€, 200€ või 100€.
|
||||
</p>
|
||||
<br />
|
||||
<div className="flex flex-row flex-wrap gap-4 md:gap-8 justify-end">
|
||||
<Link href="/kodukord" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#1F5673] cursor-pointer ${vipnagorgialla.className} font-bold italic text-[#ECE5E5]`}
|
||||
>
|
||||
LOE REEGLEID
|
||||
</button>
|
||||
</Link>
|
||||
<a href="https://fienta.com/et/tipilan" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#007CAB] cursor-pointer ${vipnagorgialla.className} font-bold italic text-[#ECE5E5]`}
|
||||
>
|
||||
OSTA PILET
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SectionDivider />
|
||||
|
||||
{/* Mini-turniirid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-16 items-center mx-8 md:mx-16 lg:mx-32 xl:mx-48">
|
||||
<div className="-skew-x-2 md:-skew-x-5">
|
||||
<h2 className={`${headingStyle}`}>Mini­turniirid</h2>
|
||||
<p className={"text-2xl mb-4 text-neutral-500"}>
|
||||
Toimumisaeg veel selgumisel
|
||||
</p>
|
||||
<p className="text-balance">
|
||||
TipiLANil toimub mitmeid erinevaid lõbusaid ja võistlushimu
|
||||
tekitavaid miniturniire. Miniturniirid toimuvad järgnevates
|
||||
mängudes: SimRacing, Tekken, FIFA, Minecraft Bedwars, Buckshot
|
||||
Roulette, LostGamer ja palju muud.
|
||||
</p>
|
||||
<br />
|
||||
<p className="text-balance">
|
||||
Auhinnafond on kõigi turniiride peale 1250€ ja reeglina saab
|
||||
rahalise auhinna miniturniiri võitja.
|
||||
</p>
|
||||
<br />
|
||||
<div className="flex flex-row flex-wrap gap-4 md:gap-8">
|
||||
<Link href="/kodukord" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#1F5673] cursor-pointer ${vipnagorgialla.className} font-bold italic text-[#ECE5E5]`}
|
||||
>
|
||||
LOE REEGLEID
|
||||
</button>
|
||||
</Link>
|
||||
<a href="https://fienta.com/et/tipilan" target="_blank">
|
||||
<button
|
||||
className={`px-4 py-2 bg-[#007CAB] cursor-pointer ${vipnagorgialla.className} font-bold italic text-[#ECE5E5]`}
|
||||
>
|
||||
OSTA PILET
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="hidden md:block">
|
||||
<div>
|
||||
{/* Outside div needs to remain so that overflow won't occur*/}
|
||||
<Image
|
||||
src="/images/minitournament_logo.png"
|
||||
alt="mini tournaments"
|
||||
width={600}
|
||||
height={400}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SectionDivider />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
import { SiDiscord, SiInstagram, SiFacebook } from "react-icons/si";
|
||||
import Image from "next/image";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
// Fonts
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
|
||||
const Footer = () => (
|
||||
const Footer = () => {
|
||||
const t = useTranslations();
|
||||
|
||||
return (
|
||||
<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">
|
||||
@@ -67,11 +71,11 @@ const Footer = () => (
|
||||
<h2
|
||||
className={`text-3xl sm:text-4xl ${vipnagorgialla.className} font-bold italic uppercase text-[#2A2C3F] dark:text-[#EEE5E5] mt-8 mb-4`}
|
||||
>
|
||||
Kontakt
|
||||
{t("footer.contact")}
|
||||
</h2>
|
||||
<div className="flex flex-row justify-between gap-4 items-center">
|
||||
<div>
|
||||
<h3 className="text-xl font-bold">IT-teaduskonna üliõpilaskogu</h3>
|
||||
<h3 className="text-xl font-bold">{t("footer.studentUnion")}</h3>
|
||||
<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]">
|
||||
@@ -90,10 +94,12 @@ const Footer = () => (
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<h3 className="text-xl font-bold pt-4">MTÜ For Tsükkel</h3>
|
||||
<h3 className="text-xl font-bold pt-4">
|
||||
{t("footer.organization")}
|
||||
</h3>
|
||||
<div>
|
||||
<p className="text-[#aaa]">
|
||||
Registrikood:{" "}
|
||||
{t("footer.registrationCode")}:{" "}
|
||||
<span className="font-semibold text-[#007CAB] dark:text-[#00A3E0]">
|
||||
80391807
|
||||
</span>
|
||||
@@ -107,5 +113,6 @@ const Footer = () => (
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Footer;
|
||||
|
||||
@@ -12,6 +12,8 @@ import {
|
||||
// Theme Provider
|
||||
import { useTheme } from "next-themes";
|
||||
|
||||
import LanguageSwitcher from "./LanguageSwitcher";
|
||||
|
||||
// Shadcn UI
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
@@ -24,24 +26,30 @@ import {
|
||||
// Fonts
|
||||
// import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
|
||||
const Header = ({
|
||||
isOpen,
|
||||
toggleSidebar,
|
||||
}: {
|
||||
interface HeaderProps {
|
||||
isOpen: boolean;
|
||||
toggleSidebar: () => void;
|
||||
}) => {
|
||||
onToggle: () => void;
|
||||
themeLabels: {
|
||||
light: string;
|
||||
dark: string;
|
||||
system: string;
|
||||
};
|
||||
}
|
||||
|
||||
const Header = ({ isOpen, onToggle, themeLabels }: HeaderProps) => {
|
||||
const { theme, setTheme } = useTheme();
|
||||
|
||||
return (
|
||||
<header className="px-8 py-2 md:px-12 flex items-center bg-[#EEE5E5] dark:bg-[#0E0F19] border-b-3 border-[#1F5673] justify-between text-[#2A2C3F] dark:text-[#EEE5E5]">
|
||||
<button onClick={toggleSidebar}>
|
||||
<button onClick={onToggle}>
|
||||
{isOpen ? (
|
||||
<MdClose className="h-12 w-12 text-[#2A2C3F] dark:text-[#EEE5E5] cursor-pointer" />
|
||||
) : (
|
||||
<MdMenu className="h-12 w-12 text-[#2A2C3F] dark:text-[#EEE5E5] cursor-pointer" />
|
||||
)}
|
||||
</button>
|
||||
<div className="flex items-center gap-2">
|
||||
<LanguageSwitcher />
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
@@ -61,15 +69,17 @@ const Header = ({
|
||||
disabled={theme === "light"}
|
||||
>
|
||||
<MdSunny className={theme === "light" ? "text-amber-500" : ""} />
|
||||
<span>Hele</span>
|
||||
<span>{themeLabels.light}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
className={`text-lg ${theme === "dark" ? "bg-accent/50 font-medium" : ""}`}
|
||||
onClick={() => setTheme("dark")}
|
||||
disabled={theme === "dark"}
|
||||
>
|
||||
<MdModeNight className={theme === "dark" ? "text-blue-500" : ""} />
|
||||
<span>Tume</span>
|
||||
<MdModeNight
|
||||
className={theme === "dark" ? "text-blue-500" : ""}
|
||||
/>
|
||||
<span>{themeLabels.dark}</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
className={`text-lg ${theme === "system" ? "bg-accent/50 font-medium" : ""}`}
|
||||
@@ -79,10 +89,11 @@ const Header = ({
|
||||
<MdComputer
|
||||
className={theme === "system" ? "text-green-500" : ""}
|
||||
/>
|
||||
<span>Süsteemipõhine</span>
|
||||
<span>{themeLabels.system}</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
47
src/components/LanguageSwitcher.tsx
Normal file
47
src/components/LanguageSwitcher.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
"use client";
|
||||
|
||||
import { useLocale } from "next-intl";
|
||||
import { useRouter, usePathname } from "@/i18n/routing";
|
||||
import { routing } from "@/i18n/routing";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
|
||||
export default function LanguageSwitcher() {
|
||||
const locale = useLocale();
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
|
||||
const getNextLocale = (): "et" | "en" => {
|
||||
const currentIndex = routing.locales.indexOf(locale as "et" | "en");
|
||||
const nextIndex = (currentIndex + 1) % routing.locales.length;
|
||||
return routing.locales[nextIndex] as "et" | "en";
|
||||
};
|
||||
|
||||
const getNextLanguageName = () => {
|
||||
const nextLocale = getNextLocale();
|
||||
switch (nextLocale) {
|
||||
case "et":
|
||||
return "EST";
|
||||
case "en":
|
||||
return "ENG";
|
||||
default:
|
||||
return nextLocale;
|
||||
}
|
||||
};
|
||||
|
||||
const handleLanguageSwitch = () => {
|
||||
const nextLocale = getNextLocale();
|
||||
router.replace(pathname, { locale: nextLocale });
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={handleLanguageSwitch}
|
||||
variant="ghost"
|
||||
size="lg"
|
||||
className={`${vipnagorgialla.className} text-3xl font-bold italic uppercase hover:bg-[#007CAB]/10 dark:hover:bg-[#00A3E0]/10 text-[#007CAB] dark:text-[#00A3E0] hover:text-[#2A2C3F] dark:hover:text-[#EEE5E5] transition-colors`}
|
||||
>
|
||||
{getNextLanguageName()}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
"use client";
|
||||
|
||||
// Fonts
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
|
||||
// Use effect to handle route changes and close the sidebar if it's open
|
||||
// usePathName to listen to route changes in Next.js
|
||||
import { useEffect } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
|
||||
const Sidebar = ({
|
||||
isOpen,
|
||||
toggleSidebar,
|
||||
}: {
|
||||
isOpen: boolean;
|
||||
toggleSidebar: () => void;
|
||||
}) => {
|
||||
const pathname = usePathname();
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
toggleSidebar();
|
||||
}
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="fixed inset-0 backdrop-blur mt-16 z-20"
|
||||
style={{ display: isOpen ? "block" : "none" }}
|
||||
onClick={toggleSidebar} // Close sidebar when clicking outside
|
||||
></div>
|
||||
<div
|
||||
className={`text-3xl md:text-5xl ${vipnagorgialla.className} font-bold italic uppercase fixed flex items-start xs:pl-25 pl-20 sm:pl-20 md:pl-24 flex-col gap-8 pt-16 top-0 left-0 h-[99vh] mt-16 -skew-x-5 border-r-3 border-[#1F5673] w-screen sm:w-96 md:w-128 bg-[#EEE5E5] dark:bg-[#0E0F19] text-[#2A2C3F] dark:text-[#EEE5E5] transition-transform transform z-20`}
|
||||
style={{
|
||||
transform: isOpen
|
||||
? "translateX(-13%) skewX(calc(5deg * -1)"
|
||||
: "translateX(-150%) skewX(calc(5deg * -1)",
|
||||
}}
|
||||
>
|
||||
<Link href="/" className="hover:text-[#00A3E0] transition duration-150">
|
||||
Avaleht
|
||||
</Link>
|
||||
<Link
|
||||
href="/messiala"
|
||||
className="hover:text-[#00A3E0] transition duration-150"
|
||||
>
|
||||
Messiala
|
||||
</Link>
|
||||
<Link
|
||||
href="/piletid"
|
||||
className="hover:text-[#00A3E0] transition duration-150"
|
||||
>
|
||||
Piletid
|
||||
</Link>
|
||||
<Link
|
||||
href="/ajakava"
|
||||
className="hover:text-[#00A3E0] transition duration-150"
|
||||
>
|
||||
Ajakava
|
||||
</Link>
|
||||
<Link
|
||||
href="/turniirid"
|
||||
className="hover:text-[#00A3E0] transition duration-150"
|
||||
>
|
||||
Turniirid
|
||||
</Link>
|
||||
<Link
|
||||
href="/kodukord"
|
||||
className="hover:text-[#00A3E0] transition duration-150"
|
||||
>
|
||||
Kodukord
|
||||
</Link>
|
||||
<Link
|
||||
href="/reeglid"
|
||||
className="hover:text-[#00A3E0] transition duration-150"
|
||||
>
|
||||
Reeglid
|
||||
</Link>
|
||||
|
||||
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Sidebar;
|
||||
84
src/components/SidebarLayoutClient.tsx
Normal file
84
src/components/SidebarLayoutClient.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { usePathname } from "@/i18n/routing";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { vipnagorgialla } from "@/components/Vipnagorgialla";
|
||||
import Header from "./Header";
|
||||
|
||||
interface NavItem {
|
||||
href:
|
||||
| "/"
|
||||
| "/ajakava"
|
||||
| "/haldus"
|
||||
| "/kodukord"
|
||||
| "/messiala"
|
||||
| "/piletid"
|
||||
| "/reeglid"
|
||||
| "/striim"
|
||||
| "/turniirid";
|
||||
label: string;
|
||||
}
|
||||
|
||||
interface SidebarLayoutClientProps {
|
||||
themeLabels: {
|
||||
light: string;
|
||||
dark: string;
|
||||
system: string;
|
||||
};
|
||||
navItems: NavItem[];
|
||||
}
|
||||
|
||||
export default function SidebarLayoutClient({
|
||||
themeLabels,
|
||||
navItems,
|
||||
}: SidebarLayoutClientProps) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const pathname = usePathname();
|
||||
|
||||
const toggleSidebar = () => setIsOpen(!isOpen);
|
||||
|
||||
// Close sidebar when route changes
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header
|
||||
isOpen={isOpen}
|
||||
onToggle={toggleSidebar}
|
||||
themeLabels={themeLabels}
|
||||
/>
|
||||
|
||||
{/* Sidebar */}
|
||||
<>
|
||||
<div
|
||||
className="fixed inset-0 backdrop-blur mt-16 z-20"
|
||||
style={{ display: isOpen ? "block" : "none" }}
|
||||
onClick={() => setIsOpen(false)}
|
||||
></div>
|
||||
<div
|
||||
className={`text-3xl md:text-4xl ${vipnagorgialla.className} font-bold break-all italic uppercase fixed flex items-start xs:pl-25 pl-20 sm:pl-20 md:pl-24 flex-col gap-8 pt-16 top-0 left-0 h-[99vh] mt-16 -skew-x-5 border-r-3 border-[#1F5673] w-screen sm:w-96 md:w-128 bg-[#EEE5E5] dark:bg-[#0E0F19] text-[#2A2C3F] dark:text-[#EEE5E5] transition-transform transform z-20`}
|
||||
style={{
|
||||
transform: isOpen
|
||||
? "translateX(-13%) skewX(calc(5deg * -1)"
|
||||
: "translateX(-150%) skewX(calc(5deg * -1)",
|
||||
}}
|
||||
>
|
||||
{navItems.map((item) => (
|
||||
<Link
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
className="hover:text-[#00A3E0] transition duration-150"
|
||||
>
|
||||
{item.label}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
</>
|
||||
);
|
||||
}
|
||||
26
src/components/SidebarLayoutServer.tsx
Normal file
26
src/components/SidebarLayoutServer.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import SidebarLayoutClient from "./SidebarLayoutClient";
|
||||
|
||||
export default async function SidebarLayoutServer() {
|
||||
const t = await getTranslations("common");
|
||||
|
||||
const themeLabels = {
|
||||
light: t("theme.light"),
|
||||
dark: t("theme.dark"),
|
||||
system: t("theme.system"),
|
||||
};
|
||||
|
||||
const navT = await getTranslations("navigation");
|
||||
|
||||
const navItems = [
|
||||
{ href: "/" as const, label: navT("home") },
|
||||
{ href: "/messiala" as const, label: navT("expo") },
|
||||
{ href: "/piletid" as const, label: navT("tickets") },
|
||||
{ href: "/ajakava" as const, label: navT("schedule") },
|
||||
{ href: "/turniirid" as const, label: navT("tournaments") },
|
||||
{ href: "/kodukord" as const, label: navT("houserules") },
|
||||
{ href: "/reeglid" as const, label: navT("rules") },
|
||||
];
|
||||
|
||||
return <SidebarLayoutClient themeLabels={themeLabels} navItems={navItems} />;
|
||||
}
|
||||
@@ -1,22 +1,14 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from "react";
|
||||
import Header from "./Header";
|
||||
import Sidebar from "./Sidebar";
|
||||
import SidebarLayoutServer from "./SidebarLayoutServer";
|
||||
|
||||
const SidebarParent = () => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const toggleSidebar = () => setIsOpen(!isOpen);
|
||||
|
||||
return (
|
||||
<div className="fixed w-screen top-0 z-9999">
|
||||
<Header isOpen={isOpen} toggleSidebar={toggleSidebar} />
|
||||
<Sidebar isOpen={isOpen} toggleSidebar={toggleSidebar}/>
|
||||
<SidebarLayoutServer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// This component is responsible for rendering the sidebar and header together.
|
||||
// It manages the state of the sidebar (open/closed) and passes the necessary props to both the Header and Sidebar components.
|
||||
// Server-side translations are handled by SidebarLayoutServer.
|
||||
|
||||
export default SidebarParent;
|
||||
@@ -1,33 +1,68 @@
|
||||
export type ScheduleItem = {
|
||||
time?: string; // Aeg on ajutine praegu kuna pole 100% kindlalt paigas
|
||||
title: string;
|
||||
location: string;
|
||||
titleKey: string;
|
||||
locationKey: string;
|
||||
description?: string;
|
||||
};
|
||||
|
||||
export const scheduleData: Record<string, ScheduleItem[]> = {
|
||||
"24. oktoober": [
|
||||
oct24: [
|
||||
{
|
||||
title: "League of Legends põhiturniir",
|
||||
location: "Aula",
|
||||
time: "-",
|
||||
titleKey: "schedule.events.doorsOpen",
|
||||
locationKey: "schedule.locations.registrationSetup",
|
||||
time: "17:00",
|
||||
},
|
||||
{
|
||||
title: "Miniturniirid",
|
||||
location: "Tudengimaja",
|
||||
time: "-",
|
||||
titleKey: "schedule.events.mainTournamentsStart",
|
||||
locationKey: "schedule.locations.auditorium",
|
||||
time: "20:00",
|
||||
},
|
||||
{
|
||||
titleKey: "schedule.events.miniTournamentsKickoff",
|
||||
locationKey: "schedule.locations.studentHouse",
|
||||
time: "18:00",
|
||||
},
|
||||
{
|
||||
titleKey: "schedule.events.fightingGamesStart",
|
||||
locationKey: "schedule.locations.studentHouse",
|
||||
time: "18:30",
|
||||
},
|
||||
{
|
||||
titleKey: "schedule.events.doorsClose",
|
||||
locationKey: "schedule.locations.auditoriumAndStudentHouse",
|
||||
time: "*01:00",
|
||||
},
|
||||
],
|
||||
"25. oktoober": [
|
||||
oct25: [
|
||||
{
|
||||
title: "Counter-Strike 2 põhiturniir",
|
||||
location: "Aula",
|
||||
time: "-",
|
||||
titleKey: "schedule.events.doorsOpen",
|
||||
locationKey: "schedule.locations.auditoriumAndStudentHouse",
|
||||
time: "10:00",
|
||||
},
|
||||
{
|
||||
title: "Miniturniirid",
|
||||
location: "Tudengimaja",
|
||||
time: "-",
|
||||
titleKey: "schedule.events.miniTournamentsStart",
|
||||
locationKey: "schedule.locations.studentHouse",
|
||||
time: "11:00",
|
||||
},
|
||||
{
|
||||
titleKey: "schedule.events.granblue",
|
||||
locationKey: "schedule.locations.studentHouse",
|
||||
time: "11:30",
|
||||
},
|
||||
{
|
||||
titleKey: "schedule.events.mainTournamentsStart",
|
||||
locationKey: "schedule.locations.auditorium",
|
||||
time: "12:00",
|
||||
},
|
||||
{
|
||||
titleKey: "schedule.events.granTurismo",
|
||||
locationKey: "schedule.locations.studentHouse",
|
||||
time: "20:00",
|
||||
},
|
||||
{
|
||||
titleKey: "schedule.events.doorsClose",
|
||||
locationKey: "schedule.locations.auditoriumAndStudentHouse",
|
||||
time: "*01:00",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
17
src/i18n/request.ts
Normal file
17
src/i18n/request.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { getRequestConfig } from "next-intl/server";
|
||||
import { routing } from "./routing";
|
||||
|
||||
export default getRequestConfig(async ({ requestLocale }) => {
|
||||
// This typically corresponds to the `[locale]` segment
|
||||
let locale = await requestLocale;
|
||||
|
||||
// Ensure that a valid locale is used
|
||||
if (!locale || !routing.locales.includes(locale as "et" | "en")) {
|
||||
locale = routing.defaultLocale;
|
||||
}
|
||||
|
||||
return {
|
||||
locale: locale!,
|
||||
messages: (await import(`../../translations/${locale}.json`)).default,
|
||||
};
|
||||
});
|
||||
55
src/i18n/routing.ts
Normal file
55
src/i18n/routing.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { defineRouting } from "next-intl/routing";
|
||||
import { createNavigation } from "next-intl/navigation";
|
||||
|
||||
export const routing = defineRouting({
|
||||
// A list of all locales that are supported
|
||||
locales: ["et", "en"],
|
||||
|
||||
// Used when no locale matches
|
||||
defaultLocale: "et",
|
||||
|
||||
// The `pathnames` object holds pairs of internal and
|
||||
// external paths. The external paths are shown in the URL.
|
||||
pathnames: {
|
||||
// If all locales use the same pathname, a single
|
||||
// external path can be used for all locales
|
||||
"/": "/",
|
||||
"/ajakava": {
|
||||
et: "/ajakava",
|
||||
en: "/schedule",
|
||||
},
|
||||
"/haldus": {
|
||||
et: "/haldus",
|
||||
en: "/admin",
|
||||
},
|
||||
"/kodukord": {
|
||||
et: "/kodukord",
|
||||
en: "/rules",
|
||||
},
|
||||
"/messiala": {
|
||||
et: "/messiala",
|
||||
en: "/expo",
|
||||
},
|
||||
"/piletid": {
|
||||
et: "/piletid",
|
||||
en: "/tickets",
|
||||
},
|
||||
"/reeglid": {
|
||||
et: "/reeglid",
|
||||
en: "/regulations",
|
||||
},
|
||||
"/striim": {
|
||||
et: "/striim",
|
||||
en: "/stream",
|
||||
},
|
||||
"/turniirid": {
|
||||
et: "/turniirid",
|
||||
en: "/tournaments",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Lightweight wrappers around Next.js' navigation APIs
|
||||
// that will consider the routing configuration
|
||||
export const { Link, redirect, usePathname, useRouter } =
|
||||
createNavigation(routing);
|
||||
20
src/middleware.ts
Normal file
20
src/middleware.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import createMiddleware from 'next-intl/middleware';
|
||||
import {routing} from './i18n/routing';
|
||||
|
||||
export default createMiddleware(routing);
|
||||
|
||||
export const config = {
|
||||
// Match only internationalized pathnames
|
||||
matcher: [
|
||||
// Enable a redirect to a matching locale at the root
|
||||
'/',
|
||||
|
||||
// Set a cookie to remember the previous locale for
|
||||
// all requests that have a locale prefix
|
||||
'/(et|en)/:path*',
|
||||
|
||||
// Enable redirects that add missing locales
|
||||
// (e.g. `/pathnames` -> `/en/pathnames`)
|
||||
'/((?!_next|_vercel|.*\\..*).*)'
|
||||
]
|
||||
};
|
||||
216
translations/en.json
Normal file
216
translations/en.json
Normal file
@@ -0,0 +1,216 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Home",
|
||||
"schedule": "Schedule",
|
||||
"admin": "Admin",
|
||||
"houserules": "House rules",
|
||||
"expo": "Expo",
|
||||
"tickets": "Tickets",
|
||||
"rules": "Rules",
|
||||
"stream": "Stream",
|
||||
"tournaments": "Tournaments"
|
||||
},
|
||||
"common": {
|
||||
"loading": "Loading...",
|
||||
"error": "Error",
|
||||
"success": "Success",
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
"delete": "Delete",
|
||||
"edit": "Edit",
|
||||
"close": "Close",
|
||||
"next": "Next",
|
||||
"previous": "Previous",
|
||||
"search": "Search",
|
||||
"filter": "Filter",
|
||||
"reset": "Reset",
|
||||
"theme": {
|
||||
"light": "Light",
|
||||
"dark": "Dark",
|
||||
"system": "System"
|
||||
},
|
||||
"language": {
|
||||
"et": "Eesti",
|
||||
"en": "English"
|
||||
}
|
||||
},
|
||||
"home": {
|
||||
"title": "TipiLAN 2025",
|
||||
"subtitle": "Estonia's largest student-organized LAN event!",
|
||||
"welcome": "Welcome to TipiLAN 2025!",
|
||||
"description": "Join us at Estonia's largest student-organized LAN event. Games, competitions and much more await you!",
|
||||
"sections": {
|
||||
"schedule": {
|
||||
"description": "TipiLAN is packed with exciting tournaments, mini-competitions and much more."
|
||||
},
|
||||
"tournaments": {
|
||||
"description": "TipiLAN features massive CS2 and LoL tournaments with a prize pool of €10,000."
|
||||
},
|
||||
"expo": {
|
||||
"description": "The TipiLAN expo area hosts companies, additional activities and lectures."
|
||||
},
|
||||
"reserveSpot": "Reserve your spot today!",
|
||||
"poweredBy": "TipiLAN is powered by..."
|
||||
}
|
||||
},
|
||||
"tickets": {
|
||||
"title": "TICKETS AND REGISTRATION",
|
||||
"buyNow": "Buy now",
|
||||
"soldOut": "Sold out",
|
||||
"available": "Available",
|
||||
"price": "Price",
|
||||
"includes": "Includes",
|
||||
"computerParticipant": {
|
||||
"title": "Computer Participant",
|
||||
"price": "8€",
|
||||
"features": [
|
||||
"Personal desk, power and internet connection",
|
||||
"Access to demo area",
|
||||
"Tournament spectating",
|
||||
"Ability to participate in mini-tournaments"
|
||||
]
|
||||
},
|
||||
"competitor": {
|
||||
"title": "Competitor",
|
||||
"price": "12-15€",
|
||||
"features": [
|
||||
"Ability to participate in the CS2 or LoL tournament",
|
||||
"Personal desk, power and internet connection",
|
||||
"Access to demo area",
|
||||
"Tournament spectating",
|
||||
"Ability to participate in mini-tournaments"
|
||||
]
|
||||
},
|
||||
"visitor": {
|
||||
"title": "Visitor",
|
||||
"price": "6€",
|
||||
"features": [
|
||||
"Access to demo area",
|
||||
"Tournament spectating",
|
||||
"Ability to participate in mini-tournaments"
|
||||
]
|
||||
},
|
||||
"buyTicket": "BUY TICKETS"
|
||||
},
|
||||
"tournaments": {
|
||||
"title": "Tournaments",
|
||||
"register": "Register",
|
||||
"participants": "Participants",
|
||||
"prizePool": "Prize pool",
|
||||
"schedule": "Schedule",
|
||||
"rules": "Rules",
|
||||
"cs2": {
|
||||
"title": "CS2 Tournament",
|
||||
"timing": "Timing to be announced",
|
||||
"description1": "TipiLAN hosts one of Estonia's largest CS2 tournaments with a significant prize pool this fall. Grab your friends and experience the adrenaline rush!",
|
||||
"description2": "The prize pool is €5,250, distributed among the TOP3 teams. Each team member receives €600, €300, or €150 based on their placement.",
|
||||
"readRules": "READ RULES",
|
||||
"buyTicket": "BUY TICKETS"
|
||||
},
|
||||
"lol": {
|
||||
"title": "LoL Tournament",
|
||||
"timing": "Timing to be announced",
|
||||
"description1": "TipiLAN hosts one of Estonia's largest LoL tournaments with a significant prize pool this fall. Grab your friends and experience the adrenaline rush!",
|
||||
"description2": "The prize pool is €3,500, distributed among the TOP3 teams. Each team member receives €400, €200, or €100 based on their placement.",
|
||||
"readRules": "READ RULES",
|
||||
"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.",
|
||||
"description2": "The total prize pool for all tournaments is €1,250 and typically the mini-tournament winner receives a cash prize.",
|
||||
"readRules": "READ RULES",
|
||||
"buyTicket": "BUY TICKETS"
|
||||
}
|
||||
},
|
||||
"schedule": {
|
||||
"title": "Schedule",
|
||||
"day": "Day",
|
||||
"time": "Time",
|
||||
"event": "Event",
|
||||
"location": "Location",
|
||||
"oct24": "October 24th",
|
||||
"oct25": "October 25th",
|
||||
"events": {
|
||||
"doorsOpen": "Doors open",
|
||||
"mainTournamentsStart": "Main tournaments begin",
|
||||
"miniTournamentsKickoff": "Mini-tournaments kick-off",
|
||||
"fightingGamesStart": "Fighting game tournaments start",
|
||||
"doorsClose": "Doors close",
|
||||
"miniTournamentsStart": "Mini-tournaments begin",
|
||||
"granblue": "Granblue tournament",
|
||||
"granTurismo": "Gran Turismo tournament"
|
||||
},
|
||||
"locations": {
|
||||
"registrationSetup": "Registration and setup in auditorium",
|
||||
"auditorium": "Auditorium",
|
||||
"studentHouse": "Student House (Tudengimaja)",
|
||||
"auditoriumAndStudentHouse": "Auditorium and Student House"
|
||||
}
|
||||
},
|
||||
"stream": {
|
||||
"title": "Stream",
|
||||
"live": "Live",
|
||||
"offline": "Offline",
|
||||
"watchNow": "Watch now"
|
||||
},
|
||||
"footer": {
|
||||
"copyright": "© 2025 TipiLAN. All rights reserved.",
|
||||
"contact": "Contact",
|
||||
"privacy": "Privacy",
|
||||
"terms": "Terms",
|
||||
"studentUnion": "IT Faculty Student Council",
|
||||
"organization": "MTÜ For Tsükkel",
|
||||
"registrationCode": "Registration code"
|
||||
},
|
||||
"notFound": {
|
||||
"title": "404",
|
||||
"message": "We couldn't find this page."
|
||||
},
|
||||
"expo": {
|
||||
"title": "Expo Area",
|
||||
"description": "The TipiLAN expo area hosts companies, additional activities and lectures.",
|
||||
"areas": {
|
||||
"bar": "Bar Area",
|
||||
"boardGames": "Board Games Area",
|
||||
"simRacing": "Red Bull Sim Racing",
|
||||
"fighting": "Fighting Games Area"
|
||||
},
|
||||
"hide": "Hide",
|
||||
"show": "Show"
|
||||
},
|
||||
"rules": {
|
||||
"title": "Rules",
|
||||
"houseRules": "House Rules",
|
||||
"cs2Rules": "CS2 Rules",
|
||||
"lolRules": "LoL Rules"
|
||||
},
|
||||
"admin": {
|
||||
"title": "Admin",
|
||||
"users": "Users",
|
||||
"teams": "Teams",
|
||||
"success": {
|
||||
"title": "Operation was successful!",
|
||||
"description": "Database data has been updated."
|
||||
},
|
||||
"sync": {
|
||||
"title": "Do you want to update the database?",
|
||||
"description1": "This will pull current data from Fienta and replace",
|
||||
"all": "ALL",
|
||||
"description2": "existing data in the database!",
|
||||
"warning": "If you're not sure, click \"Cancel\".",
|
||||
"update": "Update"
|
||||
},
|
||||
"roles": {
|
||||
"captain": "Captain",
|
||||
"teammate": "Teammate"
|
||||
},
|
||||
"table": {
|
||||
"name": "Name",
|
||||
"members": "Members",
|
||||
"noMembers": "No members"
|
||||
}
|
||||
}
|
||||
}
|
||||
215
translations/et.json
Normal file
215
translations/et.json
Normal file
@@ -0,0 +1,215 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Avaleht",
|
||||
"schedule": "Ajakava",
|
||||
"admin": "Haldus",
|
||||
"houserules": "Kodukord",
|
||||
"expo": "Messiala",
|
||||
"tickets": "Piletid",
|
||||
"rules": "Reeglid",
|
||||
"stream": "Striim",
|
||||
"tournaments": "Turniirid"
|
||||
},
|
||||
"common": {
|
||||
"loading": "Laadimine...",
|
||||
"error": "Viga",
|
||||
"success": "Õnnestus",
|
||||
"save": "Salvesta",
|
||||
"cancel": "Tühista",
|
||||
"delete": "Kustuta",
|
||||
"edit": "Muuda",
|
||||
"close": "Sulge",
|
||||
"next": "Järgmine",
|
||||
"previous": "Eelmine",
|
||||
"search": "Otsi",
|
||||
"filter": "Filtreeri",
|
||||
"reset": "Lähtesta",
|
||||
"theme": {
|
||||
"light": "Hele",
|
||||
"dark": "Tume",
|
||||
"system": "Süsteemipõhine"
|
||||
},
|
||||
"language": {
|
||||
"et": "Eesti",
|
||||
"en": "English"
|
||||
}
|
||||
},
|
||||
"home": {
|
||||
"title": "TipiLAN 2025",
|
||||
"subtitle": "Eesti suurim tudengite korraldatud LAN!",
|
||||
"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!",
|
||||
"sections": {
|
||||
"schedule": {
|
||||
"description": "TipiLAN on pungil põnevatest turniiridest, mini-võistlustest ja paljust muust."
|
||||
},
|
||||
"tournaments": {
|
||||
"description": "TipiLANil toimuvad suurejoonelised CS2 ja LoL turniirid, mille auhinnafond on 10 000€."
|
||||
},
|
||||
"expo": {
|
||||
"description": "TipiLANi messialal paiknevad ettevõtted, lisategevused ja toimuvad loengud."
|
||||
},
|
||||
"reserveSpot": "Broneeri oma koht juba täna!",
|
||||
"poweredBy": "TipiLANi tõmbab käima..."
|
||||
}
|
||||
},
|
||||
"tickets": {
|
||||
"title": "PILETID JA REGISTREERIMINE",
|
||||
"buyNow": "Osta nüüd",
|
||||
"soldOut": "Välja müüdud",
|
||||
"available": "Saadaval",
|
||||
"price": "Hind",
|
||||
"includes": "Sisaldab",
|
||||
"computerParticipant": {
|
||||
"title": "Arvutiga osaleja",
|
||||
"price": "8€",
|
||||
"features": [
|
||||
"Isiklik laud, voolu- ja internetiühendus",
|
||||
"Ligipääs demoalale",
|
||||
"Turniiride pealt vaatamine",
|
||||
"Võimalus osaleda miniturniiridel"
|
||||
]
|
||||
},
|
||||
"competitor": {
|
||||
"title": "Võistleja",
|
||||
"price": "12-15€",
|
||||
"features": [
|
||||
"Võimalus osaleda CS2 või LoL turniiril",
|
||||
"Isiklik laud, voolu- ja internetiühendus",
|
||||
"Ligipääs demoalale",
|
||||
"Turniiride pealt vaatamine",
|
||||
"Võimalus osaleda miniturniiridel"
|
||||
]
|
||||
},
|
||||
"visitor": {
|
||||
"title": "Külastaja",
|
||||
"price": "6€",
|
||||
"features": [
|
||||
"Ligipääs demoalale",
|
||||
"Turniiride pealt vaatamine",
|
||||
"Võimalus osaleda miniturniiridel"
|
||||
]
|
||||
},
|
||||
"buyTicket": "OSTA PILET"
|
||||
},
|
||||
"tournaments": {
|
||||
"title": "Turniirid",
|
||||
"register": "Registreeru",
|
||||
"participants": "Osalejad",
|
||||
"prizePool": "Auhinnafond",
|
||||
"schedule": "Ajakava",
|
||||
"rules": "Reeglid",
|
||||
"cs2": {
|
||||
"title": "CS2 turniir",
|
||||
"timing": "Toimumisaeg veel selgumisel",
|
||||
"description1": "TipiLANil toimub Eesti ühe suurima auhinnafondiga CS2 turniire juba sel sügisel. Haara kaasa sõbrad ja saa osa adrenaliinirohkest kogemusest!",
|
||||
"description2": "Auhinnafond on suuruses 5250€, mis jaotatakse TOP3 meeskonna vahel ära. Iga tiimiliige saab vastavalt saavutatud kohale auhinnaks kas 600€, 300€ või 150€.",
|
||||
"readRules": "LOE REEGLEID",
|
||||
"buyTicket": "OSTA PILET"
|
||||
},
|
||||
"lol": {
|
||||
"title": "LoL turniir",
|
||||
"timing": "Toimumisaeg veel selgumisel",
|
||||
"description1": "TipiLANil toimub Eesti ühe suurima auhinnafondiga LoL turniire juba sel sügisel. Haara kaasa sõbrad ja saa osa adrenaliinirohkest kogemusest!",
|
||||
"description2": "Auhinnafond on suuruses 3500€, mis jaotatakse TOP3 meeskonna vahel ära. Iga tiimiliige saab vastavalt saavutatud kohale auhinnaks kas 400€, 200€ või 100€.",
|
||||
"readRules": "LOE REEGLEID",
|
||||
"buyTicket": "OSTA PILET"
|
||||
},
|
||||
"mini": {
|
||||
"title": "Miniturniirid",
|
||||
"timing": "Toimumisaeg veel selgumisel",
|
||||
"description1": "TipiLANil toimub mitmeid erinevaid lõbusaid ja võistlushimu tekitavaid miniturniire. Miniturniirid toimuvad järgnevates mängudes: SimRacing, Tekken, FIFA, Minecraft Bedwars, Buckshot Roulette, LostGamer ja palju muud.",
|
||||
"description2": "Auhinnafond on kõigi turniiride peale 1250€ ja reeglina saab rahalise auhinna miniturniiri võitja.",
|
||||
"readRules": "LOE REEGLEID",
|
||||
"buyTicket": "OSTA PILET"
|
||||
}
|
||||
},
|
||||
"schedule": {
|
||||
"title": "Ajakava",
|
||||
"day": "Päev",
|
||||
"time": "Aeg",
|
||||
"event": "Sündmus",
|
||||
"location": "Asukoht",
|
||||
"oct24": "24. oktoober",
|
||||
"oct25": "25. oktoober",
|
||||
"events": {
|
||||
"doorsOpen": "Uksed avatakse",
|
||||
"mainTournamentsStart": "Põhiturniirid algavad",
|
||||
"miniTournamentsKickoff": "Miniturniiride kick-off",
|
||||
"fightingGamesStart": "Fighting games turniiride algus",
|
||||
"doorsClose": "Uksed suletakse",
|
||||
"miniTournamentsStart": "Miniturniirid algavad",
|
||||
"granblue": "Granblue turniir",
|
||||
"granTurismo": "Gran Turismo turniir"
|
||||
},
|
||||
"locations": {
|
||||
"registrationSetup": "Registreerimine ja setup aulas",
|
||||
"auditorium": "Aula",
|
||||
"studentHouse": "Tudengimaja",
|
||||
"auditoriumAndStudentHouse": "Aula ja Tudengimaja"
|
||||
}
|
||||
},
|
||||
"stream": {
|
||||
"title": "Striim",
|
||||
"live": "Otse-eetris",
|
||||
"offline": "Väljas",
|
||||
"watchNow": "Vaata nüüd"
|
||||
},
|
||||
"footer": {
|
||||
"copyright": "© 2025 TipiLAN. Kõik õigused kaitstud.",
|
||||
"contact": "Kontakt",
|
||||
"privacy": "Privaatsus",
|
||||
"terms": "Tingimused",
|
||||
"studentUnion": "IT-teaduskonna üliõpilaskogu",
|
||||
"organization": "MTÜ For Tsükkel",
|
||||
"registrationCode": "Registrikood"
|
||||
},
|
||||
"notFound": {
|
||||
"title": "404",
|
||||
"message": "Seda lehte me ei leidnud."
|
||||
},
|
||||
"expo": {
|
||||
"title": "Messiala",
|
||||
"description": "TipiLANi messialal paiknevad ettevõtted, lisategevused ja toimuvad loengud.",
|
||||
"areas": {
|
||||
"bar": "Baariala",
|
||||
"boardGames": "Lauamängude ala",
|
||||
"simRacing": "Red Bull Sim Racing",
|
||||
"fighting": "Võitlusmängu ala"
|
||||
},
|
||||
"hide": "Peida",
|
||||
"show": "Näita"
|
||||
},
|
||||
"rules": {
|
||||
"title": "Reeglid",
|
||||
"houseRules": "Kodukord",
|
||||
"cs2Rules": "CS2 Reeglid",
|
||||
"lolRules": "LoL Reeglid"
|
||||
},
|
||||
"admin": {
|
||||
"title": "Haldus",
|
||||
"users": "Kasutajaid",
|
||||
"teams": "Meeskondasid",
|
||||
"success": {
|
||||
"title": "Toiming oli edukas!",
|
||||
"description": "Andmebaasi andmed on uuendatud."
|
||||
},
|
||||
"sync": {
|
||||
"title": "Kas soovite värskendada andmebaasi?",
|
||||
"description1": "See tõmbab Fientast praegused andmed ning asendab",
|
||||
"all": "KÕIK",
|
||||
"description2": "olemasolevad andmed andmebaasis!",
|
||||
"warning": "Kui sa ei ole kindel, vajuta \"Tühista\".",
|
||||
"update": "Värskenda"
|
||||
},
|
||||
"roles": {
|
||||
"captain": "Kapten",
|
||||
"teammate": "Meeskonnaliige"
|
||||
},
|
||||
"table": {
|
||||
"name": "Nimi",
|
||||
"members": "Liikmed",
|
||||
"noMembers": "Liikmeid puuduvad"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user