diff --git a/pwa/app/(common)/events/components/EventsPage.tsx b/pwa/app/(common)/events/components/EventsPage.tsx index d9df5b941..dd2d7ecd4 100644 --- a/pwa/app/(common)/events/components/EventsPage.tsx +++ b/pwa/app/(common)/events/components/EventsPage.tsx @@ -86,7 +86,8 @@ export default function EventsPage({ events }: EventsPageProps) {
{!type || type.toLowerCase() === "conference" ? ( -
+ <> + /*
-
+
*/ ) : null} {Object.keys(eventsByYear) .sort() diff --git a/pwa/app/(con)/[locale]/con/2026/components/AfterMovie.tsx b/pwa/app/(con)/[locale]/con/2026/components/AfterMovie.tsx new file mode 100644 index 000000000..7a61921e7 --- /dev/null +++ b/pwa/app/(con)/[locale]/con/2026/components/AfterMovie.tsx @@ -0,0 +1,29 @@ +"use client"; +import SectionTitle from "components/con/common/typography/SectionTitle"; +import Section from "components/con/home/Section"; +import { useContext } from "react"; +import { LanguageContext } from "contexts/con/LanguageContext"; +import SectionSubTitle from "components/con/common/typography/SectionSubtitle"; + +export default function AfterMovie() { + const { t, Translate } = useContext(LanguageContext); + return ( +
+
+ + + + {t("2024.aftermovie.subtitle")} + +
+
+ ); +} diff --git a/pwa/app/(con)/[locale]/con/2026/review/components/Review/ReviewCover.tsx b/pwa/app/(con)/[locale]/con/2026/review/components/Review/ReviewCover.tsx new file mode 100644 index 000000000..313ceca87 --- /dev/null +++ b/pwa/app/(con)/[locale]/con/2026/review/components/Review/ReviewCover.tsx @@ -0,0 +1,23 @@ +"use client"; +import ReviewCoverBase from "components/con/review/ReviewCover"; +import { useContext } from "react"; +import { LanguageContext } from "contexts/con/LanguageContext"; + +export default function ReviewCover() { + const { t, Translate } = useContext(LanguageContext); + return ( + +

{t("2026.review.subtitle_1")}

+ + + } + /> + ); +} diff --git a/pwa/app/(con)/[locale]/con/2026/review/components/Review/en.tsx b/pwa/app/(con)/[locale]/con/2026/review/components/Review/en.tsx new file mode 100644 index 000000000..4cccebbdd --- /dev/null +++ b/pwa/app/(con)/[locale]/con/2026/review/components/Review/en.tsx @@ -0,0 +1,389 @@ +/* eslint-disable react/no-unescaped-entities */ +"use client"; +import React from "react"; +import Button from "components/con/common/Button"; +import useDynamicRefs from "hooks/con/useDynamicRefs"; +import ReviewItem from "components/con/review/ReviewItem"; +import LinedTitle from "components/con/common/typography/LinedTitle"; + +export default function ReviewList() { + const [, setRef] = useDynamicRefs(); + const reviewRef = setRef("review-list"); + + return ( +
+
+ + 6th + edition buzzin’ + + } + > + + API Platform 5 and Mercure 1.0 released + +

+ Kévin Dunglas introduced Mercure 1.0, the first stable release + following years of development, which also packs major new features. +

+

+ Antoine Bluchet showcased his recent work on integrating MCP into + API Platform, followed by the new features in API Platform 5.0. +

+
+ + 29 + amazing talks + + } + > + + Exclusive contents for every objective. + +

+ In Lille last September, the most influential voices in the PHP + ecosystem (and beyond) gathered to share their knowledge, research, + and insights, with strong representation from tech communities + throughout the event. +

+ +
+ + 26 + partners + + } + > + + A huge thank you to all our incredible sponsors and partners for + making this edition possible. + +

+ A massive shoutout to our Platinum sponsors,{" "} + + Les-Tilleuls.coop + {" "} + and{" "} + + Tilia.coop + + , API Platform creators, maintainers, and organizers of the + conference. +

+

+ We’d like to express our deepest gratitude to our Gold sponsors,{" "} + + France TV + {" "} + and{" "} + + Laravel + + . +

+

