diff --git a/public/speakers/ada-lovelace.webp b/public/speakers/ada-lovelace.webp new file mode 100644 index 0000000..17b55e1 Binary files /dev/null and b/public/speakers/ada-lovelace.webp differ diff --git a/src/components/home/SectionSpeakers.astro b/src/components/home/SectionSpeakers.astro new file mode 100644 index 0000000..61374be --- /dev/null +++ b/src/components/home/SectionSpeakers.astro @@ -0,0 +1,37 @@ +--- +import { texts } from '@/i18n/home' +import SectionTitle from '../SectionTitle.astro' +import CenteredPanel from '../CenteredPanel.astro' +import type { ISpeaker } from '../../types/speakers' +import SpeakerCard from './SpeakerCard.astro' + +const speakers = Object.values(import.meta.glob('../../data/speakers/*.md', { eager: true })) as { + frontmatter: ISpeaker +}[] + +interface Props { + lang: string +} + +const { lang } = Astro.props +const t = texts[lang as keyof typeof texts] + +const sortedSpeakers = speakers.map((s) => s.frontmatter).sort((a, b) => a.order - b.order) +--- + +{ + sortedSpeakers.length > 0 && ( +
+ + + +
    + {sortedSpeakers.map((speaker) => ( +
  • + +
  • + ))} +
+
+ ) +} diff --git a/src/components/home/SpeakerCard.astro b/src/components/home/SpeakerCard.astro new file mode 100644 index 0000000..5861bd6 --- /dev/null +++ b/src/components/home/SpeakerCard.astro @@ -0,0 +1,83 @@ +--- +import { Globe } from '@lucide/astro' +import type { ISpeaker, ISpeakerLink } from '../../types/speakers' +import { texts } from '../../i18n/home' +import { menuTexts } from '../../i18n/menu' +import SocialIcon from '../icons/SocialIcon.astro' + +interface Props { + speaker: ISpeaker + lang: string +} + +const { speaker, lang } = Astro.props +const t = texts[lang as keyof typeof texts] +const menuT = menuTexts[lang as keyof typeof menuTexts] + +const altPhoto = t['speakers.altphoto'].replace('{name}', speaker.name) + +function ariaForLink(link: ISpeakerLink, name: string): string { + const key = `speakers.aria_${link.type}` as + | 'speakers.aria_github' + | 'speakers.aria_linkedin' + | 'speakers.aria_instagram' + | 'speakers.aria_website' + const label = t[key] ?? link.type + return `${label.replace('{name}', name)} ${menuT.new_tab}` +} + +const linkClasses = + 'inline-flex items-center justify-center w-9 h-9 rounded-full bg-white/[0.03] border border-white/[0.06] hover:bg-white/[0.08] hover:border-white/[0.15] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-pycon-yellow transition-colors' +--- + +
+ {altPhoto} + +

{speaker.name}

+ + + +

+ {speaker.description} +

+
diff --git a/src/components/icons/Icon.astro b/src/components/icons/Icon.astro index 90a3d63..145db2c 100644 --- a/src/components/icons/Icon.astro +++ b/src/components/icons/Icon.astro @@ -45,15 +45,16 @@ if (!LucideIconComponent && !fallback) { ) : fallback ? ( @@ -63,8 +64,9 @@ if (!LucideIconComponent && !fallback) { ) diff --git a/src/components/index.astro b/src/components/index.astro index 6f88561..79d7b6c 100644 --- a/src/components/index.astro +++ b/src/components/index.astro @@ -1,6 +1,7 @@ --- import Layout from '@/layouts/Layout.astro' import SectionMain from './home/SectionMain.astro' +import SectionSpeakers from './home/SectionSpeakers.astro' import SectionEarlyBird from './home/SectionEarlyBird.astro' import SectionSponsors from './home/SectionSponsors.astro' @@ -14,6 +15,7 @@ const { lang } = Astro.props
+
diff --git a/src/data/speakers/ada-lovelace.md.template b/src/data/speakers/ada-lovelace.md.template new file mode 100644 index 0000000..7f5fe8c --- /dev/null +++ b/src/data/speakers/ada-lovelace.md.template @@ -0,0 +1,13 @@ +--- +name: 'Ada Lovelace' +order: 1 +photo: '/speakers/ada-lovelace.webp' +links: + - type: 'github' + url: 'https://github.com/ada-lovelace' + - type: 'linkedin' + url: 'https://linkedin.com/in/ada-lovelace' + - type: 'website' + url: 'https://ada-lovelace.dev' +description: Pionera de la computación y primera programadora de la historia. Trabajó con Charles Babbage en la Máquina Analítica y escribió lo que se considera el primer algoritmo destinado a ser procesado por una máquina. Su visión de las computadoras como herramientas capaces de manipular símbolos, música y texto anticipó por más de un siglo los usos modernos de la informática. +--- diff --git a/src/i18n/home.ts b/src/i18n/home.ts index a28c07b..8b27c95 100644 --- a/src/i18n/home.ts +++ b/src/i18n/home.ts @@ -24,6 +24,15 @@ export const texts = { 'earlybird.description': 'La venta de entradas con descuento Early Bird ya ha comenzado. ¡No te pierdas esta oportunidad única de aprender, conectar y crecer en la comunidad Python!', 'earlybird.button': 'Comprar entradas', + 'speakers.title': 'Oradores plenarios', + 'speakers.description': + 'Las voces más relevantes de la comunidad Python compartirán su visión y experiencia en la PyConES 2026. Descubre a las personas que protagonizarán las charlas plenarias de esta edición.', + 'speakers.altphoto': 'Foto de {name}', + 'speakers.aria_github': 'GitHub de {name}', + 'speakers.aria_linkedin': 'LinkedIn de {name}', + 'speakers.aria_instagram': 'Instagram de {name}', + 'speakers.aria_website': 'Sitio web de {name}', + 'speakers.aria_social_links': 'Enlaces sociales de {name}', }, en: { 'index.initializing': 'Initialising system...', @@ -51,6 +60,15 @@ export const texts = { 'earlybird.description': 'Early Bird discounted tickets are now on sale. Do not miss this unique opportunity to learn, connect, and grow in the Python community!', 'earlybird.button': 'Buy tickets', + 'speakers.title': 'Plenary Speakers', + 'speakers.description': + 'The most relevant voices in the Python community will share their vision and experience at PyConES 2026. Meet the people headlining the plenary talks of this edition.', + 'speakers.altphoto': 'Photo of {name}', + 'speakers.aria_github': '{name} on GitHub', + 'speakers.aria_linkedin': '{name} on LinkedIn', + 'speakers.aria_instagram': '{name} on Instagram', + 'speakers.aria_website': "{name}'s website", + 'speakers.aria_social_links': "{name}'s social links", }, ca: { 'index.initializing': 'Inicialitzant sistema...', @@ -78,5 +96,14 @@ export const texts = { 'earlybird.description': "La venda d'entrades amb descompte Early Bird ja ha començat. No et perdis aquesta oportunitat única d'aprendre, connectar i créixer en la comunitat Python!", 'earlybird.button': 'Comprar entrades', + 'speakers.title': 'Ponents plenaris', + 'speakers.description': + 'Les veus més rellevants de la comunitat Python compartiran la seva visió i experiència a la PyConES 2026. Descobreix les persones que protagonitzaran les xerrades plenàries d’aquesta edició.', + 'speakers.altphoto': 'Foto de {name}', + 'speakers.aria_github': 'GitHub de {name}', + 'speakers.aria_linkedin': 'LinkedIn de {name}', + 'speakers.aria_instagram': 'Instagram de {name}', + 'speakers.aria_website': 'Lloc web de {name}', + 'speakers.aria_social_links': 'Enllaços socials de {name}', }, } as const diff --git a/src/types/speakers.ts b/src/types/speakers.ts new file mode 100644 index 0000000..f488ed4 --- /dev/null +++ b/src/types/speakers.ts @@ -0,0 +1,14 @@ +export type TSpeakerLinkType = 'github' | 'linkedin' | 'instagram' | 'website' + +export interface ISpeakerLink { + type: TSpeakerLinkType + url: string +} + +export interface ISpeaker { + name: string + order: number + photo: string + links: ISpeakerLink[] + description: string +}