diff --git a/README.md b/README.md index ae8e554..bee518c 100644 --- a/README.md +++ b/README.md @@ -96,4 +96,3 @@ Deployment is manual and triggered from GitHub Actions: 3. Click **Run workflow** The site is deployed to GitHub Pages at `https://2026.es.pycon.org/`. - diff --git a/src/components/JobsPage.astro b/src/components/JobsPage.astro new file mode 100644 index 0000000..d4ccced --- /dev/null +++ b/src/components/JobsPage.astro @@ -0,0 +1,187 @@ +--- +import { jobsTexts } from '../i18n/jobs' +import { menuTexts } from '../i18n/menu' + +interface Props { + lang: string +} + +interface JobFrontmatter { + title: string + company: string + location: string + type: string + description: string + skills?: string[] + salary?: string + apply_url: string + tier?: string + draft?: boolean +} + +const { lang } = Astro.props +const t = jobsTexts[(lang || 'es') as keyof typeof jobsTexts] +const menuT = menuTexts[(lang || 'es') as keyof typeof menuTexts] + +const esJobs = Object.values(import.meta.glob('../data/jobs/es/*.md', { eager: true })) as { + frontmatter: JobFrontmatter +}[] +const enJobs = Object.values(import.meta.glob('../data/jobs/en/*.md', { eager: true })) as { + frontmatter: JobFrontmatter +}[] +const caJobs = Object.values(import.meta.glob('../data/jobs/ca/*.md', { eager: true })) as { + frontmatter: JobFrontmatter +}[] + +const allJobsMap: Record = { + es: esJobs, + en: enJobs, + ca: caJobs, +} + +const allJobs = allJobsMap[lang] || [] + +const jobs = allJobs + .filter((job) => job.frontmatter.draft !== true) + .sort((a, b) => { + const tierOrder = { platinum: 0, gold: 1, silver: 2, bronze: 3 } + const aTier = tierOrder[a.frontmatter.tier as keyof typeof tierOrder] ?? 4 + const bTier = tierOrder[b.frontmatter.tier as keyof typeof tierOrder] ?? 4 + if (aTier !== bTier) return aTier - bTier + return 0 + }) + +const isFeatured = (tier?: string) => tier === 'gold' || tier === 'platinum' +--- + +
+
+

+ {t.hero} +

+

{t.subtitle}