+ Thank you to our Silver partners:{" "} + + Bakslash + + ,{" "} + + SensioLabs + + ,{" "} + + Sweeek + + ,{" "} + + Vonage + + ,{" "} + + Clever Cloud + + ,{" "} + + Peinture + + ,{" "} + + Packagist + + ,{" "} + + UR SCOP + + , and{" "} + + CoopTech + + . +

+

+ Thank you as well to{" "} + + Caddy + {" "} + for their Bronze support. +

+

+ Thank you to all the vital members of our Community:{" "} + + Emagma + + ,{" "} + + JL Recrutement + + ,{" "} + + Larabelles + + ,{" "} + + Typesense + + ,{" "} + + Symfony + + ,{" "} + + Motiv'Her + + ,{" "} + + EuraTechnologies + + , and{" "} + + Laravel France + + . +

+

+ Special thanks to{" "} + + BitExpert + {" "} + and{" "} + + MongoDB + {" "} + for their Travel support. +

+

+ Finally, thank you to our Media partners{" "} + + Archimag + {" "} + and{" "} + + À La French + {" "} + for helping us spread the word and bring this event to life. +

+ +
+ + 1 + unmatched community party + + } + > + + One of the unmissable gatherings of the event. + +

+ As every year, the community party took place at Les Sales Mômes, + with the precious support of{" "} + JL Recrutement. Drinks, + French fries, and laughs: the perfect cocktail to end the first day + of the event. +

+
+ + 1 + conference assistant + + } + > + + Ready to give you the best experience + +

+ This year at the conference, we gave you the opportunity to discover + our event companion! It allowed you to explore the program, check + last-minute updates, rate talks, and easily build your personal + agenda. We’re already looking forward to improving this tool for + next year! +

+
+
+
+ ); +} diff --git a/pwa/app/(con)/[locale]/con/2026/review/components/Review/fr.tsx b/pwa/app/(con)/[locale]/con/2026/review/components/Review/fr.tsx new file mode 100644 index 000000000..e31fe37e2 --- /dev/null +++ b/pwa/app/(con)/[locale]/con/2026/review/components/Review/fr.tsx @@ -0,0 +1,392 @@ +/* eslint-disable react/no-unescaped-entities */ +"use client"; +import React from "react"; +import Button from "components/con/common/Button"; +import useDynamicRefs from "hooks/con/useDynamicRefs"; +import ReviewItem from "components/con/review/ReviewItem"; +import LinedTitle from "components/con/common/typography/LinedTitle"; + +export default function ReviewList() { + const [, setRef] = useDynamicRefs(); + const reviewRef = setRef("review-list"); + + return ( +
+
+ + 1 + édition plus vibrante que jamais + + } + > + + Sortie d'API Platform 5 et Mercure 1.0 + +

+ Kévin Dunglas a présenté Mercure 1.0, la première version stable + après plusieurs années de développement, qui intègre également de + nouvelles fonctionnalités majeures. +

+

+ De son côté, Antoine Bluchet a présenté ses récents travaux sur + l'intégration du MCP dans API Platform, suivis des nouvelles + fonctionnalités d'API Platform 5.0. +

+
+ + 29 + conférences passionnantes + + } + > + + Des contenus exclusifs adaptés à tous les objectifs + +

+ Les voix les plus influentes de l'écosystème PHP (et au-delà) se + sont réunies pendant deux jours à Lille pour partager leurs + connaissances, leurs recherches et leurs réflexions, auprès d’un + public captif et curieux. +

+ +
+ + 26 + partenaires + + } + > + + Un immense merci à l'ensemble de nos incroyables sponsors et + partenaires ! + +

+ Un grand merci à nos sponsors Platinum,{" "} + + Les-Tilleuls.coop + {" "} + et{" "} + + Tilia.coop + + , créateurs, mainteneurs d'API Platform et organisateurs de la + conférence. +

+

+ Nous tenons à exprimer notre profonde gratitude à nos sponsors Gold,{" "} + + France TV + {" "} + et{" "} + + Laravel + + . +

+

+ Merci à nos partenaires Silver :{" "} + + Bakslash + + ,{" "} + + SensioLabs + + ,{" "} + + Sweeek + + ,{" "} + + Vonage + + ,{" "} + + Clever Cloud + + ,{" "} + + Peinture + + ,{" "} + + Packagist + + ,{" "} + + UR SCOP + {" "} + et{" "} + + CoopTech + + . +

+

+ Merci également à{" "} + + Caddy + {" "} + pour son soutien Bronze. +

+

+ Merci à tous les membres essentiels de notre Communauté :{" "} + + Emagma + + ,{" "} + + JL Recrutement + + ,{" "} + + Larabelles + + ,{" "} + + Typesense + + ,{" "} + + Symfony + + ,{" "} + + Motiv'Her + + ,{" "} + + EuraTechnologies + {" "} + et{" "} + + Laravel France + + . +

+

+ Un remerciement particulier à{" "} + + BitExpert + {" "} + et{" "} + + MongoDB + {" "} + pour avoir pris en charge le déplacement de leurs conférenciers. +

+

+ Enfin, merci à nos partenaires Média{" "} + + Archimag + {" "} + et{" "} + + À La French + {" "} + pour nous avoir aidés à faire connaître et faire vivre cet + événement. +

+ +
+ + 1 + soirée communautaire incontournable + + } + > + + Un des rendez-vous incontournables de l'événement. + +

+ Comme chaque année, la soirée communautaire s'est déroulée aux Sales + Mômes, avec le précieux soutien du cabinet{" "} + JL Recrutement. + Boissons, frites et rigolades : le cocktail parfait pour clôturer la + journée de l'événement. +

+
+ + 1 + assistant de conférence + + } + > + + Prêt à vous offrir la meilleure expérience possible + +

+ Cette année lors de la conférence, nous vous avons proposé de + découvrir notre assistant virtuel, vous permettant de consulter le + programme, de vérifier les dernières mises à jour, d'évaluer les + conférences et de composer facilement votre agenda personnel. Nous + avons déjà hâte d'améliorer cet outil pour l'année prochaine. +

+
+
+
+ ); +} diff --git a/pwa/app/(con)/[locale]/con/2026/review/page.tsx b/pwa/app/(con)/[locale]/con/2026/review/page.tsx new file mode 100644 index 000000000..d3a9d2475 --- /dev/null +++ b/pwa/app/(con)/[locale]/con/2026/review/page.tsx @@ -0,0 +1,73 @@ +import { getAllEditionPictures } from "api/con/editions"; +import Cover from "./components/Review/ReviewCover"; +import ReviewListFr from "./components/Review/fr"; +import ReviewListEn from "./components/Review/en"; +import Image from "next/image"; +import PictureGallery from "components/con/common/PictureGallery"; +import { Locale, i18n } from "i18n/i18n-config"; +import { Metadata } from "next"; +import AfterMovie from "app/con/2026/components/AfterMovie"; + +type Props = { + params: { locale: Locale }; +}; +export async function generateMetadata({ params }: Props): Promise { + const locale = params.locale || i18n.defaultLocale; + const dictionary = await import(`i18n/meta/${locale}.json`); + + return { + title: dictionary.review.title, + description: dictionary.review.description.replace("%edition%", "2026"), + openGraph: { + title: `${dictionary.review.title} - API Platform Conference 2026`, + description: dictionary.review.description.replace("%edition%", "2026"), + }, + twitter: { + title: `${dictionary.review.title} - API Platform Conference 2026`, + description: dictionary.review.description.replace("%edition%", "2026"), + }, + alternates: { + languages: { + en: locale === "en" ? undefined : "/con/2026/review", + fr: locale === "fr" ? undefined : "/fr/con/2026/review", + }, + }, + }; +} + +export default async function Page({ params }: { params: { locale: Locale } }) { + const images = await getAllEditionPictures("2026"); + return ( + <> + + { + params.locale === "fr" ? ( + + ) : null /*FIXME: find an other way to translate this page*/ + } + { + params.locale === "en" ? ( + + ) : null /*FIXME: find an other way to translate this page*/ + } +
+ +
+ + {images.map((image: string) => ( + + ))} + + + ); +} diff --git a/pwa/app/(con)/[locale]/con/components/HomePage.tsx b/pwa/app/(con)/[locale]/con/components/HomePage.tsx new file mode 100644 index 000000000..9756fdc9d --- /dev/null +++ b/pwa/app/(con)/[locale]/con/components/HomePage.tsx @@ -0,0 +1,64 @@ +"use client"; +import { useContext } from "react"; +import Image from "next/image"; +import Cover from "components/con/home/Cover"; +import Button from "components/con/common/Button"; +import Section from "components/con/home/Section"; +import PictureGallery from "components/con/common/PictureGallery"; +import SectionTitle from "components/con/common/typography/SectionTitle"; +import ContactCard from "components/con/layout/ContactCard"; +import AfterMovie from "app/con/2026/components/AfterMovie"; +import { LanguageContext } from "contexts/con/LanguageContext"; + +type HomePageProps = { + images: string[]; +}; + +export default function HomePage({ images }: HomePageProps) { + const { t, Translate, locale } = useContext(LanguageContext); + + return ( + <> + + + + + } + /> +
+
+ + + +
+ + {images.map((image) => ( + API Platform Conference 2026 + ))} + +
+
+ +
+ + + ); +} diff --git a/pwa/app/(con)/[locale]/con/editions/components/EditionPage.tsx b/pwa/app/(con)/[locale]/con/editions/components/EditionPage.tsx index 926c12ca8..03805748e 100644 --- a/pwa/app/(con)/[locale]/con/editions/components/EditionPage.tsx +++ b/pwa/app/(con)/[locale]/con/editions/components/EditionPage.tsx @@ -9,9 +9,9 @@ import SectionSubTitle from "components/con/common/typography/SectionSubtitle"; import { LanguageContext } from "contexts/con/LanguageContext"; export default function Editions() { - const previousEditions = editions.filter( - (edition) => edition.year !== currentEdition - ); + const previousEditions = editions + .filter((edition) => edition.year !== currentEdition) + .sort((a, b) => Number(b.year) - Number(a.year)); const { t, Translate } = useContext(LanguageContext); return ( <> diff --git a/pwa/app/(con)/[locale]/con/page.tsx b/pwa/app/(con)/[locale]/con/page.tsx new file mode 100644 index 000000000..eec17a2de --- /dev/null +++ b/pwa/app/(con)/[locale]/con/page.tsx @@ -0,0 +1,68 @@ +import { getAllEditionPictures } from "api/con/editions"; +import LayoutBase from "components/con/layout/LayoutBase"; +import editions, { currentEdition } from "data/con/editions"; +import { Locale, i18n } from "i18n/i18n-config"; +import { Metadata } from "next"; +import HomePage from "./components/HomePage"; + +type Props = { + params: { locale: Locale }; +}; + +export async function generateMetadata({ params }: Props): Promise { + const locale = params.locale || i18n.defaultLocale; + const dictionary = await import(`i18n/meta/${locale}.json`); + + return { + title: { + absolute: dictionary.title, + }, + alternates: { + languages: { + en: locale === "en" ? undefined : "/con", + fr: locale === "fr" ? undefined : "/fr/con", + }, + }, + }; +} + +const nav = { + logoLink: "/", + links: [ + { + to: "/{{locale}}/con/editions", + text: "nav.links.previous_editions", + }, + { + to: "/{{locale}}/con/2026/review", + text: "con_home.review", + }, + { + to: "/{{locale}}/con/2026", + text: "Archive 2026", + }, + ], +}; + +export default async function Page({ params }: Props) { + const { locale } = params; + const images = await getAllEditionPictures("2026"); + + const footer = [ + { + title: "Previous editions", + links: editions + .filter((edition) => edition.year !== currentEdition) + .map((edition) => ({ + title: `${edition.year} edition`, + link: `/${locale}/con/${edition.year}`, + })), + }, + ]; + + return ( + + + + ); +} diff --git a/pwa/data/con/2026/nav.ts b/pwa/data/con/2026/nav.ts index 890ee7eb7..3cb4fddd4 100644 --- a/pwa/data/con/2026/nav.ts +++ b/pwa/data/con/2026/nav.ts @@ -1,5 +1,9 @@ const nav = { logoLink: "/", + backLink: { + to: "/con", + text: "back_to_current_edition", + }, links: [ { to: "/{{locale}}/con/2026/", @@ -15,12 +19,12 @@ const nav = { text: "nav.links.conferences", }, { - to: "/{{locale}}/con/2026/#venue", - text: "nav.links.venue", + to: "/{{locale}}/con/2026/review", + text: "Review 2026", }, { - to: "/{{locale}}/con/2026/schedule", - text: "nav.links.schedule", + to: "/{{locale}}/con/2026", + text: "Archive 2026", }, ], }; diff --git a/pwa/data/con/editions.ts b/pwa/data/con/editions.ts index 5f07f5931..ef3e7e4c2 100644 --- a/pwa/data/con/editions.ts +++ b/pwa/data/con/editions.ts @@ -33,7 +33,7 @@ export const editions: Edition[] = [ }, { year: "2026", - image: "2025", + image: "2026", startDate: "2026-09-17", endDate: "2026-09-18", }, @@ -47,6 +47,6 @@ export function getPreviousEdition(currentEdition: string) { } // eslint-disable-next-line @typescript-eslint/no-inferrable-types -export const currentEdition: string = "2026"; +export const currentEdition: string = "2027"; export default editions; diff --git a/pwa/i18n/dictionaries/en.json b/pwa/i18n/dictionaries/en.json index 2e5888803..2256c8fab 100644 --- a/pwa/i18n/dictionaries/en.json +++ b/pwa/i18n/dictionaries/en.json @@ -252,6 +252,11 @@ "2026": { "baseline": "The only conference dedicated to API Platform and its ecosystem is back on September 17–18, 2026!", "date": "September 17-18, 2026 - Lille & online", + "review": { + "subtitle_1": "Thank you for making API Platform Conference 2026 possible, and for your support and enthusiasm during these two days of conference.", + "subtitle_2": "Our event will be back in September 2027 in Lille and online. As every year, tickets and the CFP will open in January 2027.", + "title": "An edition looking into the future." + }, "missing_conferences": { "subtitle": "Subscribe to {{link}} to discover replay videos this winter!", "link": "our Youtube channel", @@ -410,6 +415,11 @@ "tools": "Tools" } }, + "con_home": { + "baseline": "The international conference dedicated to API Platform and its ecosystem", + "date": "Lille & online", + "review": "2026 review" + }, "contact_us": "Contact us!", "days_count": "{{count}} day", "days_count_plural": "{{count}} days", diff --git a/pwa/i18n/dictionaries/fr.json b/pwa/i18n/dictionaries/fr.json index 2647bc3ea..4298aee40 100644 --- a/pwa/i18n/dictionaries/fr.json +++ b/pwa/i18n/dictionaries/fr.json @@ -248,6 +248,11 @@ "2026": { "baseline": "L'événement phare dédié à API Platform et son écosystème est de retour les 17 et 18 septembre à Lille !", "date": "17 et 18 septembre 2026 - Lille & en ligne", + "review": { + "subtitle_1": "Merci de votre présence à l'API Platform Conference 2026, ainsi que pour votre soutien et votre enthousiasme durant ces deux jours de conférence.", + "subtitle_2": "Notre événement sera de retour en septembre 2027 à Lille et en ligne. Comme chaque année, la billetterie et le CFP ouvriront en janvier 2027.", + "title": "Une édition tournée vers l'avenir." + }, "our_speakers": { "speaker": { "coming_soon": "Prochainement" }, "subtitle": "Rejoignez nos experts pour concevoir des logiciels durables, propulsés par les technologies les plus avancées d'aujourd'hui.", @@ -406,6 +411,11 @@ "tools": "Outils" } }, + "con_home": { + "baseline": "La conférence internationale dédiée à API Platform et son écosystème", + "date": "Lille & en ligne", + "review": "Review 2026" + }, "contact_us": "Contactez-nous !", "days_count": "{{count}} jour", "days_count_plural": "{{count}} jours", diff --git a/pwa/next.config.mjs b/pwa/next.config.mjs index 97c08aae0..98fd6ed43 100644 --- a/pwa/next.config.mjs +++ b/pwa/next.config.mjs @@ -164,16 +164,6 @@ const nextConfig = { }, async redirects() { return [ - { - source: "/con", - destination: "/con/2026", - permanent: false, - }, - { - source: "/fr/con", - destination: "/fr/con/2026", - permanent: false, - }, { source: "/docs/", destination: "/docs/symfony/", diff --git a/pwa/public/images/con/2026/review/assistant.jpg b/pwa/public/images/con/2026/review/assistant.jpg new file mode 100644 index 000000000..8e08d94cb Binary files /dev/null and b/pwa/public/images/con/2026/review/assistant.jpg differ diff --git a/pwa/public/images/con/2026/review/buzz.jpg b/pwa/public/images/con/2026/review/buzz.jpg new file mode 100644 index 000000000..3ff12d43c Binary files /dev/null and b/pwa/public/images/con/2026/review/buzz.jpg differ diff --git a/pwa/public/images/con/2026/review/community.jpg b/pwa/public/images/con/2026/review/community.jpg new file mode 100644 index 000000000..5d6f24ce7 Binary files /dev/null and b/pwa/public/images/con/2026/review/community.jpg differ diff --git a/pwa/public/images/con/2026/review/partners.jpg b/pwa/public/images/con/2026/review/partners.jpg new file mode 100644 index 000000000..e480b801f Binary files /dev/null and b/pwa/public/images/con/2026/review/partners.jpg differ diff --git a/pwa/public/images/con/2026/review/pic-01.jpg b/pwa/public/images/con/2026/review/pic-01.jpg new file mode 100644 index 000000000..6afbd88c8 Binary files /dev/null and b/pwa/public/images/con/2026/review/pic-01.jpg differ diff --git a/pwa/public/images/con/2026/review/pic-02.jpg b/pwa/public/images/con/2026/review/pic-02.jpg new file mode 100644 index 000000000..c6901876e Binary files /dev/null and b/pwa/public/images/con/2026/review/pic-02.jpg differ diff --git a/pwa/public/images/con/2026/review/pic-03.jpg b/pwa/public/images/con/2026/review/pic-03.jpg new file mode 100644 index 000000000..91b4d14da Binary files /dev/null and b/pwa/public/images/con/2026/review/pic-03.jpg differ diff --git a/pwa/public/images/con/2026/review/pic-04.jpg b/pwa/public/images/con/2026/review/pic-04.jpg new file mode 100644 index 000000000..29b87f9d0 Binary files /dev/null and b/pwa/public/images/con/2026/review/pic-04.jpg differ diff --git a/pwa/public/images/con/2026/review/pic-05.jpg b/pwa/public/images/con/2026/review/pic-05.jpg new file mode 100644 index 000000000..c4a2e646c Binary files /dev/null and b/pwa/public/images/con/2026/review/pic-05.jpg differ diff --git a/pwa/public/images/con/2026/review/pic-06.jpg b/pwa/public/images/con/2026/review/pic-06.jpg new file mode 100644 index 000000000..28dc59076 Binary files /dev/null and b/pwa/public/images/con/2026/review/pic-06.jpg differ diff --git a/pwa/public/images/con/2026/review/pic-07.jpg b/pwa/public/images/con/2026/review/pic-07.jpg new file mode 100644 index 000000000..41964491a Binary files /dev/null and b/pwa/public/images/con/2026/review/pic-07.jpg differ diff --git a/pwa/public/images/con/2026/review/pic-08.jpg b/pwa/public/images/con/2026/review/pic-08.jpg new file mode 100644 index 000000000..15c2cb534 Binary files /dev/null and b/pwa/public/images/con/2026/review/pic-08.jpg differ diff --git a/pwa/public/images/con/2026/review/pic-09.jpg b/pwa/public/images/con/2026/review/pic-09.jpg new file mode 100644 index 000000000..8fe93af9c Binary files /dev/null and b/pwa/public/images/con/2026/review/pic-09.jpg differ diff --git a/pwa/public/images/con/2026/review/pic-10.jpg b/pwa/public/images/con/2026/review/pic-10.jpg new file mode 100644 index 000000000..f31d05b17 Binary files /dev/null and b/pwa/public/images/con/2026/review/pic-10.jpg differ diff --git a/pwa/public/images/con/2026/review/pic-11.jpg b/pwa/public/images/con/2026/review/pic-11.jpg new file mode 100644 index 000000000..c6cd0f7d5 Binary files /dev/null and b/pwa/public/images/con/2026/review/pic-11.jpg differ diff --git a/pwa/public/images/con/2026/review/pic-12.jpg b/pwa/public/images/con/2026/review/pic-12.jpg new file mode 100644 index 000000000..a6b513062 Binary files /dev/null and b/pwa/public/images/con/2026/review/pic-12.jpg differ diff --git a/pwa/public/images/con/2026/review/speakers.jpg b/pwa/public/images/con/2026/review/speakers.jpg new file mode 100644 index 000000000..8e3192ba8 Binary files /dev/null and b/pwa/public/images/con/2026/review/speakers.jpg differ diff --git a/pwa/public/images/con/editions/2026.jpg b/pwa/public/images/con/editions/2026.jpg new file mode 100644 index 000000000..92a81e556 Binary files /dev/null and b/pwa/public/images/con/editions/2026.jpg differ