Skip to content

Implement contact form with hCaptcha and update documentation - #92

Open
NanoMil wants to merge 1 commit into
mainfrom
contact-form-migration
Open

Implement contact form with hCaptcha and update documentation#92
NanoMil wants to merge 1 commit into
mainfrom
contact-form-migration

Conversation

@NanoMil

@NanoMil NanoMil commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Add PoC contact form to reduce Spam requests.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a reusable contact form component (backed by Web3Forms with click-to-load hCaptcha) to reduce spam and replaces obfuscated email display on the Contact and Imprint pages, alongside the required privacy-policy disclosures and developer documentation updates.

Changes:

  • Add ContactForm.astro component that submits to Web3Forms and gates hCaptcha behind explicit user interaction.
  • Replace email obfuscation snippets on Contact/Imprint pages with the new contact form (EN + DE) and add new UI translations.
  • Update privacy policies (EN + DE) to disclose Web3Forms and hCaptcha processing, and extend README with Node/nvm and form-testing notes.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/pages/privacy.mdx Adds EN privacy disclosures for contact forms, Web3Forms, and hCaptcha.
src/pages/de/privacy.mdx Adds DE privacy disclosures for contact forms, Web3Forms, and hCaptcha.
src/pages/imprint.mdx Replaces obfuscated email output with contact form for the executive board (EN).
src/pages/de/imprint.mdx Replaces obfuscated email output with contact form for the board (DE).
src/pages/contact.mdx Replaces obfuscated email with contact form embed (EN).
src/pages/de/contact.mdx Replaces obfuscated email with contact form embed (DE).
src/i18n/ui/en.ts Adds EN translation strings for the contact form UI and messages.
src/i18n/ui/de.ts Adds DE translation strings for the contact form UI and messages.
src/components/ContactForm.astro New reusable contact form component with hCaptcha consent gate, client submit, and styling.
README.md Documents Node version management and how to test the contact form behavior.
.nvmrc Pins Node major version for local development via nvm.
Suppressed comments (2)

src/components/ContactForm.astro:128

  • More TypeScript-only generic type arguments are used in the click-to-load captcha wiring (querySelector<HTMLElement>, querySelector<HTMLButtonElement>). These should be removed from the runtime script to avoid emitting invalid JS.
    const consent = form.querySelector<HTMLElement>('[data-captcha-consent]');
    const widget = form.querySelector<HTMLElement>('.h-captcha');

    form.querySelector<HTMLButtonElement>('[data-captcha-load]')?.addEventListener('click', () => {

src/components/ContactForm.astro:152

  • The validation/captcha lookup still includes TypeScript-only generic annotations (querySelector<HTMLElement>, querySelector<HTMLTextAreaElement>). These should be removed from the shipped script as well to avoid emitting invalid JS.
      if (!form.checkValidity()) {
        form.querySelector<HTMLElement>(':invalid')?.focus();
        return;
      }

      // hCaptcha injects its response textarea into the form only once solved,
      // so this has to be looked up at submit time rather than upfront.
      const captchaField = form.querySelector<HTMLTextAreaElement>('textarea[name="h-captcha-response"]');
      const captchaSolved = !form.querySelector('.h-captcha') || Boolean(captchaField?.value);

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +9 to +12
/**
* Renders the hCaptcha widget. Set to false to fall back to honeypot-only
* spam protection – see the privacy note in AGENTS.md before changing.
*/
Comment on lines +109 to +113
<script>
const forms = document.querySelectorAll<HTMLFormElement>('form[data-contact-form]');

forms.forEach((form) => {
const result = form.querySelector<HTMLElement>('[data-contact-result]');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants