feat: simplify navigation and add wiki link
All checks were successful
/ deploy (push) Successful in 3s

- Remove standalone agenda page (deleted agenda/page.tsx)
- Remove CFP/art submission sections from contribute area
- Add direct wiki link to navigation and FAQ documents
- Add wiki button alongside schedule button in hero section
- Update navigation to include wiki as external link
- Clean up translations by removing unused CFP/art text
This commit is contained in:
Dariusz Niemczyk 2025-08-27 14:09:04 +02:00
parent 10bfa5e561
commit 8a629c3de8
No known key found for this signature in database
5 changed files with 89 additions and 162 deletions

View file

@ -1,78 +0,0 @@
import Script from 'next/script';
import { getLocale, Lang, locales } from '@/i18n/locales';
import { translations } from '@/i18n/translations';
import { Metadata } from 'next';
import Link from 'next/link';
import { LanguageSelector } from '@/components/ui/language-selector';
export async function generateStaticParams() {
return locales.map((locale) => ({ locale }));
}
export async function generateMetadata({ params }: { params: Promise<{ locale: Lang }> }): Promise<Metadata> {
const { locale } = await params;
const currentLocale = getLocale(locale);
const t = translations[currentLocale];
return {
title: `${t.contribute.agenda.title} - ${t.hero.title}`,
description: t.about.description,
};
}
export default async function AgendaPage({ params }: { params: Promise<{ locale: Lang }> }) {
const { locale } = await params;
const currentLocale = getLocale(locale);
const t = translations[currentLocale];
return (
<>
<Script
src={`https://cfp.cebula.camp/camp-2025/schedule/widget/v2.${currentLocale}.js`}
strategy="afterInteractive"
/>
{/* Full page wrapper with forced light theme */}
<div className="fixed inset-0 bg-white">
{/* Custom light-themed navigation without theme context */}
<nav className="fixed top-0 left-0 right-0 bg-white border-b border-gray-200 z-[10000]">
<div className="container mx-auto px-4">
<div className="flex items-center justify-between h-16">
<div className="flex gap-4">
<Link href="/" className="text-xl font-bold tracking-tighter text-black hover:text-green-600 transition-colors">
<h1>{t.nav.title}</h1>
</Link>
</div>
<div className="flex items-center">
<LanguageSelector />
</div>
</div>
</div>
</nav>
<div className="h-full bg-white text-black pt-16 overflow-auto">
{/* Full-sized widget - no padding, full viewport */}
<div
style={{
'--pretalx-clr-primary': '#16a34a',
'--pretalx-clr-primary-text': '#ffffff',
'--pretalx-clr-secondary': '#f1f5f9',
'--pretalx-clr-text': '#000000',
'--pretalx-clr-background': '#ffffff',
'--pretalx-clr-border': '#e2e8f0',
'--pretalx-clr-hover': '#f8fafc',
} as React.CSSProperties}
>
{/* @ts-expect-error - pretalx-schedule is a custom web component */}
<pretalx-schedule
event-url="https://cfp.cebula.camp/camp-2025/"
locale={currentLocale}
style={{
display: 'block',
width: '100%',
minHeight: 'calc(100vh - 64px)' // Full height minus navbar
}}
/>
</div>
</div>
</div>
</>
);
}

View file

