Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions src/components/LanguagePicker.astro
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ const getPathForLang = (targetLang: string) => {

return '/' + parts.join('/')
}

---

{
Expand All @@ -48,10 +47,10 @@ const getPathForLang = (targetLang: string) => {
lang={lang}
aria-current={lang === currentLang ? 'page' : undefined}
class:list={[
'px-2 py-1 text-sm font-mono rounded transition-colors outline-none',
'px-2 py-1 text-sm font-outfit rounded transition-colors outline-none',
lang === currentLang
? 'text-blue-400 font-bold'
: 'text-slate-400 hover:text-white focus-visible:text-blue-400',
? 'text-pycon-red-100 font-bold underline'
: 'text-pycon-orange-500 hover:text-white focus-visible:text-pycon-red-500',
]}
>
{t.label[lang as keyof typeof t.label]}
Expand All @@ -70,7 +69,7 @@ const getPathForLang = (targetLang: string) => {
aria-current={lang === currentLang ? 'page' : undefined}
aria-label={`${t['labelariadesc']} ${t.label[lang as keyof typeof t.label]}`}
class:list={[
'px-3 py-2 text-sm font-mono rounded transition-colors outline-none',
'px-3 py-2 text-sm font-outfit rounded transition-colors outline-none',
lang === currentLang
? 'bg-blue-600 text-white font-bold'
: 'bg-white/5 text-slate-300 hover:bg-white/10 focus-visible:bg-blue-600 focus-visible:text-white',
Expand Down
8 changes: 7 additions & 1 deletion src/components/Nav.astro
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@ import Navigation from './Navigation.astro'
* - Escape: Close dropdown/mobile menu and return focus to trigger
* - Tab: Standard tab navigation with proper focus management
*/

interface Props {
lang?: string
}

const { lang } = Astro.props
---

<header>
<Navigation />
<Navigation lang={lang} />
</header>
59 changes: 34 additions & 25 deletions src/components/Navigation.astro
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,32 @@ interface MenuItem {
href: string
children?: MenuItem[]
}

// Get current language from URL
const lang = Astro.url.pathname.split('/')[1] || 'es'

interface Props {
lang?: string
}

const { lang: propLang } = Astro.props

// Get current language from URL if prop not provided
const urlLang = Astro.url.pathname.split('/')[1] || 'es'
const rawLang = propLang || urlLang
const validLangs = ['es', 'en', 'ca'] as const
type Lang = (typeof validLangs)[number]
const currentLang: Lang = validLangs.includes(lang as Lang) ? (lang as Lang) : 'es'
const currentLang: Lang = validLangs.includes(rawLang as Lang) ? (rawLang as Lang) : 'es'

// Helper to check if a URL is external
const isExternal = (href: string) => href.startsWith('http://') || href.startsWith('https://')

// Helper to get localized URL with hash support
const getLocalizedUrl = (lang: string, href: string) => {
if (isExternal(href)) return href

const [path, hash] = href.split('#')
const localizedPath = getRelativeLocaleUrl(lang, path)
return hash ? `${localizedPath}#${hash}` : localizedPath
}

/**
* Navigation Component
*
Expand All @@ -45,9 +61,9 @@ const { items } = menuTexts[currentLang]
<!-- Logo -->
<a
href={getRelativeLocaleUrl(currentLang, '/')}
class="text-2xl font-bold font-mono tracking-tighter text-white rounded px-2 py-1 outline-none transition-all focus-visible:bg-white/10 focus-visible:text-blue-400"
class="text-2xl font-bold font-outfit tracking-tighter text-white rounded px-2 py-1 outline-none transition-all focus-visible:bg-white/10 focus-visible:text-pycon-orange"
>
PyCon<span class="text-blue-500">ES</span>
PyCon<span class="text-pycon-orange">ES</span>
</a>

<div class="wrapper flex items-center gap-4">
Expand All @@ -61,7 +77,7 @@ const { items } = menuTexts[currentLang]
<>
<button
id={`dropdown-btn-${index}`}
class="dropdown-trigger flex items-center gap-1 text-slate-300 hover:text-white font-medium transition-colors rounded outline-none focus-visible:text-blue-400 focus-visible:underline decoration-2 underline-offset-4"
class="dropdown-trigger flex items-center gap-1 text-white hover:text-pycon-orange font-medium transition-colors rounded outline-none focus-visible:text-pycon-orange focus-visible:underline decoration-2 underline-offset-4"
aria-expanded="false"
aria-haspopup="true"
aria-controls={`dropdown-menu-${index}`}
Expand Down Expand Up @@ -90,12 +106,8 @@ const { items } = menuTexts[currentLang]
{item.children.map((child) => (
<li role="none">
<a
href={
isExternal(child.href)
? child.href
: getRelativeLocaleUrl(currentLang, child.href)
}
class="submenu-item block px-4 py-3 rounded-md text-white font-medium transition-colors outline-none hover:bg-white/5 focus-visible:bg-blue-600 focus-visible:text-white"
href={getLocalizedUrl(currentLang, child.href)}
class="submenu-item block px-4 py-3 rounded-md text-white font-medium transition-colors outline-none hover:text-pycon-orange hover:bg-white/5 focus-visible:bg-pycon-orange focus-visible:text-white"
role="menuitem"
{...(isExternal(child.href)
? { target: '_blank', rel: 'noopener noreferrer' }
Expand All @@ -109,8 +121,8 @@ const { items } = menuTexts[currentLang]
</>
) : (
<a
href={isExternal(item.href) ? item.href : getRelativeLocaleUrl(currentLang, item.href)}
class="block text-slate-300 hover:text-white font-medium transition-colors rounded outline-none focus-visible:text-blue-400 focus-visible:underline decoration-2 underline-offset-4"
href={getLocalizedUrl(currentLang, item.href)}
class="block text-white hover:text-pycon-orange font-medium transition-colors rounded outline-none focus-visible:text-pycon-orange focus-visible:underline decoration-2 underline-offset-4"
{...(isExternal(item.href) ? { target: '_blank', rel: 'noopener noreferrer' } : {})}
>
{item.label}
Expand Down Expand Up @@ -142,7 +154,7 @@ const { items } = menuTexts[currentLang]
<li class="menu-item">
{item.children ? (
<details class="mobile-details">
<summary class="flex items-center justify-between gap-1 w-full text-slate-300 hover:text-white font-medium py-2 transition-colors rounded outline-none focus-visible:text-blue-400 focus-visible:underline decoration-2 underline-offset-4 cursor-pointer list-none">
<summary class="flex items-center justify-between gap-1 w-full text-white hover:text-pycon-orange font-medium py-2 transition-colors rounded outline-none focus-visible:text-pycon-orange focus-visible:underline decoration-2 underline-offset-4 cursor-pointer list-none">
{item.label}
<svg
class="w-4 h-4 transition-transform duration-200 chevron-icon"
Expand All @@ -163,12 +175,8 @@ const { items } = menuTexts[currentLang]
{item.children.map((child) => (
<li>
<a
href={
isExternal(child.href)
? child.href
: getRelativeLocaleUrl(currentLang, child.href)
}
class="block px-4 py-3 rounded-md text-white font-medium transition-colors outline-none hover:bg-white/5 focus-visible:bg-blue-600 focus-visible:text-white"
href={getLocalizedUrl(currentLang, child.href)}
class="block px-4 py-3 rounded-md text-white font-medium transition-colors outline-none hover:text-pycon-orange hover:bg-white/5 focus-visible:bg-pycon-orange focus-visible:text-white"
{...(isExternal(child.href)
? { target: '_blank', rel: 'noopener noreferrer' }
: {})}
Expand All @@ -181,8 +189,8 @@ const { items } = menuTexts[currentLang]
</details>
) : (
<a
href={isExternal(item.href) ? item.href : getRelativeLocaleUrl(currentLang, item.href)}
class="block text-slate-300 hover:text-white font-medium py-2 transition-colors rounded outline-none focus-visible:text-blue-400 focus-visible:underline decoration-2 underline-offset-4"
href={getLocalizedUrl(currentLang, item.href)}
class="block text-white hover:text-pycon-orange font-medium py-2 transition-colors rounded outline-none focus-visible:text-pycon-orange focus-visible:underline decoration-2 underline-offset-4"
{...(isExternal(item.href) ? { target: '_blank', rel: 'noopener noreferrer' } : {})}
>
{item.label}
Expand Down Expand Up @@ -523,7 +531,7 @@ const { items } = menuTexts[currentLang]

/* Active menu item styling */
.is-active {
color: white;
color: var(--color-pycon-red);
font-weight: 600;
}

Expand All @@ -533,5 +541,6 @@ const { items } = menuTexts[currentLang]
text-decoration: underline;
text-decoration-thickness: 2px;
text-underline-offset: 4px;
color: var(--color-pycon-orange);
}
</style>
1 change: 0 additions & 1 deletion src/components/index.astro
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
import Layout from '../layouts/Layout.astro'
import '@fontsource-variable/jetbrains-mono'
import SectionMain from './home/SectionMain.astro'

interface Props {
Expand Down
19 changes: 18 additions & 1 deletion src/i18n/menu/ca.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,24 @@ export const ca = {
},
{
label: 'Patrocinis',
href: '/sponsors',
children: [
{
label: 'Sobre la PyConES',
href: '/sponsors#about',
},
{
label: 'En números',
href: '/sponsors#stats',
},
{
label: 'Lloc',
href: '/sponsors#location',
},
{
label: 'Opinions',
href: '/sponsors#testimonials',
},
],
},
{
label: 'Edicions Anteriors',
Expand Down
19 changes: 18 additions & 1 deletion src/i18n/menu/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,24 @@ export const en = {
},
{
label: 'Sponsorship',
href: '/sponsors',
children: [
{
label: 'About',
href: '/sponsors#about',
},
{
label: 'Stats',
href: '/sponsors#stats',
},
{
label: 'Location',
href: '/sponsors#location',
},
{
label: 'Testimonials',
href: '/sponsors#testimonials',
},
],
},
{
label: 'Past Editions',
Expand Down
19 changes: 18 additions & 1 deletion src/i18n/menu/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,24 @@ export const es = {
},
{
label: 'Patrocinios',
href: '/sponsors',
children: [
{
label: 'Sobre la PyConES',
href: '/sponsors#about',
},
{
label: 'En números',
href: '/sponsors#stats',
},
{
label: 'Lugar',
href: '/sponsors#location',
},
{
label: 'Testimonios',
href: '/sponsors#testimonials',
},
],
},
{
label: 'Ediciones Anteriores',
Expand Down
6 changes: 2 additions & 4 deletions src/layouts/Layout.astro
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
import LanguagePicker from '../components/LanguagePicker.astro'
import Nav from '../components/Nav.astro'
import '../style/global.css'
import '@fontsource-variable/jetbrains-mono'
import '@fontsource-variable/outfit'
Expand Down Expand Up @@ -35,9 +35,7 @@ const { title, description = 'PyconES 2026' } = Astro.props
class="fixed inset-0 bg-[url('/images/symbol-black-dark.svg')] bg-size-[80vh] bg-position-[140%_120%] bg-no-repeat opacity-30 pointer-events-none blur-xs"
>
</div>
<nav class="relative z-10">
<LanguagePicker lang={lang} />
</nav>
<Nav lang={lang as string} />

<main class="relative z-10 flex flex-col justify-center text-white">
<slot />
Expand Down
Loading