Move docs/ package mirror into document-navigator plugin
Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
# invoice
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The `invoiceTemplate` is the receipt / invoice / order-confirmation
|
||||
email. It renders a heading carrying the invoice number, a metadata line
|
||||
(date, optional due date), a line-items table with description /
|
||||
quantity / unit-price / total columns, a subtotal-tax-total summary, and
|
||||
an optional "Pay Now" CTA when `paymentUrl` is supplied.
|
||||
|
||||
The template is intentionally generic — it does not assume a specific
|
||||
tax-jurisdiction or currency formatting; consumers pass pre-formatted
|
||||
strings (date, currency symbol) and pre-computed numbers (subtotal,
|
||||
tax, total). The template focuses on layout, not arithmetic.
|
||||
|
||||
## Features
|
||||
|
||||
- Line-items table with description, quantity, unit price, total columns.
|
||||
- Subtotal + optional tax + total summary at right-align.
|
||||
- Optional `paymentUrl` renders a "Pay Now" CTA.
|
||||
- Currency symbol is configurable (`currency` defaults to `"$"`).
|
||||
- Optional `dueDate` appears alongside the invoice date.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { renderToHtml } from "@suaveplan/email-templates/renderer";
|
||||
import { invoiceTemplate } from "@suaveplan/email-templates/templates";
|
||||
|
||||
renderToHtml(invoiceTemplate, {
|
||||
recipientName: "Jane",
|
||||
invoiceNumber: "INV-001",
|
||||
invoiceDate: "2026-01-15",
|
||||
items: [
|
||||
{ description: "Pro plan – Jan 2026", quantity: 1, unitPrice: 29, total: 29 },
|
||||
],
|
||||
subtotal: 29,
|
||||
total: 29,
|
||||
});
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
A multi-line invoice with tax, a due date, a payment CTA, and a
|
||||
non-USD currency:
|
||||
|
||||
```ts
|
||||
import { renderToHtml } from "@suaveplan/email-templates/renderer";
|
||||
import { invoiceTemplate } from "@suaveplan/email-templates/templates";
|
||||
|
||||
renderToHtml(invoiceTemplate, {
|
||||
recipientName: "Jane",
|
||||
invoiceNumber: "INV-001",
|
||||
invoiceDate: "2026-01-15",
|
||||
dueDate: "2026-01-31",
|
||||
currency: "€",
|
||||
items: [
|
||||
{ description: "Pro plan – Jan 2026", quantity: 1, unitPrice: 29, total: 29 },
|
||||
{ description: "Add-on: extra seat", quantity: 2, unitPrice: 5, total: 10 },
|
||||
],
|
||||
subtotal: 39,
|
||||
tax: 3.9,
|
||||
total: 42.9,
|
||||
paymentUrl: "https://billing.example.test/pay?invoice=INV-001",
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Symbol | Kind | Description |
|
||||
| ----------------- | -------- | ---------------------------------------------------- |
|
||||
| `invoiceTemplate` | const | `EmailTemplate<InvoiceProps>`. |
|
||||
| `InvoiceEmail` | function | Component returning a `VNode`. |
|
||||
| `InvoiceProps` | type | `{ recipientName, invoiceNumber, invoiceDate, dueDate?, items, subtotal, tax?, total, currency?, paymentUrl?, companyName? }` |
|
||||
| `InvoiceLineItem` | type | `{ description, quantity, unitPrice, total }`. |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Currency formatting uses `Number.prototype.toFixed(2)` — locale-agnostic
|
||||
two-decimal-place rendering. Consumers needing locale-aware grouping
|
||||
separators (e.g. `1,234.56` vs `1 234,56`) should pre-format the strings
|
||||
upstream; the template intentionally does not depend on `Intl.NumberFormat`
|
||||
because email-template environments span Node, Bun, and browsers where
|
||||
the Intl data sets vary.
|
||||
|
||||
The line-items table renders a single `<tbody>` per call; the table
|
||||
header sits in its own `<thead>` so accessibility scanners report the
|
||||
correct table-with-headers structure even though most email clients
|
||||
ignore the distinction.
|
||||
@@ -0,0 +1,83 @@
|
||||
# notification
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The `notificationTemplate` is the generic system-notification email — a
|
||||
configurable severity callout suitable for product-health alerts,
|
||||
audit-trail events, account-status changes, and similar operational
|
||||
messages. The `level` prop drives both the accent border colour and the
|
||||
container background, giving recipients an at-a-glance severity cue.
|
||||
|
||||
## Features
|
||||
|
||||
- Four severity levels — `info`, `success`, `warning`, `error` — each
|
||||
selecting a distinct accent / background colour pair.
|
||||
- Optional `timestamp` (rendered as a muted caption above the action).
|
||||
- Optional `action` button (`{ label, url }`).
|
||||
- Subject derives from the `title` prop.
|
||||
- Validation: unknown level raises `EmailTemplatesError(INVALID_OPTIONS)`
|
||||
and bumps an OTel counter.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { renderToHtml } from "@suaveplan/email-templates/renderer";
|
||||
import { notificationTemplate } from "@suaveplan/email-templates/templates";
|
||||
|
||||
renderToHtml(notificationTemplate, {
|
||||
recipientName: "Jane",
|
||||
title: "Heads up",
|
||||
message: "Your subscription renews tomorrow.",
|
||||
level: "info",
|
||||
});
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
A warning notification with a timestamp and a follow-up action:
|
||||
|
||||
```ts
|
||||
import { renderToHtml } from "@suaveplan/email-templates/renderer";
|
||||
import { notificationTemplate } from "@suaveplan/email-templates/templates";
|
||||
|
||||
renderToHtml(notificationTemplate, {
|
||||
recipientName: "Jane",
|
||||
title: "Failed login from a new device",
|
||||
message: "We blocked an attempt from a device we don't recognise. If this was you, you can dismiss this message.",
|
||||
level: "warning",
|
||||
timestamp: "2026-05-25 14:32 UTC",
|
||||
action: {
|
||||
label: "Review device activity",
|
||||
url: "https://app.example.test/security/devices",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Symbol | Kind | Description |
|
||||
| ----------------------- | -------- | ---------------------------------------------------- |
|
||||
| `notificationTemplate` | const | `EmailTemplate<NotificationProps>`. |
|
||||
| `NotificationEmail` | function | Component returning a `VNode`. |
|
||||
| `NotificationProps` | type | `{ recipientName, title, message, level?, action?, companyName?, timestamp? }` |
|
||||
| `NotificationLevel` | type | `"info" \| "success" \| "warning" \| "error"`. |
|
||||
| `NotificationAction` | type | `{ label, url }`. |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The accent colour for `info`/`success`/`warning`/`error` resolves from
|
||||
the theme's colour palette (`primary` for info; `success`/`warning`/`error`
|
||||
respectively). The container background, however, is a fixed lighter
|
||||
tint per level — those values are not in the theme because they're
|
||||
visually-tuned washes specific to this template's callout pattern.
|
||||
Consumers wanting a theme-driven wash can override via `EmailContainer`
|
||||
directly.
|
||||
|
||||
The accent-bar effect is achieved with a `<div>` carrying
|
||||
`border-left: 4px solid <accent>`. The bar lives inside the
|
||||
`EmailContainer` cell so the container's themed border-radius rounds the
|
||||
outer edges while the bar stays sharp.
|
||||
@@ -0,0 +1,83 @@
|
||||
# password-reset
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The `passwordResetTemplate` is the canonical password-reset message. It
|
||||
explains the request, exposes a reset CTA, communicates the link's
|
||||
expiry, and includes a "you can safely ignore" caution to reassure
|
||||
recipients who did not initiate the request.
|
||||
|
||||
The template reproduces the reset URL as plain text underneath the CTA
|
||||
button — a deliberate redundancy that ensures recipients on
|
||||
text-stripping clients (some webmail security scanners) can still
|
||||
complete the flow.
|
||||
|
||||
## Features
|
||||
|
||||
- Themed reset CTA pointing at `resetUrl`.
|
||||
- Configurable `expiresInMinutes` (defaults to `60`).
|
||||
- Tinted callout container with the "safely ignore" caution copy.
|
||||
- Plain-URL fallback below the divider.
|
||||
- Footer with injectable `Clock`.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { renderToHtml } from "@suaveplan/email-templates/renderer";
|
||||
import { passwordResetTemplate } from "@suaveplan/email-templates/templates";
|
||||
|
||||
const { html, text, subject } = renderToHtml(passwordResetTemplate, {
|
||||
recipientName: "Jane",
|
||||
resetUrl: "https://app.example.test/reset?token=abc",
|
||||
});
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
A 30-minute expiry tied to a tenant-specific brand:
|
||||
|
||||
```ts
|
||||
import { renderToHtml } from "@suaveplan/email-templates/renderer";
|
||||
import { createTheme } from "@suaveplan/email-templates/theme";
|
||||
import { passwordResetTemplate } from "@suaveplan/email-templates/templates";
|
||||
|
||||
const theme = createTheme({
|
||||
colors: { primary: "#22d3ee" },
|
||||
branding: { companyName: "Acme" },
|
||||
});
|
||||
|
||||
renderToHtml(
|
||||
passwordResetTemplate,
|
||||
{
|
||||
recipientName: "Jane",
|
||||
resetUrl: "https://acme.test/reset?token=abc",
|
||||
expiresInMinutes: 30,
|
||||
companyName: "Acme",
|
||||
},
|
||||
{ theme },
|
||||
);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Symbol | Kind | Description |
|
||||
| ------------------------ | -------- | ---------------------------------------------------- |
|
||||
| `passwordResetTemplate` | const | `EmailTemplate<PasswordResetProps>`. |
|
||||
| `PasswordResetEmail` | function | Component returning a `VNode`. |
|
||||
| `PasswordResetProps` | type | `{ recipientName, resetUrl, expiresInMinutes?, companyName? }` |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The 60-minute default mirrors the most common security-team-approved
|
||||
upper bound for password-reset links; tenants needing tighter security
|
||||
should pass an explicit `expiresInMinutes` and ensure their token-issue
|
||||
back-end uses the same value.
|
||||
|
||||
The "safely ignore" line lives inside the tinted callout to visually
|
||||
separate it from the CTA, which discourages anxious recipients from
|
||||
clicking the reset link they did not request — a known social-engineering
|
||||
attack vector when the caution is text-only.
|
||||
@@ -0,0 +1,83 @@
|
||||
# verification
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The `verificationTemplate` is the standard email-address verification
|
||||
flow message. It greets the recipient, optionally displays a one-time
|
||||
code in a centred tinted container with tracked letter-spacing for
|
||||
readability, exposes the verify-link CTA, and includes an expiry
|
||||
notice.
|
||||
|
||||
The template handles both code-only and link-only verification flows by
|
||||
making the `code` field optional. When omitted, the code container is
|
||||
skipped entirely.
|
||||
|
||||
## Features
|
||||
|
||||
- Optional one-time code rendering in a tinted container (32 px,
|
||||
bold, 8 px letter-spacing — the conventional "OTP display" treatment).
|
||||
- Configurable `expiresInMinutes` (defaults to `30`).
|
||||
- Themed verify-email CTA pointing at `verificationUrl`.
|
||||
- Footer with injectable `Clock` for deterministic year.
|
||||
- "If you didn't create an account" caution paragraph.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { renderToHtml } from "@suaveplan/email-templates/renderer";
|
||||
import { verificationTemplate } from "@suaveplan/email-templates/templates";
|
||||
|
||||
const { html, text, subject } = renderToHtml(verificationTemplate, {
|
||||
recipientName: "Jane",
|
||||
verificationUrl: "https://app.example.test/verify?token=abc",
|
||||
code: "ABC123",
|
||||
});
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Link-only verification with a tighter expiry and a tenant-specific
|
||||
brand:
|
||||
|
||||
```ts
|
||||
import { renderToHtml } from "@suaveplan/email-templates/renderer";
|
||||
import { createTheme } from "@suaveplan/email-templates/theme";
|
||||
import { verificationTemplate } from "@suaveplan/email-templates/templates";
|
||||
|
||||
const theme = createTheme({ branding: { companyName: "Acme" } });
|
||||
renderToHtml(
|
||||
verificationTemplate,
|
||||
{
|
||||
recipientName: "Jane",
|
||||
verificationUrl: "https://acme.test/verify?token=abc",
|
||||
expiresInMinutes: 5,
|
||||
companyName: "Acme",
|
||||
},
|
||||
{ theme },
|
||||
);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Symbol | Kind | Description |
|
||||
| ----------------------- | -------- | ------------------------------------------------- |
|
||||
| `verificationTemplate` | const | `EmailTemplate<VerificationProps>`. |
|
||||
| `VerificationEmail` | function | Component returning a `VNode`. |
|
||||
| `VerificationProps` | type | `{ recipientName, verificationUrl, code?, expiresInMinutes?, companyName? }` |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The empty-string check on `code` is intentional: an upstream sanitiser
|
||||
that strips whitespace from a missing-value form field commonly produces
|
||||
`""` rather than `undefined`. Treating both as "no code" keeps the
|
||||
template stable against caller-side variance without requiring a Zod
|
||||
schema at the boundary.
|
||||
|
||||
The OTP container's `letter-spacing: 8px` is wide enough that 6-digit
|
||||
codes render as visually-grouped pairs in most clients, which improves
|
||||
copy-by-eye accuracy. The font size (32 px) is large enough to remain
|
||||
legible on a phone-sized email preview without dominating the layout.
|
||||
@@ -0,0 +1,84 @@
|
||||
# welcome
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The `welcomeTemplate` is the canonical post-signup onboarding email. It
|
||||
greets the recipient by name, summarises why they received the email,
|
||||
exposes the primary CTA, and reproduces the CTA URL as plain text
|
||||
underneath in case the button does not survive a link-rewriting proxy.
|
||||
|
||||
The template is intentionally minimal — it covers the most common
|
||||
post-signup flow. Consumers needing additional structure (feature
|
||||
highlights, social-proof imagery, multi-step onboarding) should compose
|
||||
their own template using the same components.
|
||||
|
||||
## Features
|
||||
|
||||
- Themed heading + body copy + primary CTA + plain-URL fallback +
|
||||
divider + footer.
|
||||
- Configurable `ctaLabel` (defaults to `"Get Started"`).
|
||||
- Configurable `companyName` (defaults to `theme.branding.companyName`).
|
||||
- Subject function: `Welcome to ${companyName}!`.
|
||||
- Optional preview text via the `previewText` prop.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { renderToHtml } from "@suaveplan/email-templates/renderer";
|
||||
import { welcomeTemplate } from "@suaveplan/email-templates/templates";
|
||||
|
||||
const { html, text, subject } = renderToHtml(welcomeTemplate, {
|
||||
recipientName: "Jane",
|
||||
ctaUrl: "https://app.example.test/get-started",
|
||||
});
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Brand-customised with a preview text and a non-default CTA label:
|
||||
|
||||
```ts
|
||||
import { renderToHtml } from "@suaveplan/email-templates/renderer";
|
||||
import { createTheme } from "@suaveplan/email-templates/theme";
|
||||
import { welcomeTemplate } from "@suaveplan/email-templates/templates";
|
||||
|
||||
const theme = createTheme({
|
||||
colors: { primary: "#22d3ee" },
|
||||
branding: { companyName: "Acme Corp" },
|
||||
});
|
||||
|
||||
const result = renderToHtml(
|
||||
welcomeTemplate,
|
||||
{
|
||||
recipientName: "Jane",
|
||||
ctaUrl: "https://acme.test/welcome",
|
||||
ctaLabel: "Continue",
|
||||
previewText: "You're in! Let's get you set up.",
|
||||
},
|
||||
{ theme },
|
||||
);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Symbol | Kind | Description |
|
||||
| ------------------ | -------- | ---------------------------------------------------- |
|
||||
| `welcomeTemplate` | const | `EmailTemplate<WelcomeProps>`. |
|
||||
| `WelcomeEmail` | function | Direct component access (returns a `VNode`). |
|
||||
| `WelcomeProps` | type | `{ recipientName, ctaUrl, ctaLabel?, companyName?, previewText? }` |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The plain-URL fallback paragraph is rendered as a muted caption — small
|
||||
type, low contrast — so it doesn't compete with the CTA visually. The
|
||||
fallback line uses the same `ctaUrl` value as the button, so any later
|
||||
URL change touches one source of truth.
|
||||
|
||||
The footer's clock is intentionally not threaded through this template
|
||||
— consumers wanting a deterministic copyright year supply a `clock` to
|
||||
`renderToHtml`, which passes it to the component as part of the merged
|
||||
props bag.
|
||||
Reference in New Issue
Block a user