feat: simplify navigation and add wiki link
All checks were successful
/ deploy (push) Successful in 3s
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:
parent
10bfa5e561
commit
8a629c3de8
|
|
@ -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>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -188,24 +188,44 @@ 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'>
|
||||||
<Button className={`${oxanium.className} text-xl uppercase cursor-pointer`}>
|
<div className='flex flex-row gap-4'>
|
||||||
<Link href={`https://cfp.cebula.camp/camp-2025/locale/set?locale=${currentLocale}&next=/camp-2025/schedule/`} className="flex items-center gap-2">
|
<Button className={`${oxanium.className} text-xl uppercase cursor-pointer`}>
|
||||||
<svg
|
<Link href={`https://cfp.cebula.camp/camp-2025/locale/set?locale=${currentLocale}&next=/camp-2025/schedule/`} className="flex items-center gap-2">
|
||||||
className="w-5 h-5"
|
<svg
|
||||||
fill="none"
|
className="w-5 h-5"
|
||||||
viewBox="0 0 24 24"
|
fill="none"
|
||||||
stroke="currentColor"
|
viewBox="0 0 24 24"
|
||||||
>
|
stroke="currentColor"
|
||||||
<path
|
>
|
||||||
strokeLinecap="round"
|
<path
|
||||||
strokeLinejoin="round"
|
strokeLinecap="round"
|
||||||
strokeWidth={2}
|
strokeLinejoin="round"
|
||||||
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"
|
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}
|
</svg>
|
||||||
</Link>
|
{t.contribute.agenda.title}
|
||||||
</Button>
|
</Link>
|
||||||
|
</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>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
{t.nav[value]}
|
const href = isExternal ? externalLinks[value] : `#${value}`;
|
||||||
</a>
|
|
||||||
))}
|
return (
|
||||||
|
<a
|
||||||
|
key={value}
|
||||||
|
href={href}
|
||||||
|
{...(isExternal ? { target: '_blank', rel: 'noopener noreferrer' } : {})}
|
||||||
|
className="text-lg hover:text-primary transition-colors"
|
||||||
|
>
|
||||||
|
{t.nav[value]}
|
||||||
|
</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>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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) => {
|
||||||
<a
|
const isExternal = value in externalLinks;
|
||||||
key={value}
|
const href = isExternal ? externalLinks[value] : `#${value}`;
|
||||||
href={`#${value}`}
|
|
||||||
className="text-sm md:text-md hover:text-primary transition-colors relative group will-change-[color]"
|
return (
|
||||||
>
|
<a
|
||||||
{t.nav[value]}
|
key={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", {
|
href={href}
|
||||||
})} />
|
{...(isExternal ? { target: '_blank', rel: 'noopener noreferrer' } : {})}
|
||||||
</a>
|
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>
|
</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>
|
||||||
|
|
|
||||||
|
|
@ -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: {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue