From 196b37b746afb7220890947f8a79b059942e4f04 Mon Sep 17 00:00:00 2001 From: Felix Klement Date: Fri, 9 Oct 2026 12:29:54 +0200 Subject: [PATCH] fasd --- astro.config.mjs | 2 +- src/components/verifier/Seal.astro | 103 +++++++++++++++++++++++++++++ src/i18n/ui.ts | 24 +++++++ src/pages/_NotifyPage.astro | 75 ++++++++++++++++++--- 4 files changed, 192 insertions(+), 12 deletions(-) create mode 100644 src/components/verifier/Seal.astro diff --git a/astro.config.mjs b/astro.config.mjs index 215423d..6a1feb0 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -13,5 +13,5 @@ export default defineConfig({ }, build: { inlineStylesheets: 'auto' }, // In development the form posts to the contact handler started with `npm run contact`. - vite: { server: { proxy: { '^/(contact(/challenge)?|notify(/verify)?)$': { target: 'http://127.0.0.1:3000', changeOrigin: false } } } }, + vite: { server: { proxy: { '^/(contact(/challenge)?|notify(/verify)?)(\\?|$)': { target: 'http://127.0.0.1:3000', changeOrigin: false } } } }, }); diff --git a/src/components/verifier/Seal.astro b/src/components/verifier/Seal.astro new file mode 100644 index 0000000..09ec580 --- /dev/null +++ b/src/components/verifier/Seal.astro @@ -0,0 +1,103 @@ +--- +/** + * The seal on the sign-up result pages: a target drawn as a technical line drawing. On load the + * corner brackets close in and the result is drawn in the centre: a check when the link verified, + * a cross when it did not. Then it stays still. + * Geometry is computed at build time; the motion is CSS only and off under reduced motion. + */ +interface Props { state: 'confirmed' | 'error'; label: string } +const { state, label } = Astro.props; + +const C = 200, R = 184, N = 60; +const f = (n: number) => Math.round(n * 10) / 10; +const at = (r: number, a: number): [number, number] => [C + r * Math.sin(a), C - r * Math.cos(a)]; + +/* Ticks clockwise from twelve o'clock; every fifth is long, so the ring reads as a scale. */ +const ticks = Array.from({ length: N }, (_, i) => { + const a = (i / N) * Math.PI * 2; + const [x1, y1] = at(R, a); + const [x2, y2] = at(R - (i % 5 === 0 ? 20 : 10), a); + return { x1: f(x1), y1: f(y1), x2: f(x2), y2: f(y2) }; +}); + +/* Corner brackets, each an L drawn about the centre and moved in by CSS. */ +const B = 112, arm = 30; +const brackets = [[-1, -1], [1, -1], [1, 1], [-1, 1]].map(([sx, sy]) => + `M${C + sx * B},${C + sy * (B - arm)} L${C + sx * B},${C + sy * B} L${C + sx * (B - arm)},${C + sy * B}`); +--- + + + {ticks.map((t) => )} + + + + + + + + + + + {brackets.map((d) => )} + + + {state === 'confirmed' + ? + : } + + + diff --git a/src/i18n/ui.ts b/src/i18n/ui.ts index 8888262..704ac98 100644 --- a/src/i18n/ui.ts +++ b/src/i18n/ui.ts @@ -276,11 +276,23 @@ const en = { title: 'Registered.', body: 'Your address is confirmed. You will hear from us once, when the CipherVerifier alpha is released.', link: 'Back to CipherVerifier', + seal: 'A target, locked, with a check at its centre.', + rows: [ + { key: 'Status', value: 'Confirmed' }, + { key: 'Signature', value: 'Valid' }, + { key: 'List', value: 'CipherVerifier alpha' }, + { key: 'Next email', value: 'At release' }, + ], }, error: { title: 'Not registered.', body: 'The link has expired or is incomplete, or the registration did not go through. Register again, or write to office@ciphercell.de.', link: 'Register again', + seal: 'A target that did not lock, with a cross at its centre.', + rows: [ + { key: 'Status', value: 'Not confirmed' }, + { key: 'Address', value: 'Not stored' }, + ], }, }, }, @@ -615,11 +627,23 @@ const de: typeof en = { title: 'Registriert.', body: 'Ihre Adresse ist bestätigt. Sie hören einmal von uns, sobald die Alpha von CipherVerifier erscheint.', link: 'Zurück zu CipherVerifier', + seal: 'Ein Zielkreuz, eingerastet, mit einem Haken in der Mitte.', + rows: [ + { key: 'Status', value: 'Bestätigt' }, + { key: 'Signatur', value: 'Gültig' }, + { key: 'Liste', value: 'CipherVerifier-Alpha' }, + { key: 'Nächste E-Mail', value: 'Zur Veröffentlichung' }, + ], }, error: { title: 'Nicht registriert.', body: 'Der Link ist abgelaufen oder unvollständig, oder die Registrierung ist nicht angekommen. Registrieren Sie sich erneut oder schreiben Sie an office@ciphercell.de.', link: 'Erneut registrieren', + seal: 'Ein Zielkreuz, nicht eingerastet, mit einem Kreuz in der Mitte.', + rows: [ + { key: 'Status', value: 'Nicht bestätigt' }, + { key: 'Adresse', value: 'Nicht gespeichert' }, + ], }, }, }, diff --git a/src/pages/_NotifyPage.astro b/src/pages/_NotifyPage.astro index ee346d8..8f8b9a6 100644 --- a/src/pages/_NotifyPage.astro +++ b/src/pages/_NotifyPage.astro @@ -1,5 +1,6 @@ --- import Base from '../layouts/Base.astro'; +import Seal from '../components/verifier/Seal.astro'; import { localePath, t, type Lang } from '../i18n/ui'; interface Props { lang: Lang; page: 'confirmed' | 'error' } const { lang, page } = Astro.props; @@ -8,22 +9,74 @@ const r = p[page]; const product = localePath(lang, '/cipherverifier'); --- -
-
-

{r.title}

-
-

{r.body}

- {r.link} +
+
+
+

{r.title}

+
+ +
+ +
+

{r.body}

+ {r.link} +
+ +
+ {r.rows.map((row) => ( +
+
{row.key}
+
{row.value}
+
+ ))} +