Coloriginz Design Systemshadcn custom registry

@col/email-templates

Versie: 1.0.0 Toegevoegd: 2026-08-06

Herkomst

De blokvolgorde en de zinnen komen uit de drie bestaande activatiemails: growerportal2/src/lib/email-templates.ts (activationEmailHtml, resetPasswordEmailHtml), floriday api/src/features/auth/emails/invitation.ts, en supplier-onboarding-vercel/src/lib/email.ts (sendActivationEmail, sendPasswordResetEmail). De opbouw bleek in alle drie identiek; alleen de zinnen verschilden — zie de vergelijkingstabel in docs/specs/2026-08-06-v8-email-templates-ontwerp.md. Dat is precies de scheiding waar EmailBlock[] (uit @col/email-shell) voor bestaat: dit item levert de vorm plus overschrijfbare standaardzinnen, niet vaste tekst.

Waarvoor

De twee mails die elke app met accounts nodig heeft: wachtwoord instellen (na het aanmaken van een account) en wachtwoord vergeten. Beide functies geven { subject, blocks: EmailBlock[] } terug, die je zelf aan buildEmail uit @col/email-shell doorgeeft.

Niet voor workflow-mails — orderbevestigingen, leveringsmeldingen, statusnotificaties. Die horen in de app zelf.

Let op de naamsverwarring. Supplier-onboarding-vercel's "uitnodiging" vraagt een externe leverancier een formulier in te vullen — dat is iets anders dan de activatiemail hier, die hoort bij het aanmaken van een account met wachtwoord. Alleen Floriday's "uitnodiging" (stel je wachtwoord in) valt onder activationEmail.

Wat je app moet leveren

EMAIL_TEMPLATES_VERSION

Uit email-fill.ts: EMAIL_TEMPLATES_VERSION: string. Welke versie in een app draait, achterhaal je met grep -rn EMAIL_TEMPLATES_VERSION src/; bijwerken gaat met npx shadcn add @col/email-templates --overwrite.

ActivationStrings

Veld Type Betekenis
subject string Onderwerpregel. Draagt geen merknaam — zie Bekende beperkingen
heading string Kop, blok 1
greeting string Aanhef, blok 2. Mag {name} bevatten
body string Uitleg, blok 3
button string Knoplabel, blok 4
linkValid string? Geldigheidszin, blok 5. Mag {date} bevatten. Weglaten betekent: geen blok
ignoreNotice string? Negeer-zin, blok 6. Weglaten betekent: geen blok

Meegeleverd: activationStringsNl en activationStringsEn, beide volledig ingevuld met de standaardzinnen (aanspreekvorm je, zie Bekende beperkingen).

activationEmail

function activationEmail(input: {
  name: string
  url: string
  expires?: string // al geformatteerd; alleen nodig als strings.linkValid om {date} vraagt
  strings: ActivationStrings
}): { subject: string; blocks: EmailBlock[] }

De blokkenreeks die eruit komt:

Volgorde Blok Bron
1 heading strings.heading
2 paragraph strings.greeting, met {name} ingevuld
3 paragraph strings.body
4 button strings.button + input.url
5 note strings.linkValid met {date} ingevuld — alleen als meegegeven
6 paragraph strings.ignoreNotice — alleen als meegegeven

ResetStrings / resetEmail

Identiek van vorm aan ActivationStrings / activationEmail, met dezelfde velden en dezelfde blokkenreeks. Meegeleverd: resetStringsNl en resetStringsEn. Zie Bewuste keuzes voor waarom dit een apart bestand is in plaats van een gedeelde implementatie.

Voorbeeld

import { activationEmail, activationStringsNl } from '@/components/email/email-activation'
import { buildEmail } from '@/components/email/email-shell'

const { blocks } = activationEmail({
  name: 'Jan',
  url: 'https://app.example.com/activate/abc123',
  expires: '9 augustus 2026',
  strings: activationStringsNl,
})
// De standaard subject ('Stel je wachtwoord in') draagt geen merknaam — zie
// Bekende beperkingen. Overschrijf hem in een gedeelde postbus.
const subject = 'Coloríginz — stel je wachtwoord in'

// EmailBrand komt uit @col/email-shell, niet uit dit item — zie
// docs/items/email-shell.md voor het volledige veldoverzicht.
const brand = {
  name: 'Coloríginz',
  logo: { filename: 'logo.png', content: logoBuffer, cid: 'brand-logo', width: 140, height: 40 },
  accent: '#006799',
  accentContrast: '#ffffff',
  rule: '#0098da',
  footerText: 'Coloríginz — OZ Import BV, Aalsmeer',
}

const mail = buildEmail({
  to: 'jan@example.com',
  subject,
  brand,
  // een eigen blok toevoegen kost niets aan de kant van het item —
  // dat is precies de reden voor { subject, blocks } in plaats van een compleet Mail
  blocks: entraEnabled
    ? [...blocks, { kind: 'note', text: 'Je kunt ook inloggen met je Microsoft-account.' }]
    : blocks,
})

// mail.html, mail.text, mail.attachments -> door naar je eigen transport

Bestanden

Bestand Landt in Soort
email-fill.ts components/email/ beheerd
email-activation.ts components/email/ beheerd
email-reset.ts components/email/ beheerd

Registry-afhankelijkheid: @col/email-shell. Eén npx shadcn add @col/email-templates installeert dus acht bestanden — deze drie plus de vijf van de romp — allemaal in components/email/. Dat is precies waarom de relatieve imports kloppen.

Gebruikt door

App Sinds versie Opmerkingen
(nog geen) Eerste consument wordt floriday-middleware

Vul dit bij, ook vanuit een andere repo. Dit is de enige plek waar staat wie geraakt wordt door een wijziging. Installeer je het item in een nieuwe app, voeg dan een regel toe en push naar deze repo — dat hoort bij de installatie.

Bewuste keuzes

Bekende beperkingen