diff --git a/website/astro.config.mjs b/website/astro.config.mjs index 60217f34..643583c2 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -67,7 +67,11 @@ export default defineConfig({ lastmod: new Date(), i18n: { defaultLocale: DEFAULT_LOCALE, locales: LOCALES_MAP }, filter: (page) => { + const path = new URL(page).pathname.replace(/\/$/, "") || "/"; + const isTeamIndex = + path === "/team" || /\/[a-z]{2}-[A-Z]{2}\/team$/.test(path); return ( + !isTeamIndex && !page.includes("/tags/") && !page.includes("/account/") && !page.includes("/oauth/") && diff --git a/website/src/components/features/about/TeamSection.astro b/website/src/components/features/about/TeamSection.astro index 77f18b0e..e5cf7b11 100644 --- a/website/src/components/features/about/TeamSection.astro +++ b/website/src/components/features/about/TeamSection.astro @@ -6,8 +6,13 @@ import JosephMattia from "@/assets/team/joe-mattia.webp"; import NikolausHager from "@/assets/team/nikolaus-hager.webp"; import JonathanAngle from "@/assets/team/jonathan-angle.webp"; import JarrodJayFrankel from "@/assets/team/jarrod-jay-frankel.webp"; -import { createTranslator, getLocaleFromUrl } from "@/utils/i18n"; +import { + createTranslator, + getLocaleFromUrl, + getLocalizedPath, +} from "@/utils/i18n"; import { TEAMS } from "@/constants/teams"; +import { isPersonId } from "@/constants/people"; const locale = getLocaleFromUrl(Astro.url.pathname); const t = await createTranslator(locale); @@ -32,40 +37,54 @@ const TEAM_IMAGES = {
{ - TEAMS.map((team) => ( -
-
- - {team.name} - -
- - )) + ); + }) }
@@ -148,6 +167,14 @@ const TEAM_IMAGES = { display: block; } + .team-name-link { + text-decoration: none; + } + + .team-name-link:hover .team-name { + color: #ff6b35; + } + .team-role { font-family: "Geist Mono", monospace; font-size: 11px; diff --git a/website/src/components/features/blog/BlogPost.astro b/website/src/components/features/blog/BlogPost.astro index 2bdd47c1..11658140 100644 --- a/website/src/components/features/blog/BlogPost.astro +++ b/website/src/components/features/blog/BlogPost.astro @@ -2,14 +2,18 @@ import Layout from "@/components/layout/Layout.astro"; import Card from "@/components/features/blog/Card.astro"; import type { CollectionEntry } from "astro:content"; -import type { Article, WithContext } from "schema-dts"; +import type { Article } from "schema-dts"; import { getLocaleFromUrl, getLocalizedPath, createTranslator, } from "@/utils/i18n"; -import env from "@/config"; import { createMetadata } from "@/utils/create-metadata"; +import { JsonLdGraph } from "@/utils/build-json-ld"; +import { PEOPLE, isPersonId, personId } from "@/constants/people"; +import { getPersonJsonLd } from "@/constants/person-jsonld"; +import { organizationJsonLd } from "@/constants/default-jsonld"; +import env from "@/config"; type Props = CollectionEntry<"blog">["data"] & { relatedPosts?: CollectionEntry<"blog">[]; @@ -23,6 +27,7 @@ const { heroImage, heroAlt, tags = [], + author: authorId, relatedPosts = [], } = Astro.props; @@ -38,25 +43,32 @@ const metadata = createMetadata({ }); const blogIndexHref = getLocalizedPath(currentLocale, "/blog"); +const author = authorId && isPersonId(authorId) ? PEOPLE[authorId] : undefined; -const articleSchema: WithContext
= { - "@context": "https://schema.org", +const article: Article = { "@type": "Article", + "@id": metadata.canonical as string, headline: title, description: description, url: metadata.canonical as string, image: metadata.openGraph?.basic?.image, datePublished: pubDate.toISOString(), dateModified: updatedDate?.toISOString() || pubDate.toISOString(), - author: { - "@type": "Organization", - name: env.SITE_NAME, - url: env.SITE_BASE_URL, - }, + author: author + ? { "@id": personId(author.id) } + : { "@id": env.SITE_BASE_URL }, + publisher: { "@id": env.SITE_BASE_URL }, }; + +const jsonLd = JsonLdGraph({ + "@context": "https://schema.org", + "@graph": author + ? [article, getPersonJsonLd(author.id), organizationJsonLd] + : [article, organizationJsonLd], +}); --- - +
= { }  ·  - {t("blog.post.author")} + { + author ? ( + + {author.name} + + ) : ( + {t("blog.post.author")} + ) + }

{ updatedDate && ( diff --git a/website/src/components/features/team/PersonPage.astro b/website/src/components/features/team/PersonPage.astro new file mode 100644 index 00000000..e81ac28a --- /dev/null +++ b/website/src/components/features/team/PersonPage.astro @@ -0,0 +1,164 @@ +--- +import { Image } from "astro:assets"; +import Layout from "@/components/layout/Layout.astro"; +import { PEOPLE, type PersonId } from "@/constants/people"; +import { PERSON_IMAGES } from "@/constants/person-images"; +import { getProfilePageJsonLd } from "@/constants/person-jsonld"; +import { createMetadata } from "@/utils/create-metadata"; +import { + createTranslator, + getLocaleFromUrl, + getLocalizedPath, +} from "@/utils/i18n"; + +interface Props { + slug: PersonId; +} + +const { slug } = Astro.props; +const person = PEOPLE[slug]; +const image = PERSON_IMAGES[slug]; + +const locale = getLocaleFromUrl(Astro.url.pathname); +const t = await createTranslator(locale); + +const metadata = createMetadata({ + title: t(`team.people.${slug}.meta.title`), + description: t(`team.people.${slug}.meta.description`), + pathname: Astro.url.pathname, + imageUrl: image.src, + imageAlt: person.name, +}); + +const jobTitle = t(`team.people.${slug}.jobTitle`); +const bio = t(`team.people.${slug}.bio`); + +const jsonLd = getProfilePageJsonLd(slug, metadata.canonical as string, { + jobTitle, + description: bio, +}); +const aboutTeamHref = `${getLocalizedPath(locale, "/about")}#team`; +--- + + + + + + diff --git a/website/src/components/features/whitepaper/WhitepaperHeader.astro b/website/src/components/features/whitepaper/WhitepaperHeader.astro index ee5fc91d..329c2066 100644 --- a/website/src/components/features/whitepaper/WhitepaperHeader.astro +++ b/website/src/components/features/whitepaper/WhitepaperHeader.astro @@ -1,8 +1,9 @@ --- import type { Locale } from "@/utils/i18n"; -import { formatDate } from "@/utils/i18n"; +import { formatDate, getLocalizedPath } from "@/utils/i18n"; import VersionSelector from "./VersionSelector.astro"; import DownloadButton from "./DownloadButton.astro"; +import { getPersonByName } from "@/constants/people"; export interface Props { title: string; @@ -55,7 +56,30 @@ const displayDate = updatedDate ?? publishedDate; >

{t("whitepaper.authors")}: - {authors.join(", ")} + { + authors.map((name, index) => { + const person = getPersonByName(name); + const href = person + ? getLocalizedPath(locale, `/team/${person.id}`) + : undefined; + + return ( + <> + {index > 0 ? ", " : " "} + {href ? ( + + {name} + + ) : ( + name + )} + + ); + }) + }

|

diff --git a/website/src/constants/default-jsonld.ts b/website/src/constants/default-jsonld.ts index 09893322..d57930fe 100644 --- a/website/src/constants/default-jsonld.ts +++ b/website/src/constants/default-jsonld.ts @@ -2,11 +2,13 @@ import env from "@/config"; import type { MobileApplication, Organization, + Person, TechArticle, WebSite, } from "schema-dts"; import defaultMetadata from "./default-metadata"; import { APP_LINKS } from "./app-links"; +import { getPersonByName, personId } from "./people"; export const websiteJsonLd: WebSite = { "@type": "WebSite", @@ -74,6 +76,11 @@ export const organizationJsonLd: Organization = { "https://www.youtube.com/@QuantusNetwork", "https://github.com/Quantus-Network", ], + founder: [ + { "@id": personId("christopher-smith") }, + { "@id": personId("joe-mattia") }, + ], + employee: { "@id": personId("jonathan-angle") }, }; export const iosAppJsonLd: MobileApplication = { @@ -107,17 +114,10 @@ export const whitepaperJsonLd: TechArticle = { description: "The official whitepaper for Quantus, detailing the versioned history, protocol, and architecture of the network.", author: { - "@type": "Organization", - name: "Quantus", - url: "https://github.com/Quantus-Network", + "@id": personId("christopher-smith"), }, publisher: { - "@type": "Organization", - name: "Quantus", - logo: { - "@type": "ImageObject", - url: "https://github.com/Quantus-Network.png", - }, + "@id": env.SITE_BASE_URL, }, inLanguage: "en-US", about: { @@ -127,9 +127,28 @@ export const whitepaperJsonLd: TechArticle = { }, }; +function resolveWhitepaperAuthors( + authorNames: string[], +): Person | Organization | (Person | Organization)[] { + const authors = authorNames.map((name) => { + const person = getPersonByName(name); + if (person) { + return { "@id": personId(person.id) } as Person; + } + return { + "@type": "Organization", + name, + url: env.SITE_BASE_URL, + } satisfies Organization; + }); + + return authors.length === 1 ? authors[0]! : authors; +} + export const getWhitepaperJsonLd = ( locale: string, version?: string, + authorNames: string[] = ["Christopher Smith"], ): TechArticle => { const basePath = locale === "en-US" @@ -145,6 +164,7 @@ export const getWhitepaperJsonLd = ( ...whitepaperJsonLd, "@id": url, inLanguage: locale, + author: resolveWhitepaperAuthors(authorNames), ...(version ? { version } : {}), encoding: { "@type": "MediaObject", diff --git a/website/src/constants/people.ts b/website/src/constants/people.ts new file mode 100644 index 00000000..a337fe1d --- /dev/null +++ b/website/src/constants/people.ts @@ -0,0 +1,91 @@ +import env from "@/config"; + +export const PERSON_IDS = [ + "christopher-smith", + "joe-mattia", + "jonathan-angle", +] as const; + +export type PersonId = (typeof PERSON_IDS)[number]; + +export type PersonRecord = { + id: PersonId; + name: string; + jobTitle: string; + bio: string; + sameAs: readonly string[]; + social: { + platform: "X"; + url: string; + username: string; + }; + isFounder?: boolean; + affiliation?: { + name: string; + url: string; + jobTitle: string; + }; +}; + +export const PEOPLE: Record = { + "christopher-smith": { + id: "christopher-smith", + name: "Christopher Smith", + jobTitle: "Founder and CEO, Quantus", + bio: "Christopher Smith is Editor-in-Chief of Quantum Canary and founder and CEO of Quantus. A technology entrepreneur working across artificial intelligence, blockchain and quantum computing, he has spent more than a decade building tools for decentralized systems. His earlier ventures include BitMesh, Lunyr and FactoryDAO, and he contributed to early Bitcoin software and privacy tooling. Chris is the author of the Quantus whitepaper and host of the QDay podcast, where he speaks with researchers and builders about quantum computing, cryptography and the future of digital money.", + sameAs: ["https://x.com/YuviLightman"], + social: { + platform: "X", + url: "https://x.com/YuviLightman", + username: "@YuviLightman", + }, + isFounder: true, + affiliation: { + name: "Quantum Canary", + url: "https://www.quantumcanary.org", + jobTitle: "Editor-in-Chief", + }, + }, + "joe-mattia": { + id: "joe-mattia", + name: "Joseph Mattia", + jobTitle: "Co-founder and COO, Quantus", + bio: "Joseph Mattia is co-founder and COO of Quantus, where he leads operations and helps turn post-quantum research into product execution and community programs. He has represented Quantus at QDay events and co-hosted early episodes of the QDay podcast, bringing an operator's perspective to questions about blockchain security, adoption and coordination. Joe focuses on the practical choices builders, institutions and asset holders must make before quantum risk becomes an emergency.", + sameAs: ["https://x.com/JoeMattia"], + social: { + platform: "X", + url: "https://x.com/JoeMattia", + username: "@JoeMattia", + }, + isFounder: true, + }, + "jonathan-angle": { + id: "jonathan-angle", + name: "Jonathan Angle", + jobTitle: "Communications Director, Quantus", + bio: "Jonathan “Jangle” Angle is Director of Communications at Quantus, the post-quantum blockchain. With a background in IT security, consulting, and DeFi, he has been integral to Quantus’s strategy, product, and operations. He writes on blockchain security, post-quantum cryptography, and DeFi as @defijangle.", + sameAs: ["https://x.com/defijangle"], + social: { + platform: "X", + url: "https://x.com/defijangle", + username: "@defijangle", + }, + }, +}; + +export function isPersonId(id: string): id is PersonId { + return Object.hasOwn(PEOPLE, id); +} + +export function getPersonByName(name: string): PersonRecord | undefined { + return Object.values(PEOPLE).find((person) => person.name === name); +} + +/** Canonical English profile URL. Person `@id` is always this URL + `#person`. */ +export function personUrl(slug: PersonId): string { + return `${env.SITE_BASE_URL.replace(/\/$/, "")}/team/${slug}`; +} + +export function personId(slug: PersonId): string { + return `${personUrl(slug)}#person`; +} diff --git a/website/src/constants/person-images.ts b/website/src/constants/person-images.ts new file mode 100644 index 00000000..7cea4742 --- /dev/null +++ b/website/src/constants/person-images.ts @@ -0,0 +1,11 @@ +import type { ImageMetadata } from "astro"; +import type { PersonId } from "@/constants/people"; +import christopherSmith from "@/assets/team/christopher-smith.webp"; +import joeMattia from "@/assets/team/joe-mattia.webp"; +import jonathanAngle from "@/assets/team/jonathan-angle.webp"; + +export const PERSON_IMAGES: Record = { + "christopher-smith": christopherSmith, + "joe-mattia": joeMattia, + "jonathan-angle": jonathanAngle, +}; diff --git a/website/src/constants/person-jsonld.ts b/website/src/constants/person-jsonld.ts new file mode 100644 index 00000000..04db9551 --- /dev/null +++ b/website/src/constants/person-jsonld.ts @@ -0,0 +1,115 @@ +import type { Graph, Person, ProfilePage, TechArticle } from "schema-dts"; +import env from "@/config"; +import { + PEOPLE, + PERSON_IDS, + getPersonByName, + personId, + personUrl, + type PersonId, +} from "@/constants/people"; +import { PERSON_IMAGES } from "@/constants/person-images"; +import { + getWhitepaperJsonLd, + organizationJsonLd, +} from "@/constants/default-jsonld"; + +function personImageUrl(slug: PersonId): string { + return new URL(PERSON_IMAGES[slug].src, env.SITE_BASE_URL).toString(); +} + +type PersonJsonLdCopy = { + jobTitle?: string; + description?: string; +}; + +export function getPersonJsonLd( + slug: PersonId, + copy?: PersonJsonLdCopy, +): Person { + const person = PEOPLE[slug]; + const imageUrl = personImageUrl(slug); + + const jsonLd: Person = { + "@type": "Person", + "@id": personId(slug), + name: person.name, + url: personUrl(slug), + image: { + "@type": "ImageObject", + url: imageUrl, + contentUrl: imageUrl, + }, + jobTitle: copy?.jobTitle ?? person.jobTitle, + description: copy?.description ?? person.bio, + sameAs: [...person.sameAs], + worksFor: { + "@id": env.SITE_BASE_URL, + }, + }; + + if (person.affiliation) { + jsonLd.affiliation = { + "@type": "Organization", + name: person.affiliation.name, + url: person.affiliation.url, + }; + } + + return jsonLd; +} + +export function getAllPersonJsonLd(): Person[] { + return PERSON_IDS.map((slug) => getPersonJsonLd(slug)); +} + +export function getProfilePageJsonLd( + slug: PersonId, + canonicalUrl: string, + copy?: PersonJsonLdCopy, +): Graph { + const person = getPersonJsonLd(slug, copy); + const profilePage: ProfilePage = { + "@type": "ProfilePage", + "@id": `${canonicalUrl}#profile`, + url: canonicalUrl, + name: PEOPLE[slug].name, + mainEntity: { "@id": personId(slug) }, + isPartOf: { + "@type": "WebSite", + name: "Quantus", + url: env.SITE_BASE_URL, + }, + }; + + return { + "@context": "https://schema.org", + "@graph": [profilePage, person, organizationJsonLd], + }; +} + +export function getWhitepaperJsonLdGraph( + locale: string, + version: string | undefined, + authorNames: string[], +): Graph { + const article: TechArticle = getWhitepaperJsonLd( + locale, + version, + authorNames, + ); + + const authorPeople = authorNames + .map((name) => getPersonByName(name)) + .filter((person): person is NonNullable => Boolean(person)) + .filter( + (person, index, list) => + list.findIndex((entry) => entry.id === person.id) === index, + ) + .map((person) => getPersonJsonLd(person.id)); + + return { + "@context": "https://schema.org", + "@graph": [article, ...authorPeople, organizationJsonLd], + }; +} diff --git a/website/src/content.config.ts b/website/src/content.config.ts index 718b9bf8..21afe7b3 100644 --- a/website/src/content.config.ts +++ b/website/src/content.config.ts @@ -12,6 +12,9 @@ const blog = defineCollection({ heroAlt: z.string().optional(), featured: z.boolean().optional(), tags: z.array(z.string()).default([]), + author: z + .enum(["christopher-smith", "joe-mattia", "jonathan-angle"]) + .optional(), }), }); diff --git a/website/src/i18n/de-DE.json b/website/src/i18n/de-DE.json index 6ec938b6..3e7f9729 100644 --- a/website/src/i18n/de-DE.json +++ b/website/src/i18n/de-DE.json @@ -509,6 +509,36 @@ "cta": "SCHREIBEN SIE UNS EINE NACHRICHT →" } }, + "team": { + "back_to_about": "Zurück zu Über uns", + "follow_on_x": "Auf X folgen", + "people": { + "christopher-smith": { + "jobTitle": "Gründer und CEO, Quantus", + "bio": "Christopher Smith ist Chefredakteur von Quantum Canary sowie Gründer und CEO von Quantus. Als Technologieunternehmer in den Bereichen künstliche Intelligenz, Blockchain und Quantencomputing entwickelt er seit mehr als einem Jahrzehnt Werkzeuge für dezentrale Systeme. Zu seinen früheren Unternehmen zählen BitMesh, Lunyr und FactoryDAO; außerdem wirkte er an früher Bitcoin-Software und Privacy-Tooling mit. Chris ist Autor des Quantus-Whitepapers und Moderator des QDay-Podcasts, in dem er mit Forschern und Buildern über Quantencomputing, Kryptografie und die Zukunft digitalen Geldes spricht.", + "meta": { + "title": "Christopher Smith | Gründer und CEO, Quantus", + "description": "Christopher Smith ist Gründer und CEO von Quantus und Chefredakteur von Quantum Canary. Er arbeitet an KI, Blockchain und Post-Quanten-Kryptografie." + } + }, + "joe-mattia": { + "jobTitle": "Mitgründer und COO, Quantus", + "bio": "Joseph Mattia ist Mitgründer und COO von Quantus. Er leitet den operativen Bereich und hilft, Post-Quanten-Forschung in Produktumsetzung und Community-Programme zu übersetzen. Er hat Quantus auf QDay-Veranstaltungen vertreten und frühe Folgen des QDay-Podcasts mitmoderiert – und bringt dabei die Perspektive eines Operators zu Blockchain-Sicherheit, Adoption und Koordination ein. Joe konzentriert sich auf die praktischen Entscheidungen, die Builder, Institutionen und Vermögensinhaber treffen müssen, bevor das Quantenrisiko zum Notfall wird.", + "meta": { + "title": "Joseph Mattia | Mitgründer und COO, Quantus", + "description": "Joseph Mattia ist Mitgründer und COO von Quantus. Er führt den Betrieb und macht aus Post-Quanten-Forschung Produkte, Community-Programme und QDay-Events." + } + }, + "jonathan-angle": { + "jobTitle": "Kommunikationsdirektor, Quantus", + "bio": "Jonathan „Jangle“ Angle ist Kommunikationsdirektor bei Quantus, der Post-Quanten-Blockchain. Mit Hintergrund in IT-Sicherheit, Beratung und DeFi hat er Strategie, Produkt und Betrieb von Quantus maßgeblich mitgestaltet. Er schreibt über Blockchain-Sicherheit, Post-Quanten-Kryptografie und DeFi als @defijangle.", + "meta": { + "title": "Jonathan Angle | Kommunikationsdirektor, Quantus", + "description": "Jonathan Angle leitet Kommunikation bei Quantus. Mit Erfahrung in IT-Sicherheit, Beratung und DeFi schreibt er als @defijangle über Post-Quanten-Kryptografie." + } + } + } + }, "community": { "meta": { "title": "Community | Treten Sie Quantus bei", diff --git a/website/src/i18n/en-US.json b/website/src/i18n/en-US.json index 20587691..44e92ddc 100644 --- a/website/src/i18n/en-US.json +++ b/website/src/i18n/en-US.json @@ -509,6 +509,36 @@ "cta": "SEND US A MESSAGE →" } }, + "team": { + "back_to_about": "Back to About", + "follow_on_x": "Follow on X", + "people": { + "christopher-smith": { + "jobTitle": "Founder and CEO, Quantus", + "bio": "Christopher Smith is Editor-in-Chief of Quantum Canary and founder and CEO of Quantus. A technology entrepreneur working across artificial intelligence, blockchain and quantum computing, he has spent more than a decade building tools for decentralized systems. His earlier ventures include BitMesh, Lunyr and FactoryDAO, and he contributed to early Bitcoin software and privacy tooling. Chris is the author of the Quantus whitepaper and host of the QDay podcast, where he speaks with researchers and builders about quantum computing, cryptography and the future of digital money.", + "meta": { + "title": "Christopher Smith | Founder and CEO, Quantus", + "description": "Christopher Smith is founder and CEO of Quantus and Editor-in-Chief of Quantum Canary, working across AI, blockchain, and post-quantum cryptography." + } + }, + "joe-mattia": { + "jobTitle": "Co-founder and COO, Quantus", + "bio": "Joseph Mattia is co-founder and COO of Quantus, where he leads operations and helps turn post-quantum research into product execution and community programs. He has represented Quantus at QDay events and co-hosted early episodes of the QDay podcast, bringing an operator's perspective to questions about blockchain security, adoption and coordination. Joe focuses on the practical choices builders, institutions and asset holders must make before quantum risk becomes an emergency.", + "meta": { + "title": "Joseph Mattia | Co-founder and COO, Quantus", + "description": "Joseph Mattia is co-founder and COO of Quantus, leading operations that turn post-quantum research into products, community programs, and QDay events." + } + }, + "jonathan-angle": { + "jobTitle": "Communications Director, Quantus", + "bio": "Jonathan “Jangle” Angle is Director of Communications at Quantus, the post-quantum blockchain. With a background in IT security, consulting, and DeFi, he has been integral to Quantus’s strategy, product, and operations. He writes on blockchain security, post-quantum cryptography, and DeFi as @defijangle.", + "meta": { + "title": "Jonathan Angle | Communications Director, Quantus", + "description": "Jonathan Angle leads communications at Quantus. With a background in IT security, consulting, and DeFi, he writes on post-quantum cryptography as @defijangle." + } + } + } + }, "community": { "meta": { "title": "Community | Join the Quantus Future", diff --git a/website/src/i18n/es-ES.json b/website/src/i18n/es-ES.json index fd6f3e6d..99ed45a2 100644 --- a/website/src/i18n/es-ES.json +++ b/website/src/i18n/es-ES.json @@ -509,6 +509,36 @@ "cta": "ENVÍENOS UN MENSAJE →" } }, + "team": { + "back_to_about": "Volver a Sobre nosotros", + "follow_on_x": "Seguir en X", + "people": { + "christopher-smith": { + "jobTitle": "Fundador y CEO, Quantus", + "bio": "Christopher Smith es editor jefe de Quantum Canary y fundador y CEO de Quantus. Emprendedor tecnológico en inteligencia artificial, blockchain y computación cuántica, lleva más de una década construyendo herramientas para sistemas descentralizados. Sus proyectos anteriores incluyen BitMesh, Lunyr y FactoryDAO, y contribuyó a software temprano de Bitcoin y a herramientas de privacidad. Chris es autor del whitepaper de Quantus y presentador del podcast QDay, donde conversa con investigadores y builders sobre computación cuántica, criptografía y el futuro del dinero digital.", + "meta": { + "title": "Christopher Smith | Fundador y CEO, Quantus", + "description": "Christopher Smith es fundador y CEO de Quantus y editor jefe de Quantum Canary. Trabaja en IA, blockchain y criptografía post-cuántica." + } + }, + "joe-mattia": { + "jobTitle": "Cofundador y COO, Quantus", + "bio": "Joseph Mattia es cofundador y COO de Quantus, donde dirige las operaciones y ayuda a convertir la investigación post-cuántica en ejecución de producto y programas comunitarios. Ha representado a Quantus en eventos QDay y copresentó los primeros episodios del podcast QDay, aportando la perspectiva de un operador sobre seguridad blockchain, adopción y coordinación. Joe se centra en las decisiones prácticas que builders, instituciones y tenedores de activos deben tomar antes de que el riesgo cuántico se convierta en una emergencia.", + "meta": { + "title": "Joseph Mattia | Cofundador y COO, Quantus", + "description": "Joseph Mattia es cofundador y COO de Quantus. Lidera operaciones que convierten la investigación post-cuántica en productos, programas y eventos QDay." + } + }, + "jonathan-angle": { + "jobTitle": "Director de comunicaciones, Quantus", + "bio": "Jonathan “Jangle” Angle es director de comunicaciones de Quantus, la blockchain post-cuántica. Con experiencia en seguridad informática, consultoría y DeFi, ha sido clave en la estrategia, el producto y las operaciones de Quantus. Escribe sobre seguridad blockchain, criptografía post-cuántica y DeFi como @defijangle.", + "meta": { + "title": "Jonathan Angle | Director de comunicaciones, Quantus", + "description": "Jonathan Angle dirige la comunicación en Quantus. Con experiencia en seguridad TI, consultoría y DeFi, escribe de criptografía post-cuántica como @defijangle." + } + } + } + }, "community": { "meta": { "title": "Comunidad | Únase al futuro Quantus", diff --git a/website/src/i18n/hi-IN.json b/website/src/i18n/hi-IN.json index 3948ef37..fbb9df94 100644 --- a/website/src/i18n/hi-IN.json +++ b/website/src/i18n/hi-IN.json @@ -509,6 +509,36 @@ "cta": "हमें एक संदेश भेजें →" } }, + "team": { + "back_to_about": "हमारे बारे में वापस जाएं", + "follow_on_x": "X पर फ़ॉलो करें", + "people": { + "christopher-smith": { + "jobTitle": "संस्थापक और CEO, Quantus", + "bio": "Christopher Smith Quantum Canary के प्रधान संपादक तथा Quantus के संस्थापक और CEO हैं। कृत्रिम बुद्धिमत्ता, ब्लॉकचेन और क्वांटम कंप्यूटिंग में काम करने वाले प्रौद्योगिकी उद्यमी के रूप में उन्होंने एक दशक से अधिक समय विकेंद्रीकृत प्रणालियों के लिए उपकरण बनाने में बिताया है। उनके पहले उद्यमों में BitMesh, Lunyr और FactoryDAO शामिल हैं, और उन्होंने शुरुआती Bitcoin सॉफ़्टवेयर तथा गोपनीयता टूलिंग में योगदान दिया। Chris Quantus श्वेतपत्र के लेखक और QDay पॉडकास्ट के होस्ट हैं, जहाँ वे शोधकर्ताओं और बिल्डर्स के साथ क्वांटम कंप्यूटिंग, क्रिप्टोग्राफी और डिजिटल मुद्रा के भविष्य पर बात करते हैं।", + "meta": { + "title": "Christopher Smith | संस्थापक और CEO, Quantus", + "description": "Christopher Smith Quantus के संस्थापक और CEO तथा Quantum Canary के प्रधान संपादक हैं। वे AI, ब्लॉकचेन और पोस्ट-क्वांटम क्रिप्टोग्राफी पर काम करते हैं।" + } + }, + "joe-mattia": { + "jobTitle": "सह-संस्थापक और COO, Quantus", + "bio": "Joseph Mattia Quantus के सह-संस्थापक और COO हैं, जहाँ वे संचालन का नेतृत्व करते हैं और पोस्ट-क्वांटम शोध को उत्पाद निष्पादन तथा कम्युनिटी कार्यक्रमों में बदलने में मदद करते हैं। उन्होंने QDay इवेंट्स में Quantus का प्रतिनिधित्व किया है और QDay पॉडकास्ट के शुरुआती एपिसोड सह-होस्ट किए हैं, ब्लॉकचेन सुरक्षा, अपनाने और समन्वय पर एक ऑपरेटर का दृष्टिकोण देते हुए। Joe उन व्यावहारिक विकल्पों पर ध्यान देते हैं जो बिल्डर्स, संस्थानों और परिसंपत्ति धारकों को क्वांटम जोखिम आपात बनने से पहले लेने चाहिए।", + "meta": { + "title": "Joseph Mattia | सह-संस्थापक और COO, Quantus", + "description": "Joseph Mattia Quantus के सह-संस्थापक और COO हैं। वे पोस्ट-क्वांटम शोध को उत्पादों, कम्युनिटी कार्यक्रमों और QDay इवेंट्स में बदलने का संचालन करते हैं।" + } + }, + "jonathan-angle": { + "jobTitle": "संचार निदेशक, Quantus", + "bio": "Jonathan “Jangle” Angle पोस्ट-क्वांटम ब्लॉकचेन Quantus में संचार निदेशक हैं। IT सुरक्षा, कंसल्टिंग और DeFi की पृष्ठभूमि के साथ वे Quantus की रणनीति, उत्पाद और संचालन में अहम रहे हैं। वे ब्लॉकचेन सुरक्षा, पोस्ट-क्वांटम क्रिप्टोग्राफी और DeFi पर @defijangle के रूप में लिखते हैं।", + "meta": { + "title": "Jonathan Angle | संचार निदेशक, Quantus", + "description": "Jonathan Angle Quantus में संचार का नेतृत्व करते हैं। IT सुरक्षा, कंसल्टिंग और DeFi के साथ वे @defijangle पर पोस्ट-क्वांटम क्रिप्टोग्राफी लिखते हैं।" + } + } + } + }, "community": { "meta": { "title": "समुदाय | Quantus के भविष्य से जुड़ें", diff --git a/website/src/i18n/id-ID.json b/website/src/i18n/id-ID.json index 567b4d72..ac0d790a 100644 --- a/website/src/i18n/id-ID.json +++ b/website/src/i18n/id-ID.json @@ -509,6 +509,36 @@ "cta": "KIRIM PESAN KEPADA KAMI →" } }, + "team": { + "back_to_about": "Kembali ke Tentang", + "follow_on_x": "Ikuti di X", + "people": { + "christopher-smith": { + "jobTitle": "Pendiri dan CEO, Quantus", + "bio": "Christopher Smith adalah pemimpin redaksi Quantum Canary serta pendiri dan CEO Quantus. Sebagai wirausahawan teknologi di bidang kecerdasan buatan, blockchain, dan komputasi kuantum, ia lebih dari satu dekade membangun perangkat untuk sistem terdesentralisasi. Usaha sebelumnya mencakup BitMesh, Lunyr, dan FactoryDAO, dan ia berkontribusi pada perangkat lunak Bitcoin awal serta perkakas privasi. Chris adalah penulis whitepaper Quantus dan pembawa acara podcast QDay, di mana ia berbicara dengan peneliti dan builder tentang komputasi kuantum, kriptografi, dan masa depan uang digital.", + "meta": { + "title": "Christopher Smith | Pendiri dan CEO, Quantus", + "description": "Christopher Smith adalah pendiri dan CEO Quantus serta pemimpin redaksi Quantum Canary. Ia berkarya di AI, blockchain, dan kriptografi pasca-kuantum." + } + }, + "joe-mattia": { + "jobTitle": "Pendiri bersama dan COO, Quantus", + "bio": "Joseph Mattia adalah pendiri bersama dan COO Quantus, tempat ia memimpin operasi dan membantu mengubah riset pasca-kuantum menjadi eksekusi produk serta program komunitas. Ia telah mewakili Quantus di acara QDay dan menjadi co-host episode awal podcast QDay, membawa perspektif operator pada keamanan blockchain, adopsi, dan koordinasi. Joe berfokus pada pilihan praktis yang harus diambil builder, institusi, dan pemegang aset sebelum risiko kuantum menjadi keadaan darurat.", + "meta": { + "title": "Joseph Mattia | Pendiri bersama dan COO, Quantus", + "description": "Joseph Mattia adalah pendiri bersama dan COO Quantus. Ia memimpin operasi yang mengubah riset pasca-kuantum menjadi produk, program komunitas, dan acara QDay." + } + }, + "jonathan-angle": { + "jobTitle": "Direktur Komunikasi, Quantus", + "bio": "Jonathan “Jangle” Angle adalah Direktur Komunikasi di Quantus, blockchain pasca-kuantum. Dengan latar belakang keamanan TI, konsultasi, dan DeFi, ia berperan penting dalam strategi, produk, dan operasi Quantus. Ia menulis tentang keamanan blockchain, kriptografi pasca-kuantum, dan DeFi sebagai @defijangle.", + "meta": { + "title": "Jonathan Angle | Direktur Komunikasi, Quantus", + "description": "Jonathan Angle memimpin komunikasi Quantus. Berlatar keamanan TI, konsultasi, dan DeFi, ia menulis kriptografi pasca-kuantum sebagai @defijangle." + } + } + } + }, "community": { "meta": { "title": "Komunitas | Bergabung dengan Quantus", diff --git a/website/src/i18n/ja-JP.json b/website/src/i18n/ja-JP.json index 97778b83..4572c018 100644 --- a/website/src/i18n/ja-JP.json +++ b/website/src/i18n/ja-JP.json @@ -509,6 +509,36 @@ "cta": "メッセージを送る →" } }, + "team": { + "back_to_about": "概要に戻る", + "follow_on_x": "Xでフォロー", + "people": { + "christopher-smith": { + "jobTitle": "Quantus創業者兼CEO", + "bio": "Christopher SmithはQuantum Canaryの編集長であり、Quantusの創業者兼CEOです。人工知能、ブロックチェーン、量子コンピューティングに取り組むテクノロジー起業家として、10年以上にわたり分散型システム向けのツールを構築してきました。以前の事業にはBitMesh、Lunyr、FactoryDAOがあり、初期のBitcoinソフトウェアやプライバシーツールにも貢献しています。ChrisはQuantusホワイトペーパーの著者であり、QDayポッドキャストのホストとして、研究者やビルダーとともに量子コンピューティング、暗号、デジタルマネーの未来について語っています。", + "meta": { + "title": "Christopher Smith | Quantus創業者兼CEO", + "description": "Christopher SmithはQuantusの創業者兼CEOであり、Quantum Canaryの編集長。AI、ブロックチェーン、耐量子計算機暗号の分野で活動しています。" + } + }, + "joe-mattia": { + "jobTitle": "Quantus共同創業者兼COO", + "bio": "Joseph MattiaはQuantusの共同創業者兼COOとして、オペレーションを率い、耐量子研究をプロダクト実行とコミュニティプログラムに結びつける役割を担っています。QDayイベントでQuantusを代表し、QDayポッドキャストの初期エピソードを共同ホストするなど、ブロックチェーンのセキュリティ、普及、調整についてオペレーターの視点を提供しています。Joeが注力するのは、量子リスクが緊急事態になる前に、ビルダー、機関、資産保有者が下すべき実務上の判断です。", + "meta": { + "title": "Joseph Mattia | Quantus共同創業者兼COO", + "description": "Joseph MattiaはQuantusの共同創業者兼COO。耐量子研究をプロダクト、コミュニティプログラム、QDayイベントへとつなげる運営を率いています。" + } + }, + "jonathan-angle": { + "jobTitle": "Quantusコミュニケーションディレクター", + "bio": "Jonathan “Jangle” Angleは、ポスト量子ブロックチェーンQuantusのコミュニケーションディレクターです。ITセキュリティ、コンサルティング、DeFiのバックグラウンドを持ち、Quantusの戦略、プロダクト、オペレーションに深く関わってきました。ブロックチェーンセキュリティ、耐量子計算機暗号、DeFiについて@defijangleとして発信しています。", + "meta": { + "title": "Jonathan Angle | Quantusコミュニケーション責任者", + "description": "Jonathan AngleはQuantusのコミュニケーションを統括。ITセキュリティ、コンサルティング、DeFiの経験を活かし、@defijangleとして耐量子暗号について発信しています。" + } + } + } + }, "community": { "meta": { "title": "コミュニティ | Quantusの量子セキュアな未来へ", diff --git a/website/src/i18n/ko-KR.json b/website/src/i18n/ko-KR.json index 41fec017..bcaa1758 100644 --- a/website/src/i18n/ko-KR.json +++ b/website/src/i18n/ko-KR.json @@ -509,6 +509,36 @@ "cta": "메시지 보내기 →" } }, + "team": { + "back_to_about": "소개로 돌아가기", + "follow_on_x": "X에서 팔로우", + "people": { + "christopher-smith": { + "jobTitle": "Quantus 창업자 겸 CEO", + "bio": "Christopher Smith는 Quantum Canary의 편집장이자 Quantus의 창업자 겸 CEO입니다. 인공지능, 블록체인, 양자 컴퓨팅을 아우르는 기술 기업가로서 10년 이상 탈중앙 시스템을 위한 도구를 만들어 왔습니다. 이전 벤처로는 BitMesh, Lunyr, FactoryDAO가 있으며, 초기 Bitcoin 소프트웨어와 프라이버시 툴링에도 기여했습니다. Chris는 Quantus 백서의 저자이자 QDay 팟캐스트 진행자로, 연구자 및 빌더들과 양자 컴퓨팅, 암호, 디지털 화폐의 미래를 이야기합니다.", + "meta": { + "title": "Christopher Smith | Quantus 창업자 겸 CEO", + "description": "Christopher Smith는 Quantus 창업자 겸 CEO이자 Quantum Canary 편집장으로, AI·블록체인·양자 내성 암호 분야에서 활동합니다." + } + }, + "joe-mattia": { + "jobTitle": "Quantus 공동창업자 겸 COO", + "bio": "Joseph Mattia는 Quantus의 공동창업자 겸 COO로, 운영을 이끌며 양자 내성 연구를 제품 실행과 커뮤니티 프로그램으로 연결합니다. QDay 행사에서 Quantus를 대표하고 QDay 팟캐스트 초기 에피소드를 공동 진행하며, 블록체인 보안·도입·조율에 운영자의 관점을 더해 왔습니다. Joe는 양자 위험이 비상 사태가 되기 전에 빌더, 기관, 자산 보유자가 내려야 할 실질적 선택에 집중합니다.", + "meta": { + "title": "Joseph Mattia | Quantus 공동창업자 겸 COO", + "description": "Joseph Mattia는 Quantus 공동창업자 겸 COO로, 양자 내성 연구를 제품·커뮤니티 프로그램·QDay 이벤트로 전환하는 운영을 이끕니다." + } + }, + "jonathan-angle": { + "jobTitle": "Quantus 커뮤니케이션 디렉터", + "bio": "Jonathan “Jangle” Angle은 포스트 양자 블록체인 Quantus의 커뮤니케이션 디렉터입니다. IT 보안, 컨설팅, DeFi 배경을 바탕으로 Quantus의 전략, 제품, 운영에 깊이 관여해 왔습니다. 블록체인 보안, 양자 내성 암호, DeFi에 대해 @defijangle로 글을 씁니다.", + "meta": { + "title": "Jonathan Angle | Quantus 커뮤니케이션 디렉터", + "description": "Jonathan Angle은 Quantus의 커뮤니케이션을 이끕니다. IT 보안, 컨설팅, DeFi 배경을 바탕으로 @defijangle로 양자 내성 암호에 대해 글을 씁니다." + } + } + } + }, "community": { "meta": { "title": "커뮤니티 | Quantus 양자 보안 미래에 참여", diff --git a/website/src/i18n/ru-RU.json b/website/src/i18n/ru-RU.json index 0f497791..00c70aea 100644 --- a/website/src/i18n/ru-RU.json +++ b/website/src/i18n/ru-RU.json @@ -509,6 +509,36 @@ "cta": "ОТПРАВИТЬ СООБЩЕНИЕ →" } }, + "team": { + "back_to_about": "Назад к «О нас»", + "follow_on_x": "Подписаться в X", + "people": { + "christopher-smith": { + "jobTitle": "Основатель и CEO, Quantus", + "bio": "Christopher Smith — главный редактор Quantum Canary, основатель и CEO Quantus. Технологический предприниматель в сферах искусственного интеллекта, блокчейна и квантовых вычислений, более десяти лет он создает инструменты для децентрализованных систем. Среди его предыдущих проектов — BitMesh, Lunyr и FactoryDAO; он также участвовал в разработке раннего ПО Bitcoin и инструментов для приватности. Крис — автор whitepaper Quantus и ведущий подкаста QDay, где беседует с исследователями и билдерами о квантовых вычислениях, криптографии и будущем цифровых денег.", + "meta": { + "title": "Christopher Smith | Основатель и CEO Quantus", + "description": "Christopher Smith — основатель и CEO Quantus, главный редактор Quantum Canary. Работает на стыке ИИ, блокчейна и постквантовой криптографии." + } + }, + "joe-mattia": { + "jobTitle": "Сооснователь и COO, Quantus", + "bio": "Joseph Mattia — сооснователь и COO Quantus: он руководит операциями и помогает превращать постквантовые исследования в продуктовую реализацию и комьюнити-программы. Он представлял Quantus на мероприятиях QDay и был соведущим ранних выпусков подкаста QDay, привнося взгляд оператора на безопасность блокчейна, внедрение и координацию. Джо сосредоточен на практических решениях, которые билдеры, институты и держатели активов должны принять до того, как квантовый риск станет чрезвычайной ситуацией.", + "meta": { + "title": "Joseph Mattia | Сооснователь и COO Quantus", + "description": "Joseph Mattia — сооснователь и COO Quantus. Он руководит операциями, превращая постквантовые исследования в продукты, комьюнити-программы и мероприятия QDay." + } + }, + "jonathan-angle": { + "jobTitle": "Директор по коммуникациям, Quantus", + "bio": "Jonathan «Jangle» Angle — директор по коммуникациям Quantus, постквантового блокчейна. С опытом в ИТ-безопасности, консалтинге и DeFi он сыграл важную роль в стратегии, продукте и операциях Quantus. Он пишет о безопасности блокчейна, постквантовой криптографии и DeFi как @defijangle.", + "meta": { + "title": "Jonathan Angle | Директор по коммуникациям Quantus", + "description": "Jonathan Angle руководит коммуникациями Quantus. С опытом в ИТ-безопасности, консалтинге и DeFi он пишет о постквантовой криптографии как @defijangle." + } + } + } + }, "community": { "meta": { "title": "Сообщество | Присоединяйтесь к Quantus", diff --git a/website/src/i18n/zh-CN.json b/website/src/i18n/zh-CN.json index ad7771d2..a7ef0b9f 100644 --- a/website/src/i18n/zh-CN.json +++ b/website/src/i18n/zh-CN.json @@ -509,6 +509,36 @@ "cta": "给我们发送消息 →" } }, + "team": { + "back_to_about": "返回关于我们", + "follow_on_x": "在 X 上关注", + "people": { + "christopher-smith": { + "jobTitle": "Quantus 创始人兼首席执行官", + "bio": "Christopher Smith 是 Quantum Canary 的主编,也是 Quantus 的创始人兼首席执行官。作为一名横跨人工智能、区块链和量子计算的科技创业者,他十多年来一直在为去中心化系统构建工具。他此前创办过 BitMesh、Lunyr 和 FactoryDAO,并参与过早期 Bitcoin 软件与隐私工具的开发。Chris 是 Quantus 白皮书的作者,也是 QDay 播客的主持人,与研究者和建设者探讨量子计算、密码学以及数字货币的未来。", + "meta": { + "title": "Christopher Smith | Quantus 创始人兼首席执行官", + "description": "Christopher Smith 是 Quantus 创始人兼首席执行官,也是 Quantum Canary 主编,深耕人工智能、区块链与后量子密码学。" + } + }, + "joe-mattia": { + "jobTitle": "Quantus 联合创始人兼首席运营官", + "bio": "Joseph Mattia 是 Quantus 的联合创始人兼首席运营官,负责运营,并将后量子研究转化为产品落地与社区项目。他曾代表 Quantus 出席 QDay 活动,并共同主持过 QDay 播客的早期节目,从运营者的视角讨论区块链安全、采用与协作。Joe 关注建设者、机构和资产持有人在量子风险演变成紧急事态之前必须做出的实际选择。", + "meta": { + "title": "Joseph Mattia | Quantus 联合创始人兼首席运营官", + "description": "Joseph Mattia 是 Quantus 联合创始人兼首席运营官,负责将后量子研究转化为产品、社区项目与 QDay 活动,推动落地执行。" + } + }, + "jonathan-angle": { + "jobTitle": "Quantus 传播总监", + "bio": "Jonathan “Jangle” Angle 是后量子区块链 Quantus 的传播总监。他拥有 IT 安全、咨询和 DeFi 背景,深度参与 Quantus 的战略、产品与运营。他以 @defijangle 的身份撰写区块链安全、后量子密码学和 DeFi 相关内容。", + "meta": { + "title": "Jonathan Angle | Quantus 传播总监", + "description": "Jonathan Angle 负责 Quantus 传播工作。他拥有 IT 安全、咨询与 DeFi 背景,以 @defijangle 撰写后量子密码学相关内容。" + } + } + } + }, "community": { "meta": { "title": "社区 | 加入 Quantus 量子安全的未来", diff --git a/website/src/pages/[lang]/about.astro b/website/src/pages/[lang]/about.astro index dd8a4da8..84347a40 100644 --- a/website/src/pages/[lang]/about.astro +++ b/website/src/pages/[lang]/about.astro @@ -13,6 +13,7 @@ import { organizationJsonLd, websiteJsonLd, } from "@/constants/default-jsonld"; +import { getAllPersonJsonLd } from "@/constants/person-jsonld"; import HeroBanner from "@/components/features/about/HeroBanner.astro"; import MissionSection from "@/components/features/about/MissionSection.astro"; import TeamSection from "@/components/features/about/TeamSection.astro"; @@ -34,7 +35,13 @@ const metadata = createMetadata({ const jsonLd = JsonLdGraph({ "@context": "https://schema.org", - "@graph": [websiteJsonLd, organizationJsonLd, iosAppJsonLd, androidAppJsonLd], + "@graph": [ + websiteJsonLd, + organizationJsonLd, + ...getAllPersonJsonLd(), + iosAppJsonLd, + androidAppJsonLd, + ], }); --- diff --git a/website/src/pages/[lang]/team/[slug].astro b/website/src/pages/[lang]/team/[slug].astro new file mode 100644 index 00000000..f62a8f8e --- /dev/null +++ b/website/src/pages/[lang]/team/[slug].astro @@ -0,0 +1,18 @@ +--- +import PersonPage from "@/components/features/team/PersonPage.astro"; +import { PERSON_IDS, isPersonId } from "@/constants/people"; +import { PREFIXED_LOCALES } from "@/utils/i18n"; + +export function getStaticPaths() { + return PREFIXED_LOCALES.flatMap((lang) => + PERSON_IDS.map((slug) => ({ params: { lang, slug } })), + ); +} + +const { slug } = Astro.params; +if (!slug || !isPersonId(slug)) { + return Astro.redirect("/404"); +} +--- + + diff --git a/website/src/pages/[lang]/team/index.astro b/website/src/pages/[lang]/team/index.astro new file mode 100644 index 00000000..f4bb7c55 --- /dev/null +++ b/website/src/pages/[lang]/team/index.astro @@ -0,0 +1,10 @@ +--- +import { PREFIXED_LOCALES, getLocaleFromUrl } from "@/utils/i18n"; + +export function getStaticPaths() { + return PREFIXED_LOCALES.map((lang) => ({ params: { lang } })); +} + +const locale = getLocaleFromUrl(Astro.url.pathname); +return Astro.redirect(`/${locale}/about#team`); +--- diff --git a/website/src/pages/[lang]/whitepaper.astro b/website/src/pages/[lang]/whitepaper.astro index 166dff34..091ab333 100644 --- a/website/src/pages/[lang]/whitepaper.astro +++ b/website/src/pages/[lang]/whitepaper.astro @@ -6,8 +6,7 @@ import { createTranslator, PREFIXED_LOCALES, } from "@/utils/i18n"; -import { JsonLdGraph } from "@/utils/build-json-ld"; -import { getWhitepaperJsonLd } from "@/constants/default-jsonld"; +import { getWhitepaperJsonLdGraph } from "@/constants/person-jsonld"; import { createMetadata } from "@/utils/create-metadata"; import WhitepaperHeader from "@/components/features/whitepaper/WhitepaperHeader.astro"; import TableOfContents from "@/components/features/whitepaper/TableOfContents.astro"; @@ -46,10 +45,11 @@ const metadata = createMetadata({ pathname: Astro.url.pathname, }); -const jsonLd = JsonLdGraph({ - "@context": "https://schema.org", - "@graph": [getWhitepaperJsonLd(locale, entry.data.version)], -}); +const jsonLd = getWhitepaperJsonLdGraph( + locale, + entry.data.version, + entry.data.authors, +); const styleVersion = entry.data.version === "0.3.1" ? "v1" : "v2"; --- diff --git a/website/src/pages/[lang]/whitepaper/[version].astro b/website/src/pages/[lang]/whitepaper/[version].astro index bea56c45..9f035a5d 100644 --- a/website/src/pages/[lang]/whitepaper/[version].astro +++ b/website/src/pages/[lang]/whitepaper/[version].astro @@ -6,8 +6,7 @@ import { createTranslator, PREFIXED_LOCALES, } from "@/utils/i18n"; -import { JsonLdGraph } from "@/utils/build-json-ld"; -import { getWhitepaperJsonLd } from "@/constants/default-jsonld"; +import { getWhitepaperJsonLdGraph } from "@/constants/person-jsonld"; import { createMetadata } from "@/utils/create-metadata"; import WhitepaperHeader from "@/components/features/whitepaper/WhitepaperHeader.astro"; import WhitepaperPrintCover from "@/components/features/whitepaper/WhitepaperPrintCover.astro"; @@ -67,10 +66,11 @@ const metadata = createMetadata({ pathname: Astro.url.pathname, }); -const jsonLd = JsonLdGraph({ - "@context": "https://schema.org", - "@graph": [getWhitepaperJsonLd(locale, entry.data.version)], -}); +const jsonLd = getWhitepaperJsonLdGraph( + locale, + entry.data.version, + entry.data.authors, +); const styleVersion = entry.data.version === "0.3.1" ? "v1" : "v2"; --- diff --git a/website/src/pages/about.astro b/website/src/pages/about.astro index 7e94d5af..e016503c 100644 --- a/website/src/pages/about.astro +++ b/website/src/pages/about.astro @@ -9,6 +9,7 @@ import { organizationJsonLd, websiteJsonLd, } from "@/constants/default-jsonld"; +import { getAllPersonJsonLd } from "@/constants/person-jsonld"; import HeroBanner from "@/components/features/about/HeroBanner.astro"; import MissionSection from "@/components/features/about/MissionSection.astro"; import TeamSection from "@/components/features/about/TeamSection.astro"; @@ -26,7 +27,13 @@ const metadata = createMetadata({ const jsonLd = JsonLdGraph({ "@context": "https://schema.org", - "@graph": [websiteJsonLd, organizationJsonLd, iosAppJsonLd, androidAppJsonLd], + "@graph": [ + websiteJsonLd, + organizationJsonLd, + ...getAllPersonJsonLd(), + iosAppJsonLd, + androidAppJsonLd, + ], }); --- diff --git a/website/src/pages/team/[slug].astro b/website/src/pages/team/[slug].astro new file mode 100644 index 00000000..7b501fb8 --- /dev/null +++ b/website/src/pages/team/[slug].astro @@ -0,0 +1,15 @@ +--- +import PersonPage from "@/components/features/team/PersonPage.astro"; +import { PERSON_IDS, isPersonId } from "@/constants/people"; + +export function getStaticPaths() { + return PERSON_IDS.map((slug) => ({ params: { slug } })); +} + +const { slug } = Astro.params; +if (!slug || !isPersonId(slug)) { + return Astro.redirect("/404"); +} +--- + + diff --git a/website/src/pages/team/index.astro b/website/src/pages/team/index.astro new file mode 100644 index 00000000..c368243a --- /dev/null +++ b/website/src/pages/team/index.astro @@ -0,0 +1,3 @@ +--- +return Astro.redirect("/about#team"); +--- diff --git a/website/src/pages/whitepaper.astro b/website/src/pages/whitepaper.astro index 9214099c..35c5220f 100644 --- a/website/src/pages/whitepaper.astro +++ b/website/src/pages/whitepaper.astro @@ -2,8 +2,7 @@ import { render } from "astro:content"; import Layout from "@/components/layout/Layout.astro"; import { getLocaleFromUrl, createTranslator } from "@/utils/i18n"; -import { JsonLdGraph } from "@/utils/build-json-ld"; -import { getWhitepaperJsonLd } from "@/constants/default-jsonld"; +import { getWhitepaperJsonLdGraph } from "@/constants/person-jsonld"; import { createMetadata } from "@/utils/create-metadata"; import WhitepaperHeader from "@/components/features/whitepaper/WhitepaperHeader.astro"; import TableOfContents from "@/components/features/whitepaper/TableOfContents.astro"; @@ -38,10 +37,11 @@ const metadata = createMetadata({ pathname: Astro.url.pathname, }); -const jsonLd = JsonLdGraph({ - "@context": "https://schema.org", - "@graph": [getWhitepaperJsonLd(locale, entry.data.version)], -}); +const jsonLd = getWhitepaperJsonLdGraph( + locale, + entry.data.version, + entry.data.authors, +); const styleVersion = entry.data.version === "0.3.1" ? "v1" : "v2"; --- diff --git a/website/src/pages/whitepaper/[version].astro b/website/src/pages/whitepaper/[version].astro index d41d942a..70a80064 100644 --- a/website/src/pages/whitepaper/[version].astro +++ b/website/src/pages/whitepaper/[version].astro @@ -2,8 +2,7 @@ import { render } from "astro:content"; import Layout from "@/components/layout/Layout.astro"; import { getLocaleFromUrl, createTranslator } from "@/utils/i18n"; -import { JsonLdGraph } from "@/utils/build-json-ld"; -import { getWhitepaperJsonLd } from "@/constants/default-jsonld"; +import { getWhitepaperJsonLdGraph } from "@/constants/person-jsonld"; import { createMetadata } from "@/utils/create-metadata"; import WhitepaperHeader from "@/components/features/whitepaper/WhitepaperHeader.astro"; import WhitepaperPrintCover from "@/components/features/whitepaper/WhitepaperPrintCover.astro"; @@ -51,10 +50,11 @@ const metadata = createMetadata({ pathname: Astro.url.pathname, }); -const jsonLd = JsonLdGraph({ - "@context": "https://schema.org", - "@graph": [getWhitepaperJsonLd(locale, entry.data.version)], -}); +const jsonLd = getWhitepaperJsonLdGraph( + locale, + entry.data.version, + entry.data.authors, +); const styleVersion = entry.data.version === "0.3.1" ? "v1" : "v2"; ---