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
162 changes: 111 additions & 51 deletions src/components/AccommodationPage.astro
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@ interface Props {

const { lang } = Astro.props
const t = accommodationTexts[lang as keyof typeof accommodationTexts]
type AreaSlug =
| 'eixampleEsquerra'
| 'elRaval'
| 'santAntoni'
| 'ciutatVella'
| 'sants'
| 'poblenou22'
| 'elClot'
| 'lesCorts'
| 'eixampleDreta'
| 'collblanc'

const walkingAreas: AreaSlug[] = ['eixampleEsquerra', 'elRaval', 'santAntoni', 'ciutatVella']
const directMetroAreas: AreaSlug[] = ['sants', 'poblenou22', 'elClot']
const transferAreas: AreaSlug[] = ['lesCorts', 'eixampleDreta', 'collblanc']

const areaName = (slug: AreaSlug) => t[`accommodation.areas.${slug}.name` as keyof typeof t]
const areaDesc = (slug: AreaSlug) => t[`accommodation.areas.${slug}.desc` as keyof typeof t]
---

<div class="accommodation-container pb-20">
Expand All @@ -20,33 +38,91 @@ const t = accommodationTexts[lang as keyof typeof accommodationTexts]
</p>
</section>

<section
class="max-w-4xl bg-white/5 backdrop-blur-md p-8 md:p-12 rounded-3xl border border-white/10 mb-16 shadow-2xl"
>
<p class="text-lg text-pycon-gray-25 leading-relaxed">
{t['accommodation.intro']}
</p>
<!-- Areas -->
<section class="mb-24" aria-labelledby="accommodation-areas-heading">
<div class="flex items-center gap-4 mb-12">
<div class="h-px bg-white/20 flex-1" aria-hidden="true"></div>
<h2 id="accommodation-areas-heading" class="text-3xl font-bold text-white px-4">
{t['accommodation.areas.title']}
</h2>
<div class="h-px bg-white/20 flex-1" aria-hidden="true"></div>
</div>
<div class="max-w-4xl space-y-4 mb-12 text-pycon-gray-25 leading-relaxed">
<p class="text-lg">{t['accommodation.areas.transportIntro.p1']}</p>
<p class="text-lg">{t['accommodation.areas.transportIntro.p2']}</p>
<p class="text-lg">{t['accommodation.areas.transportIntro.p3']}</p>
</div>

<div class="space-y-16">
<div>
<h3 class="text-2xl font-bold text-white mb-6">{t['accommodation.areas.category.walking']}</h3>
<ul class="grid sm:grid-cols-2 lg:grid-cols-3 gap-8 list-none m-0 p-0">
{
walkingAreas.map((slug) => (
<li class="bg-pycon-black/40 p-8 rounded-2xl border border-white/5 hover:border-pycon-orange/50 transition-all motion-safe:hover:-translate-y-2">
<h4 class="text-xl font-bold text-pycon-orange mb-4 italic">{areaName(slug)}</h4>
<p class="text-pycon-gray-25 text-sm leading-relaxed">{areaDesc(slug)}</p>
</li>
))
}
</ul>
</div>
<div>
<h3 class="text-2xl font-bold text-white mb-6">{t['accommodation.areas.category.directMetro']}</h3>
<ul class="grid sm:grid-cols-2 lg:grid-cols-3 gap-8 list-none m-0 p-0">
{
directMetroAreas.map((slug) => (
<li class="bg-pycon-black/40 p-8 rounded-2xl border border-white/5 hover:border-pycon-orange/50 transition-all motion-safe:hover:-translate-y-2">
<h4 class="text-xl font-bold text-pycon-orange mb-4 italic">{areaName(slug)}</h4>
<p class="text-pycon-gray-25 text-sm leading-relaxed">{areaDesc(slug)}</p>
</li>
))
}
</ul>
</div>
<div>
<h3 class="text-2xl font-bold text-white mb-6">{t['accommodation.areas.category.transferMetro']}</h3>
<ul class="grid sm:grid-cols-2 lg:grid-cols-3 gap-8 list-none m-0 p-0">
{
transferAreas.map((slug) => (
<li class="bg-pycon-black/40 p-8 rounded-2xl border border-white/5 hover:border-pycon-orange/50 transition-all motion-safe:hover:-translate-y-2">
<h4 class="text-xl font-bold text-pycon-orange mb-4 italic">{areaName(slug)}</h4>
<p class="text-pycon-gray-25 text-sm leading-relaxed">{areaDesc(slug)}</p>
</li>
))
}
</ul>
</div>
</div>
</section>

<!-- Hotels Section -->
<section class="mb-24">
<section class="mb-24" aria-labelledby="accommodation-hotels-heading">
<div class="flex items-center gap-4 mb-12">
<div class="h-px bg-white/20 flex-1"></div>
<h2 class="text-3xl font-bold text-white px-4">{t['accommodation.hotels.title']}</h2>
<div class="h-px bg-white/20 flex-1"></div>
<div class="h-px bg-white/20 flex-1" aria-hidden="true"></div>
<h2 id="accommodation-hotels-heading" class="text-3xl font-bold text-white px-4">
{t['accommodation.hotels.title']}
</h2>
<div class="h-px bg-white/20 flex-1" aria-hidden="true"></div>
</div>

<div
class="bg-pycon-gray-100/50 p-12 rounded-3xl border border-pycon-yellow/30 text-center relative overflow-hidden group"
>
<!-- Shine effect -->
<div
class="absolute -top-full -left-full w-[300%] h-[300%] bg-linear-to-br from-transparent via-pycon-yellow/5 to-transparent rotate-45 transition-transform duration-1000 group-hover:translate-x-[33%] group-hover:translate-y-[33%] pointer-events-none"
class="absolute -top-full -left-full w-[300%] h-[300%] bg-linear-to-br from-transparent via-pycon-yellow/5 to-transparent rotate-45 transition-transform duration-1000 motion-safe:group-hover:translate-x-[33%] motion-safe:group-hover:translate-y-[33%] pointer-events-none"
aria-hidden="true"
>
</div>

<div class="relative z-10">
<StatusIcon type="construction" size="xl" role="img" aria-label="Construyendo" />
<StatusIcon
type="construction"
size="xl"
role="img"
aria-label={t['accommodation.a11y.constructionIcon']}
/>
<h3 class="text-2xl font-bold text-pycon-yellow mb-4">{t['accommodation.hotels.subtitle']}</h3>
<p class="text-xl text-white font-medium max-w-2xl mx-auto italic opacity-80">
{t['accommodation.hotels.disclaimer']}
Expand All @@ -55,59 +131,36 @@ const t = accommodationTexts[lang as keyof typeof accommodationTexts]
</div>
</section>

<!-- Areas -->
<section class="mb-24">
<h2 class="text-3xl font-bold text-white mb-12 flex items-center gap-3">
<span class="w-2 h-8 bg-pycon-red rounded-full"></span>
{t['accommodation.areas.title']}
</h2>
<div class="grid md:grid-cols-3 gap-8">
<div
class="bg-pycon-black/40 p-8 rounded-2xl border border-white/5 hover:border-pycon-orange/50 transition-all hover:-translate-y-2"
>
<h3 class="text-xl font-bold text-pycon-orange mb-4 italic">
{t['accommodation.areas.eixample.name']}
</h3>
<p class="text-pycon-gray-25 text-sm leading-relaxed">{t['accommodation.areas.eixample.desc']}</p>
</div>
<div
class="bg-pycon-black/40 p-8 rounded-2xl border border-white/5 hover:border-pycon-orange/50 transition-all hover:-translate-y-2 text-center"
>
<h3 class="text-xl font-bold text-pycon-orange mb-4 italic">
{t['accommodation.areas.gothic.name']}
</h3>
<p class="text-pycon-gray-25 text-sm leading-relaxed">{t['accommodation.areas.gothic.desc']}</p>
</div>
<div
class="bg-pycon-black/40 p-8 rounded-2xl border border-white/5 hover:border-pycon-orange/50 transition-all hover:-translate-y-2 text-right"
>
<h3 class="text-xl font-bold text-pycon-orange mb-4 italic">
{t['accommodation.areas.poblenou.name']}
</h3>
<p class="text-pycon-gray-25 text-sm leading-relaxed">{t['accommodation.areas.poblenou.desc']}</p>
</div>
</div>
</section>

<!-- Apartments -->
<section
class="bg-linear-to-r from-pycon-red/20 to-pycon-orange/20 p-8 md:p-16 rounded-3xl border border-pycon-red/30"
aria-labelledby="accommodation-apartments-heading"
>
<div class="flex flex-col md:flex-row gap-12 items-center">
<div class="flex-1">
<h2 class="text-3xl font-bold text-white mb-6 uppercase tracking-tight">
<h2
id="accommodation-apartments-heading"
class="text-3xl font-bold text-white mb-6 uppercase tracking-tight"
>
{t['accommodation.apartments.title']}
</h2>
<p class="text-pycon-gray-25 text-lg mb-8 leading-relaxed">
{t['accommodation.apartments.text']}
</p>
<a
href="https://meet.barcelona/es/alojarse-en-barcelona"
href={t['accommodation.apartments.linkUrl']}
target="_blank"
class="inline-flex items-center gap-2 bg-white text-pycon-red font-bold px-6 py-3 rounded-lg hover:scale-105 transition-transform no-underline"
rel="noopener noreferrer"
class="inline-flex items-center gap-2 bg-white text-pycon-red font-bold px-6 py-3 rounded-lg motion-safe:hover:scale-105 transition-transform no-underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-pycon-yellow"
>
{t['accommodation.apartments.link']}
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"
<span class="sr-only"> ({t['accommodation.a11y.linkOpensNewTab']})</span>
<svg
class="w-5 h-5 shrink-0"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
aria-hidden="true"
><path
stroke-linecap="round"
stroke-linejoin="round"
Expand All @@ -118,8 +171,9 @@ const t = accommodationTexts[lang as keyof typeof accommodationTexts]
</div>
<div
class="w-48 h-48 bg-white/10 rounded-full flex items-center justify-center border border-white/20 shadow-2xl backdrop-blur-xl shrink-0"
aria-hidden="true"
>
<StatusIcon type="city" size="xl" role="img" aria-label="Ubicación" />
<StatusIcon type="city" size="xl" />
</div>
</div>
</section>
Expand All @@ -140,4 +194,10 @@ const t = accommodationTexts[lang as keyof typeof accommodationTexts]
transform: translateY(0);
}
}