+
+ + { + jobs.length === 0 ? ( +

{t.no_jobs}

+ ) : ( + + ) + } +
+ + diff --git a/src/data/jobs/_plantilla-oferta.md b/src/data/jobs/_plantilla-oferta.md new file mode 100644 index 0000000..2e1b5f6 --- /dev/null +++ b/src/data/jobs/_plantilla-oferta.md @@ -0,0 +1,12 @@ +--- +title: 'Nombre del puesto' +company: 'Nombre de la empresa' +location: 'Remoto / Madrid / Barcelona' +type: 'Full-time' +description: 'Descripción breve del puesto. Explica qué harás, el equipo, el proyecto, etc.' +skills: [Python, Django, PostgreSQL] +salary: '35k-50k' +apply_url: 'https://ejemplo.com/careers' +tier: 'gold' +draft: true +--- diff --git a/src/data/jobs/ca/jetbrains-python-dev.md b/src/data/jobs/ca/jetbrains-python-dev.md new file mode 100644 index 0000000..f85d7f7 --- /dev/null +++ b/src/data/jobs/ca/jetbrains-python-dev.md @@ -0,0 +1,12 @@ +--- +title: 'Senior Python Developer' +company: 'JetBrains' +location: 'Remot' +type: 'Full-time' +description: "Uneix-te al nostre equip per treballar en eines de desenvolupament d'última generació. Formaràs part d'un equip que crea productes utilitzats per milions de desenvolupadors a tot el món." +skills: [Python, Django, PostgreSQL, AWS] +salary: '60k-80k' +apply_url: 'https://www.jetbrains.com/careers/' +tier: 'gold' +draft: true +--- diff --git a/src/data/jobs/en/fever-senior-dev.md b/src/data/jobs/en/fever-senior-dev.md new file mode 100644 index 0000000..6fda4af --- /dev/null +++ b/src/data/jobs/en/fever-senior-dev.md @@ -0,0 +1,12 @@ +--- +title: 'Senior Backend Engineer' +company: 'Fever' +location: 'Madrid - Hybrid' +type: 'Full-time' +description: "We're looking for a Senior Backend Engineer to join our backend team, with outstanding software development talent." +skills: [Python, Django, PostgreSQL, Redis, AWS, Docker, Kubernetes] +salary: '50k-70k + 10% + stock options' +apply_url: 'https://careers.feverup.com/' +tier: 'gold' +draft: true +--- diff --git a/src/data/jobs/en/jetbrains-python-dev.md b/src/data/jobs/en/jetbrains-python-dev.md new file mode 100644 index 0000000..b27081d --- /dev/null +++ b/src/data/jobs/en/jetbrains-python-dev.md @@ -0,0 +1,12 @@ +--- +title: 'Senior Python Developer' +company: 'JetBrains' +location: 'Remote' +type: 'Full-time' +description: "Join our team to work on cutting-edge developer tools. You'll be part of a team that creates products used by millions of developers worldwide." +skills: [Python, Django, PostgreSQL, AWS] +salary: '60k-80k' +apply_url: 'https://www.jetbrains.com/careers/' +tier: 'gold' +draft: true +--- diff --git a/src/data/jobs/es/fever-senior-dev.md b/src/data/jobs/es/fever-senior-dev.md new file mode 100644 index 0000000..2dff39d --- /dev/null +++ b/src/data/jobs/es/fever-senior-dev.md @@ -0,0 +1,12 @@ +--- +title: 'Senior Backend Engineer' +company: 'Fever' +location: 'Madrid - Hybrid' +type: 'Full-time' +description: "We're looking for a Senior Backend Engineer to join our backend team, with outstanding software development talent demonstrated by great work results and experience." +skills: [Python, Django, PostgreSQL, Redis, AWS, Docker, Kubernetes] +salary: '50k-70k + 10% + stock options' +apply_url: 'https://careers.feverup.com/' +tier: 'gold' +draft: true +--- diff --git a/src/data/jobs/es/jetbrains-python-dev.md b/src/data/jobs/es/jetbrains-python-dev.md new file mode 100644 index 0000000..ca100c4 --- /dev/null +++ b/src/data/jobs/es/jetbrains-python-dev.md @@ -0,0 +1,12 @@ +--- +title: 'Senior Python Developer' +company: 'JetBrains' +location: 'Remoto' +type: 'Full-time' +description: "Join our team to work on cutting-edge developer tools. You'll be part of a team that creates products used by millions of developers worldwide." +skills: [Python, Django, PostgreSQL, AWS] +salary: '60k-80k' +apply_url: 'https://www.jetbrains.com/careers/' +tier: 'gold' +draft: true +--- diff --git a/src/i18n/jobs/ca.ts b/src/i18n/jobs/ca.ts new file mode 100644 index 0000000..4415466 --- /dev/null +++ b/src/i18n/jobs/ca.ts @@ -0,0 +1,11 @@ +export const ca = { + title: 'Ofertes de treball | PyConES 2026', + hero: 'Ofertes de treball', + subtitle: 'Les següents ofertes han estat enviades pels patrocinadors de la conferència:', + apply: 'Veure detalls', + featured: 'Destacat', + salary: 'Sou', + location: 'Ubicació', + no_jobs: 'No hi ha ofertes de treball publicades en aquest idioma.', + skills: 'Tecnologies', +} as const diff --git a/src/i18n/jobs/en.ts b/src/i18n/jobs/en.ts new file mode 100644 index 0000000..575d4c3 --- /dev/null +++ b/src/i18n/jobs/en.ts @@ -0,0 +1,11 @@ +export const en = { + title: 'Job offers | PyConES 2026', + hero: 'Job offers', + subtitle: 'The following offers have been submitted by conference sponsors:', + apply: 'View details', + featured: 'Featured', + salary: 'Salary', + location: 'Location', + no_jobs: 'No job offers published in this language.', + skills: 'Technologies', +} as const diff --git a/src/i18n/jobs/es.ts b/src/i18n/jobs/es.ts new file mode 100644 index 0000000..071e256 --- /dev/null +++ b/src/i18n/jobs/es.ts @@ -0,0 +1,11 @@ +export const es = { + title: 'Ofertas de trabajo | PyConES 2026', + hero: 'Ofertas de trabajo', + subtitle: 'Las siguientes ofertas han sido enviadas por los patrocinadores de la conferencia:', + apply: 'Ver detalles', + featured: 'Destacado', + salary: 'Salario', + location: 'Ubicación', + no_jobs: 'No hay ofertas de trabajo publicadas en este idioma.', + skills: 'Tecnologías', +} as const diff --git a/src/i18n/jobs/index.ts b/src/i18n/jobs/index.ts new file mode 100644 index 0000000..5f4de95 --- /dev/null +++ b/src/i18n/jobs/index.ts @@ -0,0 +1,9 @@ +import { es } from './es' +import { en } from './en' +import { ca } from './ca' + +export const jobsTexts = { + es, + en, + ca, +} as const diff --git a/src/i18n/menu/ca.ts b/src/i18n/menu/ca.ts index 1820209..62eb720 100644 --- a/src/i18n/menu/ca.ts +++ b/src/i18n/menu/ca.ts @@ -55,6 +55,10 @@ export const ca = { }, ], }, + { + label: 'Ofertes de treball', + href: '/jobs', + }, { label: 'Edicions Anteriors', children: [ diff --git a/src/i18n/menu/en.ts b/src/i18n/menu/en.ts index b03e2f8..40c9c92 100644 --- a/src/i18n/menu/en.ts +++ b/src/i18n/menu/en.ts @@ -55,6 +55,10 @@ export const en = { }, ], }, + { + label: 'Job offers', + href: '/jobs', + }, { label: 'Past Editions', children: [ diff --git a/src/i18n/menu/es.ts b/src/i18n/menu/es.ts index f1669d7..869fcbd 100644 --- a/src/i18n/menu/es.ts +++ b/src/i18n/menu/es.ts @@ -55,6 +55,10 @@ export const es = { }, ], }, + { + label: 'Ofertas de trabajo', + href: '/jobs', + }, { label: 'Ediciones Anteriores', children: [ diff --git a/src/pages/[lang]/jobs.astro b/src/pages/[lang]/jobs.astro new file mode 100644 index 0000000..1f33872 --- /dev/null +++ b/src/pages/[lang]/jobs.astro @@ -0,0 +1,34 @@ +--- +import Layout from '../../layouts/Layout.astro' +import JobsPage from '../../components/JobsPage.astro' +import { jobsTexts } from '../../i18n/jobs' + +export function getStaticPaths() { + return [{ params: { lang: 'es' } }, { params: { lang: 'en' } }, { params: { lang: 'ca' } }] +} + +const { lang } = Astro.params + +const titles = { + es: 'Ofertas de trabajo | PyConES 2026', + en: 'Job offers | PyConES 2026', + ca: 'Ofertes de treball | PyConES 2026', +} + +const descriptions = { + es: 'Explora las ofertas de trabajo de los patrocinadores de PyConES 2026. Encuentra oportunidades como Python Developer, DevOps Engineer y más.', + en: 'Explore job offers from PyConES 2026 sponsors. Find opportunities like Python Developer, DevOps Engineer and more.', + ca: 'Explora les ofertes de treball dels patrocinadors de PyConES 2026. Troba oportunitats com Python Developer, DevOps Engineer i més.', +} + +const title = titles[(lang || 'es') as keyof typeof titles] +const description = descriptions[(lang || 'es') as keyof typeof descriptions] +--- + + +
+
+ +
+
+
diff --git a/tsconfig.json b/tsconfig.json index 2e66b49..f520ae4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "extends": "astro/tsconfigs/base", - "include": ["src/**/*"], + "include": ["src/**/*"], "compilerOptions": { "baseUrl": ".", "paths": {