@ -188,6 +188,7 @@ export default function LandingPage(
<p className="mt-2 text-3xl sm:text-4xl md:text-5xl lg:text-6xl xl-text:7xl 2xl:text-8xl text-primary">{t.hero.subtitle}</p> <p className="mt-2 text-3xl sm:text-4xl md:text-5xl lg:text-6xl xl-text:7xl 2xl:text-8xl text-primary">{t.hero.subtitle}</p>
<p className="mt-2 text-3xl sm:text-4xl md:text-5xl lg:text-6xl xl-text:7xl 2xl:text-8xl text-primary ">{t.details.when.date}</p> <p className="mt-2 text-3xl sm:text-4xl md:text-5xl lg:text-6xl xl-text:7xl 2xl:text-8xl text-primary ">{t.details.when.date}</p>
<div className='flex flex-col space-y-4 items-center justify-center m-auto'> <div className='flex flex-col space-y-4 items-center justify-center m-auto'>
<div className='flex flex-row gap-4'>
<Button className={`${oxanium.className} text-xl uppercase cursor-pointer`}> <Button className={`${oxanium.className} text-xl uppercase cursor-pointer`}>
<Link href={`https://cfp.cebula.camp/camp-2025/locale/set?locale=${currentLocale}&next=/camp-2025/schedule/`} className="flex items-center gap-2"> <Link href={`https://cfp.cebula.camp/camp-2025/locale/set?locale=${currentLocale}&next=/camp-2025/schedule/`} className="flex items-center gap-2">
<svg <svg
@ -206,6 +207,25 @@ export default function LandingPage(
{t.contribute.agenda.title} {t.contribute.agenda.title}
</Link> </Link>
</Button> </Button>
<Button className={`${oxanium.className} text-xl uppercase cursor-pointer`}>
<Link href="https://wiki.cebula.camp/pl/home" target="_blank" rel="noopener noreferrer" className="flex items-center gap-2">
<svg
className="w-5 h-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"
/>
</svg>
{t.nav.wiki}
</Link>
</Button>
</div>
<NewsletterPopup t={t} /> <NewsletterPopup t={t} />
</div> </div>
</div> </div>
@ -278,24 +298,6 @@ export default function LandingPage(
</div> </div>
</TextWrapper> </TextWrapper>
</section> </section>
<section>
<Subheading>{t.contribute.talks.title}</Subheading>
<TextWrapper><p>{t.contribute.talks.description}</p></TextWrapper>
<TextWrapper>
<Button className={`${oxanium.className} text-xl mt-4 uppercase cursor-pointer`}>
<Link href={t.contribute.talks.link}>{t.contribute.talks.buttonText}</Link>
</Button>
</TextWrapper>
</section>
<section>
<Subheading>{t.contribute.art.title}</Subheading>
<TextWrapper><p>{t.contribute.art.description}</p></TextWrapper>
<TextWrapper>
<Button className={`${oxanium.className} text-xl mt-4 uppercase cursor-pointer`}>
<Link href={t.contribute.art.link}>{t.contribute.art.buttonText}</Link>
</Button>
</TextWrapper>
</section>
</> </>
</NewSection> </NewSection>
@ -326,6 +328,8 @@ export default function LandingPage(
<a className='hover:text-primary' href={`/${currentLocale}/pages/rules`}>📜 {t.faq.documents.rules}</a></p></TextWrapper> <a className='hover:text-primary' href={`/${currentLocale}/pages/rules`}>📜 {t.faq.documents.rules}</a></p></TextWrapper>
<TextWrapper><p> <TextWrapper><p>
<a className='hover:text-primary' href={`/${currentLocale}/pages/privacy`}>📜 {t.faq.documents.privacyPolicy}</a></p></TextWrapper> <a className='hover:text-primary' href={`/${currentLocale}/pages/privacy`}>📜 {t.faq.documents.privacyPolicy}</a></p></TextWrapper>
<TextWrapper><p>
<a className='hover:text-primary' href="https://wiki.cebula.camp/pl/home" target="_blank" rel="noopener noreferrer">📚 {t.faq.documents.wiki}</a></p></TextWrapper>
</section> </section>
</> </>
</NewSection> </NewSection>

View file

@ -9,20 +9,32 @@ import { LanguageSelector } from "./ui/language-selector"
function NavContent({ function NavContent({
t, t,
linksOrder linksOrder,
externalLinks
}: { }: {
t: typeof translations.pl, t: typeof translations.pl,
linksOrder: Array<Sections> linksOrder: Array<Sections>,
externalLinks: Record<string, string>
}) { }) {
return ( return (
<nav className="flex flex-col gap-4 mt-8"> <nav className="flex flex-col gap-4 mt-8">
<ScrollSpy activeClass="nav-active" offsetTop={80}> <ScrollSpy activeClass="nav-active" offsetTop={80}>
{linksOrder.map((value) => ( {linksOrder.map((value) => {
<a key={value} href={`#${value}`} className="text-lg hover:text-primary transition-colors"> const isExternal = value in externalLinks;
const href = isExternal ? externalLinks[value] : `#${value}`;
return (
<a
key={value}
href={href}
{...(isExternal ? { target: '_blank', rel: 'noopener noreferrer' } : {})}
className="text-lg hover:text-primary transition-colors"
>
{t.nav[value]} {t.nav[value]}
</a> </a>
))} );
})}
</ScrollSpy> </ScrollSpy>
<LanguageSelector /> <LanguageSelector />
</nav> </nav>
@ -32,9 +44,11 @@ function NavContent({
export function MobileNav({ export function MobileNav({
t, t,
linksOrder, linksOrder,
externalLinks,
}: { }: {
t: typeof translations.pl t: typeof translations.pl
linksOrder: Array<Sections> linksOrder: Array<Sections>
externalLinks: Record<string, string>
}) { }) {
return ( return (
<Sheet > <Sheet >
@ -48,7 +62,7 @@ export function MobileNav({
<SheetHeader> <SheetHeader>
<SheetTitle>{t.mobileNav.menu}</SheetTitle> <SheetTitle>{t.mobileNav.menu}</SheetTitle>
</SheetHeader> </SheetHeader>
<NavContent t={t} linksOrder={linksOrder} /> <NavContent t={t} linksOrder={linksOrder} externalLinks={externalLinks} />
</SheetContent> </SheetContent>
</Sheet> </Sheet>
) )

View file

@ -11,9 +11,14 @@ const linksOrder: Array<keyof (typeof translations.pl)["nav"]> = [
'tickets', 'tickets',
'contribute', 'contribute',
'details', 'details',
'wiki',
'contact' 'contact'
] ]
const externalLinks: Record<string, string> = {
'wiki': 'https://wiki.cebula.camp/pl/home'
}
export function MainpageNav({ export function MainpageNav({
t, t,
}: { }: {
@ -26,21 +31,27 @@ export function MainpageNav({
<div className="hidden md:flex md:items-center md:gap-4 lg:gap-8"> <div className="hidden md:flex md:items-center md:gap-4 lg:gap-8">
<ScrollSpy activeClass="nav-active" offsetTop={80}> <ScrollSpy activeClass="nav-active" offsetTop={80}>
{linksOrder.map((value) => ( {linksOrder.map((value) => {
const isExternal = value in externalLinks;
const href = isExternal ? externalLinks[value] : `#${value}`;
return (
<a <a
key={value} key={value}
href={`#${value}`} href={href}
{...(isExternal ? { target: '_blank', rel: 'noopener noreferrer' } : {})}
className="text-sm md:text-md hover:text-primary transition-colors relative group will-change-[color]" className="text-sm md:text-md hover:text-primary transition-colors relative group will-change-[color]"
> >
{t.nav[value]} {t.nav[value]}
<span data-sub={value} className={cn("absolute inset-x-0 -bottom-1 h-0.5 bg-primary transform scale-x-0 group-hover:scale-x-100 transition-transform will-change-transform", { <span data-sub={value} className={cn("absolute inset-x-0 -bottom-1 h-0.5 bg-primary transform scale-x-0 group-hover:scale-x-100 transition-transform will-change-transform", {
})} /> })} />
</a> </a>
))} );
})}
</ScrollSpy> </ScrollSpy>
</div> </div>
<div className="md:hidden ml-2"> <div className="md:hidden ml-2">
<MobileNav t={t} linksOrder={linksOrder} /> <MobileNav t={t} linksOrder={linksOrder} externalLinks={externalLinks} />
</div> </div>
</> </>
</NavContainer> </NavContainer>

View file

@ -13,6 +13,7 @@ const pl = {
contribute: "Agenda", contribute: "Agenda",
details: "FAQ", details: "FAQ",
contact: "Kontakt", contact: "Kontakt",
wiki: "Wiki",
}, },
mobileNav: { mobileNav: {
toggleMenu: "Aktywuj menu", toggleMenu: "Aktywuj menu",
@ -47,20 +48,6 @@ const pl = {
}, },
contribute: { contribute: {
title: "Zgłoś się!", title: "Zgłoś się!",
talks: {
title: "Prelekcje, dyskusje panelowe, warsztaty",
description:
"Nasi uczestnicy są zainteresowani szerokim spektrum tematów, ale spodziewamy się że większość wykładów podpadać będzie pod następujące kategorie:\n1. Haking: technologia zarówno pod względem jej budowy, jak i jej rozkładu na czynniki.\n2. Sztuka i społeczeństwo: zrozumienie i przeprocesowania świata dookoła nas.\n3. Niszowe pasje: rzeczy które cię naprawdę interesują i którymi chcesz się podzielić z resztą świata.\nJeśli powyższe to myśli które w przeszłości przewijały ci się przez głowę, wyślij nam zgłoszenie! Nawet jeśli masz obawy co do tematu - śmiało, pomożemy Ci zdecydować albo go doszlifować.\nW szczególności zachęcamy początkujących prelegentów - będzie nas niewiele i spodziewamy się wyjątkowo luźnej i przyjaznej atmosfery.",
link: "https://cfp.cebula.camp/camp-2025/cfp",
buttonText: "Zgłoś prelekcję",
},
art: {
title: "Sztuka",
description:
"W tym roku na Cebula Camp próbujemy czegoś nowego - otwieramy publiczny nabór zgłoszeń na sztukę i inne instalacje/eksponaty, które zmienią nasze wydarzenie w coś więcej niż zwykłą konferencję.\nKultura hakerska od zawsze leży na przecięciu sztuki i technologii. To przecięcie jest naszym tematem przewodnim, i jesteśmy otwarci na wszystko co pod niego pasuje - od ściany LED która wyświetla reklamy karmy dla zwierząt z tiktoka po galerię świecących w ciemności obrazów linii energetycznych w anime.\nZarejestrowanie się tutaj pozwoli nam zaaranżować przestrzeń tak, żeby była w niej miejsce na Ciebie i Twoją sztukę. Daj znać, jeśli potrzebujesz dodatkowej pomocy logistycznej, np. z transportem lub instalacją.",
link: "https://cfp.cebula.camp/camp-2025-art/cfp",
buttonText: "Zgłoś eksponat",
},
agenda: { agenda: {
title: "Agenda", title: "Agenda",
description: "Zobacz pełny harmonogram wydarzeń, prelekcji i warsztatów", description: "Zobacz pełny harmonogram wydarzeń, prelekcji i warsztatów",
@ -90,6 +77,7 @@ const pl = {
title: "Dokumenty", title: "Dokumenty",
rules: "Regulamin wydarzenia", rules: "Regulamin wydarzenia",
privacyPolicy: "Polityka prywatności", privacyPolicy: "Polityka prywatności",
wiki: "Wiki CebulaCamp",
}, },
}, },
contact: { contact: {
@ -133,6 +121,7 @@ const en = {
contribute: "Schedule", contribute: "Schedule",
details: "FAQ", details: "FAQ",
contact: "Contact", contact: "Contact",
wiki: "Wiki",
}, },
mobileNav: { mobileNav: {
toggleMenu: "Toggle menu", toggleMenu: "Toggle menu",
@ -166,20 +155,6 @@ const en = {
}, },
contribute: { contribute: {
title: "Contribute!", title: "Contribute!",
talks: {
title: "Talks, panels and workshops",
description:
"Our audience is interested in a wide variety of subjects, but we expect most talks to fall into the following categories:\n1. Hacking: how to build up and break down technology.\n2. Art and society: understanding and processing the world around us all.\n3. Niche obsessions: stuff that really interests you and you just wanna tell the world about it.\nIf you've had some thoughts on the above which you'd like to present to our audience, submit a proposal! Even if you're not sure if it's the right fit - we'll help you decide or iron it out.\nIf you're a first time speaker, this is a great opportunity to try it out. We expect a very cozy and friendly atmosphere.",
link: "https://cfp.cebula.camp/camp-2025/cfp",
buttonText: "Submit a talk",
},
art: {
title: "Art",
description:
"For Cebula Camp 2025 we're trying something new: crowdsourcing art and any other on-site installations that will make our event more than just a boring conference.\nAs hackers, we're at the intersection of art and technology. We invite anything that makes us reflect on this intersection, be it a LED video wall showing tiktok ads for pet food or a gallery of glow-in-the-dark gouache paintings of powerlines in anime.\nRegistering here will allow us to make sure we'll have space for you and your work. Please let us know if you need any assistance in transport or bringup, and how else we can accommodate you.",
link: "https://cfp.cebula.camp/camp-2025-art/cfp",
buttonText: "Submit an exhibit",
},
agenda: { agenda: {
title: "Schedule", title: "Schedule",
description: "View the full schedule of events, talks, and workshops", description: "View the full schedule of events, talks, and workshops",
@ -209,6 +184,7 @@ const en = {
title: "Documents", title: "Documents",
rules: "Terms and Conditions", rules: "Terms and Conditions",
privacyPolicy: "Privacy Policy", privacyPolicy: "Privacy Policy",
wiki: "CebulaCamp Wiki",
}, },
}, },
contact: { contact: {