@media (prefers-reduced-motion: reduce) {
.accommodation-container {
animation: none;
}
}
</style>
53 changes: 42 additions & 11 deletions src/i18n/accommodation/ca.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,55 @@ export const ca = {
'accommodation.title': 'Allotjament',
'accommodation.hero.title': 'On allotjar-se',
'accommodation.hero.subtitle': 'Recomanacions per a la teva estada a Barcelona',
'accommodation.intro':
"Barcelona és una de les ciutats amb més oferta hotelera d'Europa. Per a la PyConES 2026, recomanem buscar allotjament al districte de l'Eixample o a Ciutat Vella per estar a pocs minuts a peu de la seu (UB Edifici Històric).",
'accommodation.hotels.title': 'Hotels Recomanats',
'accommodation.hotels.subtitle': 'Convenis i opcions properes',
'accommodation.hotels.disclaimer':
'Estem treballant per tancar convenis exclusius amb descomptes per als assistents. Torna aviat per veure els codis promocionals!',
'accommodation.areas.title': 'Millors Zones',
'accommodation.areas.eixample.name': "L'Eixample",
'accommodation.areas.eixample.desc':
'La zona més segura i elegant, amb arquitectura modernista i a un pas de la seu.',
'accommodation.areas.gothic.name': 'Barri Gòtic',
'accommodation.areas.gothic.desc':
'El centre històric, amb carrers màgics i molta vida nocturna, a 10 min de la UB.',
'accommodation.areas.poblenou.name': 'Poblenou / 22@',
'accommodation.areas.poblenou.desc':
'El hub tecnològic. Un poc més allunyat però molt ben connectat per metro (L1).',
'accommodation.areas.transportIntro.p1':
'Si has de tornar a casa en tren, les millors opcions són Sants, Eixample Esquerra o Les Corts (per anar a Sants Estació).',
'accommodation.areas.transportIntro.p2':
"Si tornes en avió, et recomanem els barris d'El Raval, Sant Antoni, Eixample Esquerra (Aerobús), Sants (tren Rodalies R2) o Les Corts i Collblanc (L9 Sud). Tanmateix hi ha una parada de l'autobús directe a l'aeroport (Aerobús) davant de la seu.",
'accommodation.areas.transportIntro.p3':
'Tindrem servei de consigna, així que si marxes el diumenge pots fer check-out i deixar les maletes aquí.',
'accommodation.areas.category.walking': 'A peu',
'accommodation.areas.category.directMetro': 'Metro directe',
'accommodation.areas.category.transferMetro': 'Metro amb transbord',
'accommodation.areas.eixampleEsquerra.name': 'Eixample Esquerra',
'accommodation.areas.eixampleEsquerra.desc':
"Costat esquerre de l'eixample, modernista i molt a prop de la UB a peu; bona opció si també fas servir Sants.",
'accommodation.areas.elRaval.name': 'El Raval',
'accommodation.areas.elRaval.desc':
'Barri cèntric i multicultural, a poca distància a peu de la seu; l’Aerobús enllaça bé amb l’aeroport.',
'accommodation.areas.santAntoni.name': 'Sant Antoni',
'accommodation.areas.santAntoni.desc':
'Mercat i terrasses, ambient de barri i una passejada còmoda fins a la universitat.',
'accommodation.areas.ciutatVella.name': 'Ciutat Vella',
'accommodation.areas.ciutatVella.desc':
'Nucli històric (Gòtic, Born…): ambient únic i ubicacions a prop de l’esdeveniment.',
'accommodation.areas.sants.name': 'Sants',
'accommodation.areas.sants.desc':
'Al costat de l’estació de Sants: ideal per trens de llarg recorregut i Rodalies cap a l’aeroport.',
'accommodation.areas.poblenou22.name': 'Poblenou / 22@',
'accommodation.areas.poblenou22.desc':
'Districte 22@ i platja; ben connectat per metro en línia directa al centre i la UB.',
'accommodation.areas.elClot.name': 'El Clot',
'accommodation.areas.elClot.desc':
'Barri consolidat amb bon accés en metro directe al centre on hi ha la seu.',
'accommodation.areas.lesCorts.name': 'Les Corts',
'accommodation.areas.lesCorts.desc':
'A prop de la L9 Sud a l’aeroport; per arribar a la seu sol cal transbord en metro.',
'accommodation.areas.eixampleDreta.name': 'Eixample Dreta',
'accommodation.areas.eixampleDreta.desc':
'Eixample dret: emblemàtic i ben comunicat, amb enllaços que sovint impliquen una correspondència.',
'accommodation.areas.collblanc.name': 'Collblanc',
'accommodation.areas.collblanc.desc':
'L9 Sud a l’aeroport; per arribar a la UB normalment faràs transbord.',
'accommodation.apartments.title': 'Apartaments Turístics',
'accommodation.apartments.text':
"Si prefereixes un apartament, assegura't que compti amb llicència turística oficial (HUTB). Barcelona és molt estricta amb la regulació d'allotjaments.",
'accommodation.apartments.link': "Veure guia d'allotjament segur a Barcelona",
'accommodation.apartments.linkUrl': 'https://meet.barcelona.cat/habitatgesturistics/ca',
'accommodation.a11y.constructionIcon': 'En construcció',
'accommodation.a11y.linkOpensNewTab': "s'obre en una pestanya nova",
} as const
53 changes: 42 additions & 11 deletions src/i18n/accommodation/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,55 @@ export const en = {
'accommodation.title': 'Accommodation',
'accommodation.hero.title': 'Where to stay',
'accommodation.hero.subtitle': 'Recommendations for your stay in Barcelona',
'accommodation.intro':
'Barcelona offers one of the largest hotel selections in Europe. For PyConES 2026, we recommend looking for accommodation in the Eixample district or Ciutat Vella to be within walking distance of the venue (UB Historic Building).',
'accommodation.hotels.title': 'Recommended Hotels',
'accommodation.hotels.subtitle': 'Agreements and nearby options',
'accommodation.hotels.disclaimer':
'We are working on exclusive discounts for attendees. Check back soon for promo codes!',
'accommodation.areas.title': 'Best Areas',
'accommodation.areas.eixample.name': "L'Eixample",
'accommodation.areas.eixample.desc':
'The safest and most elegant area, with modernist architecture and very close to the venue.',
'accommodation.areas.gothic.name': 'Gothic Quarter',
'accommodation.areas.gothic.desc':
'The historical center, with magical streets and vibrant nightlife, 10 min from UB.',
'accommodation.areas.poblenou.name': 'Poblenou / 22@',
'accommodation.areas.poblenou.desc':
'The tech hub. Slightly further away but very well connected by metro (L1).',
'accommodation.areas.transportIntro.p1':
'If you are heading home by train, the best options are Sants, Eixample Esquerra, or Les Corts (for reaching Sants Estació).',
'accommodation.areas.transportIntro.p2':
'If you fly out, we suggest El Raval, Sant Antoni, Eixample Esquerra (Aerobús), Sants (Rodalies R2 to the airport), or Les Corts and Collblanc (L9 Sud). There is also a direct airport bus (Aerobús) stop in front of the venue.',
'accommodation.areas.transportIntro.p3':
'We will provide a luggage room, so if you leave on Sunday you can check out and leave your bags with us.',
'accommodation.areas.category.walking': 'On foot',
'accommodation.areas.category.directMetro': 'Direct metro',
'accommodation.areas.category.transferMetro': 'Metro with a change',
'accommodation.areas.eixampleEsquerra.name': 'Eixample Esquerra',
'accommodation.areas.eixampleEsquerra.desc':
'The left side of the Eixample: modernist and very close to UB on foot; a strong pick if you also use Sants.',
'accommodation.areas.elRaval.name': 'El Raval',
'accommodation.areas.elRaval.desc':
'A central, multicultural area within walking distance of the venue; Aerobús links well to the airport.',
'accommodation.areas.santAntoni.name': 'Sant Antoni',
'accommodation.areas.santAntoni.desc':
'Market halls and terraces, a lively neighbourhood feel, and an easy walk to the university.',
'accommodation.areas.ciutatVella.name': 'Ciutat Vella',
'accommodation.areas.ciutatVella.desc':
'The old city (Gòtic, Born…): unique atmosphere and locations close to the event.',
'accommodation.areas.sants.name': 'Sants',
'accommodation.areas.sants.desc':
'Next to Sants station: ideal for long-distance trains and Rodalies to the airport.',
'accommodation.areas.poblenou22.name': 'Poblenou / 22@',
'accommodation.areas.poblenou22.desc':
'The 22@ district by the beach; direct metro lines to the centre and UB.',
'accommodation.areas.elClot.name': 'El Clot',
'accommodation.areas.elClot.desc':
'An established neighbourhood with a direct metro ride to the city centre where the venue is.',
'accommodation.areas.lesCorts.name': 'Les Corts',
'accommodation.areas.lesCorts.desc':
'Near L9 Sud to the airport; reaching the venue usually means one metro change.',
'accommodation.areas.eixampleDreta.name': 'Eixample Dreta',
'accommodation.areas.eixampleDreta.desc':
'The right side of the Eixample: iconic and well connected, often with one interchange.',
'accommodation.areas.collblanc.name': 'Collblanc',
'accommodation.areas.collblanc.desc':
'L9 Sud to the airport; you will typically change lines to get to UB.',
'accommodation.apartments.title': 'Tourist Apartments',
'accommodation.apartments.text':
'If you prefer an apartment, make sure it has an official tourist license (HUTB). Barcelona is very strict regarding accommodation regulations.',
'accommodation.apartments.link': 'View safe accommodation guide in Barcelona',
'accommodation.apartments.linkUrl': 'https://meet.barcelona.cat/habitatgesturistics/en',
'accommodation.a11y.constructionIcon': 'Under construction',
'accommodation.a11y.linkOpensNewTab': 'opens in a new tab',
} as const
Loading
Loading