From d4a2d0aef8d264a577e5c08016eef4f470e844d0 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 2 Nov 2026 19:43:03 +0000 Subject: [PATCH] Name the person who runs DebateOwl on /about and /terms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A directory put our listing on hold until the site says who runs it. /about and /terms (EN, ES, HU) now name Ádám Gáborjáni as operator, with Pi-Stack as the name he publishes under. The Organization JSON-LD swaps parentOrganization: Pi-Stack for a founder Person, the footer copyright names him, and llms.txt gains the same fact. check-site now requires the founder and rejects parentOrganization or legalName. Co-Authored-By: Claude Opus 5.5 --- public/llms.txt | 3 ++- scripts/check-site.mjs | 14 ++++++++------ scripts/generate_seo_content.py | 4 +++- src/config/site.json | 11 ++++++++--- src/lib/seo/pages.ts | 14 ++++++++------ src/locales/en.json | 14 ++++++++------ src/locales/es.json | 14 ++++++++------ src/locales/hu.json | 14 ++++++++------ src/pages/AboutPage.tsx | 13 +++++++++++-- src/pages/PressPage.tsx | 3 +-- src/pages/TermsPage.tsx | 11 ++++++++++- 11 files changed, 75 insertions(+), 40 deletions(-) diff --git a/public/llms.txt b/public/llms.txt index 8fd9371c..0849c9dd 100644 --- a/public/llms.txt +++ b/public/llms.txt @@ -7,6 +7,7 @@ DebateOwl runs at https://debateowl.com/. It is a separate product from debatela ## Key facts (as of October 2026) - Who it is for: students, competitive debaters and their coaches. +- Who runs it: Ádám Gáborjáni, an independent student developer in Hungary. Pi-Stack (pi-stack.org) is the name he publishes his projects under, and Programcode is his GitHub username. Contact: hello@debateowl.com. - 8 prep modes: Case generator, Brainstorm, Factoids, Flowchart, Case attacker, Ask coach, Crossfire and Sparring. Plus 3 utilities: Library, Debate timer and History. - Case format: A DebateOwl case is written the way school debaters prepare: an opening, two to four arguments each with an explanation, evidence and why it matters, "If they say… we answer…" replies, a closing line and the sources it used. - Second speech (R2): no new arguments; about two minutes reinforcing our arguments, then about four minutes of "If they say X, we answer Y" replies. @@ -21,7 +22,7 @@ DebateOwl runs at https://debateowl.com/. It is a separate product from debatela - [Home](https://debateowl.com/): what DebateOwl is, the 8 prep modes, pricing and FAQ - [Pricing](https://debateowl.com/debateowl-pricing): trial, Pro and what each includes -- [About](https://debateowl.com/about): what DebateOwl is, who makes it and its former name +- [About](https://debateowl.com/about): what DebateOwl is, who runs it and its former name - [Contact](https://debateowl.com/contact): email hello@debateowl.com for support and feedback, privacy@debateowl.com for privacy and data requests - [Press kit and facts](https://debateowl.com/press): a one-sentence definition, former name, maker, languages, pricing, logo downloads and what DebateOwl is not - [Full text](https://debateowl.com/llms-full.txt): this file plus the plain text of the home page, About, Which AI is best for debate? and the press kit diff --git a/scripts/check-site.mjs b/scripts/check-site.mjs index 51d2c66c..98e60ae3 100644 --- a/scripts/check-site.mjs +++ b/scripts/check-site.mjs @@ -8,7 +8,7 @@ // references do not resolve or whose WebSite and SoftwareApplication are not // named for the product, or a page whose publisher or about names an @id the // home page does not define, or a home-page Organization not named for the -// product or without its logo and parent; +// product or without its logo and founder; // - an indexed page without the favicon and 192px icon links, or whose meta // author is not the organization; // - two indexed pages with the same , which then compete for one query; @@ -174,14 +174,16 @@ function checkStructuredData(where, data, body) { const sameAs = organization.sameAs; // sameAs is optional (site.json lists only profiles that spell the name "DebateOwl"), but when present it is a non-empty list of https URLs. if (sameAs !== undefined && (!Array.isArray(sameAs) || !sameAs.length || sameAs.some((url) => !url.startsWith('https://')))) report(where, 'Organization.sameAs is not a list of https URLs'); - // One name for one entity: the Organization on this domain is the product, and the company - // that builds it is its parent, never a sameAs. + // One name for one entity: the Organization on this domain is the product, and the person + // who runs it is its founder, never a sameAs. if (organization.name !== SITE.product) report(where, `Organization.name is "${organization.name}", not the product name "${SITE.product}"`); const logo = organization.logo ?? {}; if (logo['@type'] !== 'ImageObject' || !logo.url?.startsWith(`${SITE_ORIGIN}/`) || !logo.width || !logo.height) report(where, 'Organization.logo is not an ImageObject on this site with a width and height'); - const parent = organization.parentOrganization ?? {}; - if (!parent.name || !parent.url) report(where, 'Organization.parentOrganization has no name and url'); - else if (sameAs?.includes(parent.url)) report(where, `Organization.sameAs lists the parent ${parent.url}`); + const founder = organization.founder ?? {}; + if (founder['@type'] !== 'Person' || !founder.name || !founder.url) report(where, 'Organization.founder is not a Person with a name and url'); + else if (sameAs?.includes(founder.url)) report(where, `Organization.sameAs lists the founder ${founder.url}`); + // Pi-Stack is the name the founder publishes under, not a company: no parent organization or legal name. + if (organization.parentOrganization || organization.legalName) report(where, 'Organization has a parentOrganization or legalName'); const alternates = byType('WebSite').alternateName ?? []; if (!alternates.some((name) => name !== SITE.product)) report(where, 'WebSite.alternateName only repeats the name'); } diff --git a/scripts/generate_seo_content.py b/scripts/generate_seo_content.py index 80f94629..618f1764 100644 --- a/scripts/generate_seo_content.py +++ b/scripts/generate_seo_content.py @@ -22,6 +22,7 @@ BRAND = SITE["brand"] PRODUCT = SITE["product"] ORGANIZATION = SITE["organization"] +OPERATOR = ORGANIZATION["operator"] FORMERLY = SITE["formerly"] PRICING = SITE["pricing"] # Prices and plan facts are stated "as of" this month; move it when they are rechecked. @@ -872,6 +873,7 @@ def llms_txt(): ## Key facts (as of {FACTS_AS_OF}) - Who it is for: students, competitive debaters and their coaches. +- Who runs it: {OPERATOR["name"]}, an independent student developer in {OPERATOR["country"]}. Pi-Stack ({OPERATOR["publishesAs"]["url"].removeprefix("https://").rstrip("/")}) is the name he publishes his projects under, and {OPERATOR["github"].rsplit("/", 1)[1]} is his GitHub username. Contact: {SITE["contactEmail"]}. - {len(PREP_MODES)} prep modes: {names(PREP_MODES)}. Plus {len(UTILITIES)} utilities: {names(UTILITIES)}. - Case format: {CASE_FORMAT} - {SITE["secondSpeech"]} @@ -886,7 +888,7 @@ def llms_txt(): - [Home]({BASE}/): what {PRODUCT} is, the {len(PREP_MODES)} prep modes, pricing and FAQ - [Pricing]({page_url("debateowl-pricing")}): trial, Pro and what each includes -- [About]({BASE}/about): what {PRODUCT} is, who makes it and its former name +- [About]({BASE}/about): what {PRODUCT} is, who runs it and its former name - [Contact]({BASE}/contact): email {SITE["contactEmail"]} for support and feedback, {SITE["privacyEmail"]} for privacy and data requests - [Press kit and facts]({BASE}/press): a one-sentence definition, former name, maker, languages, pricing, logo downloads and what {PRODUCT} is not - [Full text]({BASE}/llms-full.txt): this file plus the plain text of the home page, About, Which AI is best for debate? and the press kit diff --git a/src/config/site.json b/src/config/site.json index 8992e7cc..bc0590aa 100644 --- a/src/config/site.json +++ b/src/config/site.json @@ -20,9 +20,14 @@ "description": "DebateOwl (formerly DebateLab at debate.pi-stack.org) is an AI debate prep and practice app for students and competitive debaters.", "disambiguatingDescription": "DebateOwl is an AI debate prep and practice app for students, not a sports or computer-vision product.", "sameAs": ["https://github.com/Programcode/DebateOwl"], - "parent": { - "name": "Pi-Stack", - "url": "https://pi-stack.org/" + "operator": { + "name": "Ádám Gáborjáni", + "country": "Hungary", + "github": "https://github.com/Programcode", + "publishesAs": { + "name": "Pi-Stack", + "url": "https://pi-stack.org/" + } } }, "factsCheckedOn": "2026-10-20", diff --git a/src/lib/seo/pages.ts b/src/lib/seo/pages.ts index 1a1d2672..4fb6d375 100644 --- a/src/lib/seo/pages.ts +++ b/src/lib/seo/pages.ts @@ -11,13 +11,15 @@ export const ORGANIZATION_ID = `${SITE_ORIGIN}/#organization`; /** * The Organization behind the site, named for the product so search engines - * see one name for one entity. Pi-Stack, which builds it, is its parent, not a - * sameAs: a sameAs profile is the same entity elsewhere. site.json lists only - * profiles that spell the name "DebateOwl" and that DebateOwl itself runs; with - * none, the node has no sameAs. /press, the fact sheet, is its subjectOf. + * see one name for one entity. Its founder is the person who runs it; Pi-Stack + * is only the name he publishes under, not a company, so it appears as his URL + * and never as a parent organization or legal name. A sameAs profile is the same + * entity elsewhere: site.json lists only profiles that spell the name "DebateOwl" + * and that DebateOwl itself runs; with none, the node has no sameAs. /press, the + * fact sheet, is its subjectOf. */ export function organizationNode() { - const { name, logo, description, disambiguatingDescription, sameAs, parent } = site.organization; + const { name, logo, description, disambiguatingDescription, sameAs, operator } = site.organization; return { '@type': 'Organization', '@id': ORGANIZATION_ID, @@ -29,7 +31,7 @@ export function organizationNode() { disambiguatingDescription, email: site.contactEmail, contactPoint: { '@type': 'ContactPoint', contactType: 'customer support', email: site.contactEmail, availableLanguage: ['en', 'hu', 'es'] }, - parentOrganization: { '@type': 'Organization', '@id': `${parent.url}#organization`, name: parent.name, url: parent.url }, + founder: { '@type': 'Person', name: operator.name, url: operator.publishesAs.url, sameAs: [operator.github] }, ...(sameAs.length ? { sameAs } : {}), subjectOf: { '@type': 'WebPage', '@id': `${SITE_ORIGIN}/press#webpage`, url: `${SITE_ORIGIN}/press`, name: PAGE_HEADS['/press'].title }, }; diff --git a/src/locales/en.json b/src/locales/en.json index 0a5c214b..a75bf958 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -883,7 +883,7 @@ "about": "About", "contact": "Contact", "press": "Press kit", - "copyright": "© 2026 Pi-Stack. All rights reserved.", + "copyright": "© 2026 Ádám Gáborjáni. All rights reserved.", "formerly": "{{product}}, formerly DebateLab.", "navLabel": "Footer", "pricingGuide": "Pricing details", @@ -1895,8 +1895,8 @@ "question": "What is {{product}}?", "answer": "<home>{{product}}</home> is an AI debate prep and practice app for students and competitive debaters. It helps you write a case, find the weak points in an argument, research evidence with citations and practice timed rounds against an AI opponent.", "notThis": "{{product}} is a debate app for students, not a sports or computer-vision product. The <press>press kit</press> has the short facts and the logo.", - "makerHeading": "Who makes it", - "maker": "{{product}} is built by a student developer and made by <pistack>Pi-Stack</pistack>.", + "makerHeading": "Who runs {{product}}", + "maker": "{{product}} is run by Ádám Gáborjáni, an independent student developer in Hungary. Pi-Stack (<pistack>pi-stack.org</pistack>) is the name he publishes his projects under, and <github>Programcode</github> is his GitHub username. Contact: <email>{{email}}</email>.", "nameHeading": "The name", "name": "{{product}} was called DebateLab, at debate.pi-stack.org, until {{date}}.", "pricingHeading": "Pricing", @@ -1916,7 +1916,7 @@ "formerlyLabel": "Former name", "formerly": "{{name}}, at {{host}}, renamed on {{date}}", "makerLabel": "Maker", - "maker": "Adam (<github>Programcode</github> on GitHub), a student developer in Hungary, published by <pistack>Pi-Stack</pistack>", + "maker": "Ádám Gáborjáni (<github>Programcode</github> on GitHub), an independent student developer in Hungary, who publishes his projects as Pi-Stack (<pistack>pi-stack.org</pistack>)", "launchedLabel": "Launched", "launched": "2026, under the name {{name}}", "languagesLabel": "Languages", @@ -1944,7 +1944,9 @@ "termsPage": { "title": "Terms of Service", "lastUpdated": "Last updated", - "date": "October 28, 2026", + "date": "November 2, 2026", + "operatorLabel": "Operator", + "operator": "{{product}} is operated by Ádám Gáborjáni, Hungary, publishing as Pi-Stack (<pistack>pi-stack.org</pistack>). Contact: <contact>{{contactEmail}}</contact>.", "s1": "Acceptance of Terms", "p1": "By using DebateOwl, you agree to these terms. If you do not agree, do not use the service.", "s2": "Service Description", @@ -2733,7 +2735,7 @@ }, "about": { "title": "About {{product}} | {{brand}}", - "description": "{{product}} is an AI debate prep and practice app for students and competitive debaters, built by a student developer and made by Pi-Stack." + "description": "{{product}} is an AI debate prep and practice app for students and competitive debaters, run by Ádám Gáborjáni, an independent student developer in Hungary." }, "contact": { "title": "Contact | {{brand}}", diff --git a/src/locales/es.json b/src/locales/es.json index 984c0ca5..3baf7c1e 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -883,7 +883,7 @@ "about": "Acerca de", "contact": "Contacto", "press": "Kit de prensa", - "copyright": "© 2026 Pi-Stack. Todos los derechos reservados.", + "copyright": "© 2026 Ádám Gáborjáni. Todos los derechos reservados.", "formerly": "{{product}}, antes DebateLab.", "navLabel": "Pie de página", "pricingGuide": "Detalles de precios", @@ -1895,8 +1895,8 @@ "question": "¿Qué es {{product}}?", "answer": "<home>{{product}}</home> es una app de preparación y práctica de debate con IA para estudiantes y debatientes de competición. Te ayuda a escribir un caso, encontrar los puntos débiles de un argumento, buscar evidencia con citas y practicar rondas cronometradas contra un oponente de IA.", "notThis": "{{product}} es una app de debate para estudiantes, no un producto de deportes ni de visión por computadora. El <press>kit de prensa</press> reúne los datos básicos y el logotipo.", - "makerHeading": "Quién lo hace", - "maker": "{{product}} lo desarrolla una persona estudiante y lo publica <pistack>Pi-Stack</pistack>.", + "makerHeading": "Quién gestiona {{product}}", + "maker": "{{product}} lo gestiona Ádám Gáborjáni, un estudiante y desarrollador independiente de Hungría. Pi-Stack (<pistack>pi-stack.org</pistack>) es el nombre con el que publica sus proyectos, y <github>Programcode</github> es su nombre de usuario en GitHub. Contacto: <email>{{email}}</email>.", "nameHeading": "El nombre", "name": "{{product}} se llamaba DebateLab, en debate.pi-stack.org, hasta el {{date}}.", "pricingHeading": "Precios", @@ -1916,7 +1916,7 @@ "formerlyLabel": "Nombre anterior", "formerly": "{{name}}, en {{host}}, renombrado el {{date}}", "makerLabel": "Creador", - "maker": "Adam (<github>Programcode</github> en GitHub), estudiante y desarrollador en Hungría; lo publica <pistack>Pi-Stack</pistack>", + "maker": "Ádám Gáborjáni (<github>Programcode</github> en GitHub), estudiante y desarrollador independiente en Hungría, que publica sus proyectos como Pi-Stack (<pistack>pi-stack.org</pistack>)", "launchedLabel": "Lanzamiento", "launched": "2026, con el nombre {{name}}", "languagesLabel": "Idiomas", @@ -1944,7 +1944,9 @@ "termsPage": { "title": "Términos de servicio", "lastUpdated": "Última actualización", - "date": "28 de octubre de 2026", + "date": "2 de noviembre de 2026", + "operatorLabel": "Responsable", + "operator": "{{product}} lo gestiona Ádám Gáborjáni, en Hungría, que publica como Pi-Stack (<pistack>pi-stack.org</pistack>). Contacto: <contact>{{contactEmail}}</contact>.", "s1": "Aceptación de términos", "p1": "Al usar DebateOwl, aceptas estos términos. Si no estás de acuerdo, no uses el servicio.", "s2": "Descripción del servicio", @@ -2733,7 +2735,7 @@ }, "about": { "title": "Acerca de {{product}} | {{brand}}", - "description": "{{product}} es una app de preparación y práctica de debate con IA para estudiantes, desarrollada por una persona estudiante y publicada por Pi-Stack." + "description": "{{product}} es una app de preparación y práctica de debate con IA para estudiantes, gestionada por Ádám Gáborjáni, un estudiante y desarrollador independiente de Hungría." }, "contact": { "title": "Contacto | {{brand}}", diff --git a/src/locales/hu.json b/src/locales/hu.json index e89ea7fb..cf01c983 100644 --- a/src/locales/hu.json +++ b/src/locales/hu.json @@ -883,7 +883,7 @@ "about": "Rólunk", "contact": "Kapcsolat", "press": "Sajtóanyag", - "copyright": "© 2026 Pi-Stack. Minden jog fenntartva.", + "copyright": "© 2026 Gáborjáni Ádám. Minden jog fenntartva.", "formerly": "{{product}}, korábban DebateLab.", "navLabel": "Lábléc", "pricingGuide": "Árak részletei", @@ -1895,8 +1895,8 @@ "question": "Mi az a {{product}}?", "answer": "A <home>{{product}}</home> MI-alapú vitafelkészítő és gyakorló alkalmazás diákoknak és versenyzőknek. Segít megírni az esetet, megtalálni egy érvelés gyenge pontjait, hivatkozásokkal ellátott bizonyítékot keresni, és időre gyakorolni egy MI-ellenféllel.", "notThis": "A {{product}} vitaalkalmazás diákoknak, nem sport- vagy gépilátás-termék. A <press>sajtóanyagban</press> megtalálod a rövid adatokat és a logót.", - "makerHeading": "Ki készíti", - "maker": "A {{product}} alkalmazást egy diák fejlesztő építi, és a <pistack>Pi-Stack</pistack> adja ki.", + "makerHeading": "Ki üzemelteti a {{product}}-t", + "maker": "A {{product}}-t Gáborjáni Ádám, egy magyarországi független diákfejlesztő üzemelteti. A Pi-Stack (<pistack>pi-stack.org</pistack>) az a név, amelyen a projektjeit közzéteszi, a <github>Programcode</github> pedig a GitHub-felhasználóneve. Kapcsolat: <email>{{email}}</email>.", "nameHeading": "A név", "name": "A {{product}} neve {{date}}-ig DebateLab volt, a debate.pi-stack.org címen.", "pricingHeading": "Árak", @@ -1916,7 +1916,7 @@ "formerlyLabel": "Korábbi név", "formerly": "{{name}}, a {{host}} címen; átnevezve: {{date}}", "makerLabel": "Készítő", - "maker": "Ádám (a GitHubon <github>Programcode</github>), magyarországi diák fejlesztő; kiadó: <pistack>Pi-Stack</pistack>", + "maker": "Gáborjáni Ádám (a GitHubon <github>Programcode</github>), magyarországi független diákfejlesztő, aki Pi-Stack néven teszi közzé a projektjeit (<pistack>pi-stack.org</pistack>)", "launchedLabel": "Indulás", "launched": "2026, {{name}} néven", "languagesLabel": "Nyelvek", @@ -1944,7 +1944,9 @@ "termsPage": { "title": "Felhasználási feltételek", "lastUpdated": "Utolsó frissítés", - "date": "2026. október 28.", + "date": "2026. november 2.", + "operatorLabel": "Üzemeltető", + "operator": "A {{product}}-t Gáborjáni Ádám, egy magyarországi független diákfejlesztő üzemelteti, aki Pi-Stack néven teszi közzé a projektjeit (<pistack>pi-stack.org</pistack>). Kapcsolat: <contact>{{contactEmail}}</contact>.", "s1": "Feltételek elfogadása", "p1": "A DebateOwl használatával elfogadod ezeket a feltételeket. Ha nem értesz egyet, ne használd a szolgáltatást.", "s2": "Szolgáltatás leírása", @@ -2733,7 +2735,7 @@ }, "about": { "title": "A {{product}} bemutatása | {{brand}}", - "description": "A {{product}} MI-alapú vitafelkészítő és gyakorló alkalmazás diákoknak és versenyzőknek, amelyet egy diák fejlesztő épít, és a Pi-Stack ad ki." + "description": "A {{product}} MI-alapú vitafelkészítő és gyakorló alkalmazás diákoknak és versenyzőknek, amelyet Gáborjáni Ádám, egy magyarországi független diákfejlesztő üzemeltet." }, "contact": { "title": "Kapcsolat | {{brand}}", diff --git a/src/pages/AboutPage.tsx b/src/pages/AboutPage.tsx index 2f921f16..98c0f936 100644 --- a/src/pages/AboutPage.tsx +++ b/src/pages/AboutPage.tsx @@ -12,6 +12,7 @@ export default function AboutPage() { const { t, i18n } = useTranslation(); usePageHead('/about'); const product = site.product; + const { operator } = site.organization; const renamedOn = new Intl.DateTimeFormat(i18n.language, { day: 'numeric', month: 'long', year: 'numeric', timeZone: 'UTC' }) .format(new Date(`${site.formerly.until}T00:00:00Z`)); @@ -30,9 +31,17 @@ export default function AboutPage() { </p> </section> <section> - <h2 className="text-lg font-semibold">{t('aboutPage.makerHeading')}</h2> + <h2 className="text-lg font-semibold">{t('aboutPage.makerHeading', { product })}</h2> <p> - <Trans i18nKey="aboutPage.maker" values={{ product }} components={{ pistack: <a href={site.organization.parent.url} className={linkClass} /> }} /> + <Trans + i18nKey="aboutPage.maker" + values={{ product, email: site.contactEmail }} + components={{ + pistack: <a href={operator.publishesAs.url} className={linkClass} />, + github: <a href={operator.github} className={linkClass} />, + email: <a href={`mailto:${site.contactEmail}`} className={linkClass} />, + }} + /> </p> </section> <section> diff --git a/src/pages/PressPage.tsx b/src/pages/PressPage.tsx index 406ff86c..48cd8f65 100644 --- a/src/pages/PressPage.tsx +++ b/src/pages/PressPage.tsx @@ -9,7 +9,6 @@ import { usePageHead } from '@/lib/seo/use-page-head'; const linkClass = 'font-medium text-primary underline underline-offset-4 hover:text-primary/80'; // The day the facts below were last checked; move it when they are. const CHECKED_ON = '2026-11-02'; -const MAKER_GITHUB = 'https://github.com/Programcode'; /** * The fact sheet for press and answer engines: what DebateOwl is, who makes it @@ -25,7 +24,7 @@ export default function PressPage() { [t('pressPage.nameLabel'), <>{t('pressPage.name', { product, alternateName: site.alternateName })}</>], [t('pressPage.websiteLabel'), <a href={`${site.origin}/`} className={linkClass}>{new URL(site.origin).host}</a>], [t('pressPage.formerlyLabel'), <>{t('pressPage.formerly', { name: site.formerly.name, host: site.formerly.host, date: longDate(site.formerly.until) })}</>], - [t('pressPage.makerLabel'), <Trans i18nKey="pressPage.maker" components={{ github: <a href={MAKER_GITHUB} className={linkClass} />, pistack: <a href={site.organization.parent.url} className={linkClass} /> }} />], + [t('pressPage.makerLabel'), <Trans i18nKey="pressPage.maker" components={{ github: <a href={site.organization.operator.github} className={linkClass} />, pistack: <a href={site.organization.operator.publishesAs.url} className={linkClass} /> }} />], [t('pressPage.launchedLabel'), <>{t('pressPage.launched', { name: site.formerly.name })}</>], [t('pressPage.languagesLabel'), <>{t('aboutPage.languages')}</>], [t('pressPage.pricingLabel'), ( diff --git a/src/pages/TermsPage.tsx b/src/pages/TermsPage.tsx index 53379bb8..07d91483 100644 --- a/src/pages/TermsPage.tsx +++ b/src/pages/TermsPage.tsx @@ -9,12 +9,21 @@ export default function TermsPage() { const sections = Array.from({ length: 11 }, (_, i) => i + 1); const emails = { contactEmail: site.contactEmail, privacyEmail: site.privacyEmail }; - const mail = (address: string) => <a href={`mailto:${address}`} className="font-medium text-primary underline underline-offset-4 hover:text-primary/80" />; + const linkClass = 'font-medium text-primary underline underline-offset-4 hover:text-primary/80'; + const mail = (address: string) => <a href={`mailto:${address}`} className={linkClass} />; return ( <PublicPageShell className="max-w-[65ch]" footer> <h1 className="text-3xl font-bold tracking-tight text-foreground">{t('termsPage.title')}</h1> <p className="mt-2 text-sm text-muted-foreground">{t('termsPage.lastUpdated')}: {t('termsPage.date')}</p> + <p className="mt-4 text-base leading-7 text-foreground"> + <strong>{t('termsPage.operatorLabel')}:</strong>{' '} + <Trans + i18nKey="termsPage.operator" + values={{ product: site.product, contactEmail: site.contactEmail }} + components={{ pistack: <a href={site.organization.operator.publishesAs.url} className={linkClass} />, contact: mail(site.contactEmail) }} + /> + </p> <div className="mt-8 space-y-6 text-base leading-7 text-foreground"> {sections.map((n) => (