Compare commits
7 commits
50ded1089c
...
892ca8a79a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
892ca8a79a | ||
|
|
2a4c2ca392 | ||
|
|
34330d9d1f | ||
|
|
3fb06c523d | ||
|
|
3e11459bbb | ||
|
|
401b8046ec | ||
|
|
09038467f2 |
BIN
public/apple-touch-icon.png
Normal file
BIN
public/apple-touch-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
BIN
public/favicon-96x96.png
Normal file
BIN
public/favicon-96x96.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
3
public/favicon.svg
Normal file
3
public/favicon.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 30 KiB |
BIN
public/fonts/jgs7.ttf
Normal file
BIN
public/fonts/jgs7.ttf
Normal file
Binary file not shown.
BIN
public/fonts/jgs7.woff
Normal file
BIN
public/fonts/jgs7.woff
Normal file
Binary file not shown.
BIN
public/fonts/jgs7.woff2
Normal file
BIN
public/fonts/jgs7.woff2
Normal file
Binary file not shown.
BIN
public/jgs7.ttf
Normal file
BIN
public/jgs7.ttf
Normal file
Binary file not shown.
21
public/site.webmanifest
Normal file
21
public/site.webmanifest
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "MyWebSite",
|
||||||
|
"short_name": "MySite",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/web-app-manifest-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/web-app-manifest-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"theme_color": "#ffffff",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"display": "standalone"
|
||||||
|
}
|
||||||
BIN
public/web-app-manifest-192x192.png
Normal file
BIN
public/web-app-manifest-192x192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
BIN
public/web-app-manifest-512x512.png
Normal file
BIN
public/web-app-manifest-512x512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 134 KiB |
|
|
@ -3,6 +3,7 @@ import "../../globals.css";
|
||||||
import type React from "react";
|
import type React from "react";
|
||||||
|
|
||||||
import { Lang, locales } from "@/i18n/locales";
|
import { Lang, locales } from "@/i18n/locales";
|
||||||
|
import Head from 'next/head';
|
||||||
|
|
||||||
import { Oxanium } from "next/font/google";
|
import { Oxanium } from "next/font/google";
|
||||||
const oxanium = Oxanium({ subsets: ["latin-ext"] })
|
const oxanium = Oxanium({ subsets: ["latin-ext"] })
|
||||||
|
|
@ -18,7 +19,15 @@ export default async function RootLayout({
|
||||||
const { locale } = await params
|
const { locale } = await params
|
||||||
const currentLang = locales.includes(locale) ? locale : "en"
|
const currentLang = locales.includes(locale) ? locale : "en"
|
||||||
return (
|
return (
|
||||||
<html lang={currentLang} className={oxanium.className}>
|
<html lang={currentLang} className={`${oxanium.className} dark`}>
|
||||||
|
<Head>
|
||||||
|
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
<link rel="shortcut icon" href="/favicon.ico" />
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||||
|
<meta name="apple-mobile-web-app-title" content="MyWebSite" />
|
||||||
|
<link rel="manifest" href="/site.webmanifest" />
|
||||||
|
</Head>
|
||||||
<body className="bg-background text:foreground antialiased">
|
<body className="bg-background text:foreground antialiased">
|
||||||
{children}
|
{children}
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -40,9 +40,9 @@ export default function Home() {
|
||||||
</video>
|
</video>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative z-10 container mx-auto px-4 h-full flex items-center justify-center">
|
<div className="relative z-10 container mx-auto px-4 h-full flex items-center justify-center">
|
||||||
<div className="text-center">
|
<div className="text-center font-[JGS7]">
|
||||||
<h1 className="text-6xl md:text-8xl font-bold tracking-tighter mb-6 light:text-background">{t.hero.title}</h1>
|
<h1 className="text-5xl sm:text-6xl md:text-8xl font-bold tracking-tighter mb-6 light:text-background">{t.hero.title}</h1>
|
||||||
<p className="text-xl md:text-2xl text-primary">{t.hero.subtitle}</p>
|
<p className="text-3xl sm:text-4xl md:text-5xl lg:text-6xl xl-text:7xl 2xl:text-8xl text-primary">{t.hero.subtitle}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -69,7 +69,7 @@ export default function Home() {
|
||||||
<div className="container mx-auto px-4">
|
<div className="container mx-auto px-4">
|
||||||
<h2 className="text-4xl font-bold mb-8 tracking-tighter">{t.when.title}</h2>
|
<h2 className="text-4xl font-bold mb-8 tracking-tighter">{t.when.title}</h2>
|
||||||
<div className="text-lg text-muted-foreground">
|
<div className="text-lg text-muted-foreground">
|
||||||
<p className="text-primary text-3xl">{t.when.date}</p>
|
<p className="text-primary text-3xl font-[JGS7]">{t.when.date}</p>
|
||||||
<p className="mt-4">{t.when.extra}</p>
|
<p className="mt-4">{t.when.extra}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -112,6 +112,17 @@ export default function Home() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section id="credits" className="py-24 bg-background">
|
||||||
|
<div className="container mx-auto px-4">
|
||||||
|
<h2 className="text-4xl font-bold mb-8 tracking-tighter">{t.credits.title}</h2>
|
||||||
|
<div className="text-lg text-muted-foreground">
|
||||||
|
<p>{t.credits.usedFonts}</p>
|
||||||
|
<p><a className="hover:underline" href="https://velvetyne.fr/fonts/jgs-font/">{t.credits.jgs7}</a> {` ${t.credits.jgs7RemovedGlyphs}`}</p>
|
||||||
|
<p><a className="hover:underline" href="https://fonts.google.com/specimen/Oxanium">{t.credits.oxanium}</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,18 @@
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet"
|
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet"
|
||||||
import type { translations } from "@/i18n/translations"
|
import type { Sections, translations } from "@/i18n/translations"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
import { Menu } from "lucide-react"
|
import { Menu } from "lucide-react"
|
||||||
|
|
||||||
export function MobileNav({
|
export function MobileNav({
|
||||||
t,
|
t,
|
||||||
linksOrder,
|
linksOrder,
|
||||||
|
activeSection
|
||||||
}: {
|
}: {
|
||||||
t: typeof translations.pl
|
t: typeof translations.pl
|
||||||
linksOrder: Array<keyof (typeof translations.pl)["nav"]>
|
linksOrder: Array<Sections>
|
||||||
|
activeSection: Sections
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Sheet>
|
<Sheet>
|
||||||
|
|
@ -26,7 +29,9 @@ export function MobileNav({
|
||||||
</SheetHeader>
|
</SheetHeader>
|
||||||
<nav className="flex flex-col gap-4 mt-8">
|
<nav className="flex flex-col gap-4 mt-8">
|
||||||
{linksOrder.map((value) => (
|
{linksOrder.map((value) => (
|
||||||
<a key={value} href={`#${value}`} className="text-lg hover:text-primary transition-colors">
|
<a key={value} href={`#${value}`} className={cn("text-lg hover:text-primary transition-colors", {
|
||||||
|
'text-primary': activeSection === value
|
||||||
|
})}>
|
||||||
{t.nav[value]}
|
{t.nav[value]}
|
||||||
</a>
|
</a>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
"use client"
|
"use client"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import type { translations } from "@/i18n/translations"
|
import { Sections, type translations } from "@/i18n/translations"
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
import { MoonIcon, SunIcon } from "lucide-react"
|
import { MoonIcon, SunIcon } from "lucide-react"
|
||||||
import { useEffect, useState } from "react"
|
import { useCallback, useEffect, useState } from "react"
|
||||||
import { MobileNav } from "./mobile-nav"
|
import { MobileNav } from "./mobile-nav"
|
||||||
|
|
||||||
const linksOrder: Array<keyof (typeof translations.pl)["nav"]> = [
|
const linksOrder: Array<keyof (typeof translations.pl)["nav"]> = [
|
||||||
|
|
@ -16,29 +16,43 @@ const linksOrder: Array<keyof (typeof translations.pl)["nav"]> = [
|
||||||
"contact",
|
"contact",
|
||||||
]
|
]
|
||||||
|
|
||||||
export function Nav({
|
function useTheme(): [theme: "light" | "dark", setTheme: (theme: "light" | "dark") => void] {
|
||||||
t,
|
/* eslint-disable react-hooks/rules-of-hooks */
|
||||||
}: {
|
if (typeof window === "undefined") return ["dark", () => { }]
|
||||||
t: typeof translations.pl
|
|
||||||
}) {
|
|
||||||
const [theme, setTheme] = useState<"light" | "dark">("dark")
|
const [theme, setTheme] = useState<"light" | "dark">("dark")
|
||||||
const [activeSection, setActiveSection] = useState<keyof (typeof translations.pl)["nav"]>("about")
|
|
||||||
|
const root = window.document.documentElement
|
||||||
|
|
||||||
|
const changeTheme = useCallback((theme: "light" | "dark") => {
|
||||||
|
root.classList.remove("light", "dark")
|
||||||
|
root.classList.add(theme)
|
||||||
|
}, [root])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Determine the user's preferred color scheme
|
// Determine the user's preferred color scheme
|
||||||
const preferredTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
|
const preferredTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
|
||||||
setTheme(preferredTheme)
|
setTheme(preferredTheme)
|
||||||
|
|
||||||
const root = window.document.documentElement
|
changeTheme(preferredTheme)
|
||||||
root.classList.remove("light", "dark")
|
}, [changeTheme])
|
||||||
root.classList.add(preferredTheme)
|
|
||||||
}, [])
|
const updateTheme = useCallback((theme: "light" | "dark") => {
|
||||||
|
setTheme(theme)
|
||||||
|
changeTheme(theme)
|
||||||
|
}, [changeTheme, setTheme])
|
||||||
|
|
||||||
|
return [theme, updateTheme]
|
||||||
|
/* eslint-enable react-hooks/rules-of-hooks */
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Nav({
|
||||||
|
t,
|
||||||
|
}: {
|
||||||
|
t: typeof translations.pl
|
||||||
|
}) {
|
||||||
|
const [theme, setTheme] = useTheme()
|
||||||
|
const [activeSection, setActiveSection] = useState<Sections>("about")
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const root = window.document.documentElement
|
|
||||||
root.classList.remove("light", "dark")
|
|
||||||
root.classList.add(theme)
|
|
||||||
}, [theme])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const options = {
|
const options = {
|
||||||
|
|
@ -80,7 +94,7 @@ export function Nav({
|
||||||
<div className="container mx-auto px-4">
|
<div className="container mx-auto px-4">
|
||||||
<div className="flex items-center justify-between h-16">
|
<div className="flex items-center justify-between h-16">
|
||||||
<a href="#" className="text-xl font-bold tracking-tighter hover:text-primary transition-colors">
|
<a href="#" className="text-xl font-bold tracking-tighter hover:text-primary transition-colors">
|
||||||
CEBULACAMP
|
{t.siteTitle}
|
||||||
</a>
|
</a>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
{/* Desktop Navigation */}
|
{/* Desktop Navigation */}
|
||||||
|
|
@ -89,12 +103,14 @@ export function Nav({
|
||||||
<a
|
<a
|
||||||
key={value}
|
key={value}
|
||||||
href={`#${value}`}
|
href={`#${value}`}
|
||||||
className={cn("text-sm hover:text-primary transition-colors relative group", {
|
className={cn("text-sm md:text-md hover:text-primary transition-colors relative group", {
|
||||||
'text-primary': activeSection === value
|
'text-primary': activeSection === value
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{t.nav[value]}
|
{t.nav[value]}
|
||||||
<span className="absolute inset-x-0 -bottom-1 h-0.5 bg-primary transform scale-x-0 group-hover:scale-x-100 transition-transform" />
|
<span className={cn("absolute inset-x-0 -bottom-1 h-0.5 bg-primary transform scale-x-0 group-hover:scale-x-100 transition-transform", {
|
||||||
|
'scale-x-100': activeSection === value
|
||||||
|
})} />
|
||||||
</a>
|
</a>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -111,7 +127,7 @@ export function Nav({
|
||||||
|
|
||||||
{/* Mobile Navigation */}
|
{/* Mobile Navigation */}
|
||||||
<div className="md:hidden ml-2">
|
<div className="md:hidden ml-2">
|
||||||
<MobileNav t={t} linksOrder={linksOrder} />
|
<MobileNav t={t} linksOrder={linksOrder} activeSection={activeSection} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,15 @@
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "JGS7";
|
||||||
|
src: url("/fonts/jgs7.woff2") format("woff2"),
|
||||||
|
url("/fonts/jgs7.woff") format("woff"),
|
||||||
|
url("/fonts/jgs7.ttf") format("truetype");
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
|
|
@ -72,9 +81,7 @@ html {
|
||||||
--input: hsl(0 0% 14.9%);
|
--input: hsl(0 0% 14.9%);
|
||||||
--ring: hsl(0 0% 83.1%);
|
--ring: hsl(0 0% 83.1%);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@layer base {
|
|
||||||
* {
|
* {
|
||||||
@apply border-border;
|
@apply border-border;
|
||||||
}
|
}
|
||||||
|
|
@ -89,3 +96,7 @@ html {
|
||||||
.parallax-video {
|
.parallax-video {
|
||||||
transition: transform 0.25s ease-out;
|
transition: transform 0.25s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.jgs7 {
|
||||||
|
font-family: "JGS7" !important;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
export const translations = {
|
const common = {
|
||||||
pl: {
|
jgs7: "JGS7",
|
||||||
|
oxanium: "Oxanium",
|
||||||
|
};
|
||||||
|
|
||||||
|
const pl = {
|
||||||
|
siteTitle: "CEBULACAMP",
|
||||||
nav: {
|
nav: {
|
||||||
about: "O nas",
|
about: "O nas",
|
||||||
when: "Kiedy",
|
when: "Kiedy",
|
||||||
|
|
@ -12,7 +17,6 @@ export const translations = {
|
||||||
mobileNav: {
|
mobileNav: {
|
||||||
toggleMenu: "Aktywnuj menu",
|
toggleMenu: "Aktywnuj menu",
|
||||||
menu: "Menu",
|
menu: "Menu",
|
||||||
|
|
||||||
},
|
},
|
||||||
hero: {
|
hero: {
|
||||||
title: "CEBULACAMP 2025",
|
title: "CEBULACAMP 2025",
|
||||||
|
|
@ -25,8 +29,7 @@ export const translations = {
|
||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
title: "Gdzie",
|
title: "Gdzie",
|
||||||
location:
|
location: "klub Łącznik, Tramwajowa 1-3, Wrocław, obok Hackerspace Wrocław",
|
||||||
"klub Łącznik, Tramwajowa 1-3, Wrocław, obok Hackerspace Wrocław",
|
|
||||||
},
|
},
|
||||||
when: {
|
when: {
|
||||||
title: "Kiedy",
|
title: "Kiedy",
|
||||||
|
|
@ -52,8 +55,24 @@ export const translations = {
|
||||||
title: "Kontakt",
|
title: "Kontakt",
|
||||||
email: "contact@cebula.camp",
|
email: "contact@cebula.camp",
|
||||||
},
|
},
|
||||||
},
|
credits: {
|
||||||
en: {
|
title: "Uznania",
|
||||||
// English translations would go here
|
usedFonts: "Użyte fonty:",
|
||||||
|
oxanium: common.oxanium,
|
||||||
|
jgs7: common.jgs7,
|
||||||
|
jgs7RemovedGlyphs: "z usuniętymi znakami",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const en = {};
|
||||||
|
|
||||||
|
export const translations: {
|
||||||
|
en: typeof pl;
|
||||||
|
pl: typeof pl;
|
||||||
|
} = {
|
||||||
|
pl: pl,
|
||||||
|
// @ts-expect-error This should fail so far, remove me when translations are properly added to "en" object.
|
||||||
|
en: en,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Sections = keyof (typeof pl)["nav"];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue