Compare commits
No commits in common. "main" and "fix-schedule-link" have entirely different histories.
main
...
fix-schedu
78
src/app/[locale]/agenda/page.tsx
Normal file
78
src/app/[locale]/agenda/page.tsx
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -7,7 +7,6 @@ import dynamic from 'next/dynamic';
|
|||
import { jgs7, oxanium } from '@/fonts';
|
||||
import { Lang } from '@/i18n/locales';
|
||||
import { Translations } from "@/i18n/translations";
|
||||
import { getWikiUrl, getCfpScheduleUrl, getEmailUrl } from '@/lib/external-links';
|
||||
import { cn } from "@/lib/utils";
|
||||
import Link from 'next/link';
|
||||
import { ReactElement, useEffect, useRef } from "react";
|
||||
|
|
@ -175,7 +174,7 @@ export default function LandingPage(
|
|||
|
||||
return (
|
||||
<div>
|
||||
<MainpageNav t={t} currentLocale={currentLocale} />
|
||||
<MainpageNav t={t} />
|
||||
<main className="flex flex-col min-h-screen grid-gap-10 gap-10 pb-12">
|
||||
|
||||
<section id="hero" className="h-screen relative overflow-hidden dark:bg-black light:bg-white ">
|
||||
|
|
@ -189,44 +188,24 @@ 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.details.when.date}</p>
|
||||
<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`}>
|
||||
<Link href={getCfpScheduleUrl(currentLocale)} 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="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
{t.contribute.agenda.title}
|
||||
</Link>
|
||||
</Button>
|
||||
<Button className={`${oxanium.className} text-xl uppercase cursor-pointer`}>
|
||||
<Link href={getWikiUrl(currentLocale)} 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>
|
||||
<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">
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
{t.contribute.agenda.title}
|
||||
</Link>
|
||||
</Button>
|
||||
<NewsletterPopup t={t} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -292,13 +271,31 @@ export default function LandingPage(
|
|||
</p>
|
||||
</div>
|
||||
<Button className={`${oxanium.className} text-xl uppercase cursor-pointer`} size="lg">
|
||||
<Link href={getCfpScheduleUrl(currentLocale)}>
|
||||
<Link href={`https://cfp.cebula.camp/camp-2025/locale/set?locale=${currentLocale}&next=/camp-2025/schedule/`}>
|
||||
{t.contribute.agenda.viewButton}
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</TextWrapper>
|
||||
</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>
|
||||
|
||||
|
|
@ -313,7 +310,7 @@ export default function LandingPage(
|
|||
</section>
|
||||
<section>
|
||||
<Subheading>{t.faq.accesibility.title}</Subheading>
|
||||
<TextWrapper><p>{t.faq.accesibility.description} <a href={getEmailUrl()}>{t.contact.email}</a></p></TextWrapper>
|
||||
<TextWrapper><p>{t.faq.accesibility.description} <a href="mailto:orga@cebula.camp">{t.contact.email}</a></p></TextWrapper>
|
||||
</section>
|
||||
<section>
|
||||
<Subheading>{t.faq.food.title}</Subheading>
|
||||
|
|
@ -329,8 +326,6 @@ export default function LandingPage(
|
|||
<a className='hover:text-primary' href={`/${currentLocale}/pages/rules`}>📜 {t.faq.documents.rules}</a></p></TextWrapper>
|
||||
<TextWrapper><p>
|
||||
<a className='hover:text-primary' href={`/${currentLocale}/pages/privacy`}>📜 {t.faq.documents.privacyPolicy}</a></p></TextWrapper>
|
||||
<TextWrapper><p>
|
||||
<a className='hover:text-primary' href={getWikiUrl(currentLocale)} target="_blank" rel="noopener noreferrer">📚 {t.faq.documents.wiki}</a></p></TextWrapper>
|
||||
</section>
|
||||
</>
|
||||
</NewSection>
|
||||
|
|
@ -343,7 +338,7 @@ export default function LandingPage(
|
|||
<section>
|
||||
<TextWrapper><p>{t.contact.details.line1}</p></TextWrapper>
|
||||
<br />
|
||||
<TextWrapper><p>📬 <a href={getEmailUrl()}>{t.contact.email}</a> {t.contact.details.line2}</p></TextWrapper>
|
||||
<TextWrapper><p>📬 <a href={`mailto:${t.contact.email}`}>{t.contact.email}</a> {t.contact.details.line2}</p></TextWrapper>
|
||||
<br />
|
||||
<TextWrapper><p>{t.contact.details.line3}</p></TextWrapper>
|
||||
<br />
|
||||
|
|
|
|||
|
|
@ -9,32 +9,20 @@ import { LanguageSelector } from "./ui/language-selector"
|
|||
|
||||
function NavContent({
|
||||
t,
|
||||
linksOrder,
|
||||
externalLinks
|
||||
linksOrder
|
||||
}: {
|
||||
t: typeof translations.pl,
|
||||
linksOrder: Array<Sections>,
|
||||
externalLinks: Record<string, string>
|
||||
linksOrder: Array<Sections>
|
||||
}) {
|
||||
return (
|
||||
<nav className="flex flex-col gap-4 mt-8">
|
||||
<ScrollSpy activeClass="nav-active" offsetTop={80}>
|
||||
|
||||
{linksOrder.map((value) => {
|
||||
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]}
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
{linksOrder.map((value) => (
|
||||
<a key={value} href={`#${value}`} className="text-lg hover:text-primary transition-colors">
|
||||
{t.nav[value]}
|
||||
</a>
|
||||
))}
|
||||
</ScrollSpy>
|
||||
<LanguageSelector />
|
||||
</nav>
|
||||
|
|
@ -44,11 +32,9 @@ function NavContent({
|
|||
export function MobileNav({
|
||||
t,
|
||||
linksOrder,
|
||||
externalLinks,
|
||||
}: {
|
||||
t: typeof translations.pl
|
||||
linksOrder: Array<Sections>
|
||||
externalLinks: Record<string, string>
|
||||
}) {
|
||||
return (
|
||||
<Sheet >
|
||||
|
|
@ -62,7 +48,7 @@ export function MobileNav({
|
|||
<SheetHeader>
|
||||
<SheetTitle>{t.mobileNav.menu}</SheetTitle>
|
||||
</SheetHeader>
|
||||
<NavContent t={t} linksOrder={linksOrder} externalLinks={externalLinks} />
|
||||
<NavContent t={t} linksOrder={linksOrder} />
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
"use client"
|
||||
import { type translations } from "@/i18n/translations"
|
||||
import { Lang } from '@/i18n/locales'
|
||||
import { getWikiUrl } from '@/lib/external-links'
|
||||
import { cn } from "@/lib/utils"
|
||||
import ScrollSpy from 'react-scrollspy-navigation'
|
||||
import { MobileNav } from "./mobile-nav"
|
||||
|
|
@ -13,20 +11,14 @@ const linksOrder: Array<keyof (typeof translations.pl)["nav"]> = [
|
|||
'tickets',
|
||||
'contribute',
|
||||
'details',
|
||||
'wiki',
|
||||
'contact'
|
||||
]
|
||||
|
||||
export function MainpageNav({
|
||||
t,
|
||||
currentLocale = 'pl' as Lang
|
||||
}: {
|
||||
t: typeof translations.pl
|
||||
currentLocale?: Lang
|
||||
}) {
|
||||
const externalLinks: Record<string, string> = {
|
||||
'wiki': getWikiUrl(currentLocale)
|
||||
}
|
||||
|
||||
return (
|
||||
<NavContainer title={t.nav.title}>
|
||||
|
|
@ -34,27 +26,21 @@ export function MainpageNav({
|
|||
<div className="hidden md:flex md:items-center md:gap-4 lg:gap-8">
|
||||
<ScrollSpy activeClass="nav-active" offsetTop={80}>
|
||||
|
||||
{linksOrder.map((value) => {
|
||||
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-sm md:text-md hover:text-primary transition-colors relative group will-change-[color]"
|
||||
>
|
||||
{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", {
|
||||
})} />
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
{linksOrder.map((value) => (
|
||||
<a
|
||||
key={value}
|
||||
href={`#${value}`}
|
||||
className="text-sm md:text-md hover:text-primary transition-colors relative group will-change-[color]"
|
||||
>
|
||||
{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", {
|
||||
})} />
|
||||
</a>
|
||||
))}
|
||||
</ScrollSpy>
|
||||
</div>
|
||||
<div className="md:hidden ml-2">
|
||||
<MobileNav t={t} linksOrder={linksOrder} externalLinks={externalLinks} />
|
||||
<MobileNav t={t} linksOrder={linksOrder} />
|
||||
</div>
|
||||
</>
|
||||
</NavContainer>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ const pl = {
|
|||
contribute: "Agenda",
|
||||
details: "FAQ",
|
||||
contact: "Kontakt",
|
||||
wiki: "Wiki",
|
||||
},
|
||||
mobileNav: {
|
||||
toggleMenu: "Aktywuj menu",
|
||||
|
|
@ -48,6 +47,20 @@ const pl = {
|
|||
},
|
||||
contribute: {
|
||||
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: {
|
||||
title: "Agenda",
|
||||
description: "Zobacz pełny harmonogram wydarzeń, prelekcji i warsztatów",
|
||||
|
|
@ -77,7 +90,6 @@ const pl = {
|
|||
title: "Dokumenty",
|
||||
rules: "Regulamin wydarzenia",
|
||||
privacyPolicy: "Polityka prywatności",
|
||||
wiki: "Wiki CebulaCamp",
|
||||
},
|
||||
},
|
||||
contact: {
|
||||
|
|
@ -121,7 +133,6 @@ const en = {
|
|||
contribute: "Schedule",
|
||||
details: "FAQ",
|
||||
contact: "Contact",
|
||||
wiki: "Wiki",
|
||||
},
|
||||
mobileNav: {
|
||||
toggleMenu: "Toggle menu",
|
||||
|
|
@ -155,6 +166,20 @@ const en = {
|
|||
},
|
||||
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: {
|
||||
title: "Schedule",
|
||||
description: "View the full schedule of events, talks, and workshops",
|
||||
|
|
@ -184,7 +209,6 @@ const en = {
|
|||
title: "Documents",
|
||||
rules: "Terms and Conditions",
|
||||
privacyPolicy: "Privacy Policy",
|
||||
wiki: "CebulaCamp Wiki",
|
||||
},
|
||||
},
|
||||
contact: {
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
import { Lang } from "@/i18n/locales";
|
||||
|
||||
export const EXTERNAL_URLS = {
|
||||
email: "orga@cebula.camp",
|
||||
} as const;
|
||||
|
||||
export function getWikiUrl(locale: Lang): string {
|
||||
return `https://wiki.cebula.camp/${locale}/home`;
|
||||
}
|
||||
|
||||
export function getCfpScheduleUrl(locale: Lang): string {
|
||||
return `https://cfp.cebula.camp/camp-2025/locale/set?locale=${locale}&next=/camp-2025/schedule/`;
|
||||
}
|
||||
|
||||
export function getCfpUrl(): string {
|
||||
return `https://cfp.cebula.camp/camp-2025/cfp`;
|
||||
}
|
||||
|
||||
export function getCfpArtUrl(): string {
|
||||
return `https://cfp.cebula.camp/camp-2025-art/cfp`;
|
||||
}
|
||||
|
||||
export function getEmailUrl(): string {
|
||||
return `mailto:${EXTERNAL_URLS.email}`;
|
||||
}
|
||||
|
||||
export function getExternalLinks(locale: Lang) {
|
||||
return {
|
||||
wiki: getWikiUrl(locale),
|
||||
cfpSchedule: getCfpScheduleUrl(locale),
|
||||
cfp: getCfpUrl(),
|
||||
cfpArt: getCfpArtUrl(),
|
||||
email: getEmailUrl(),
|
||||
};
|
||||
}
|
||||
Loading…
Reference in a new issue