@nxgt/mail-presets 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,395 @@
1
+ # Troubleshooting `@nxgt/mail-presets`
2
+
3
+ Each entry is headed by the message you see. Search this page for the words of
4
+ your message. Near the end, a trap that fails no build, and a section for
5
+ contributors to this package.
6
+
7
+ How the messages are shaped:
8
+
9
+ - **A wiring mistake is a `TypeError` starting `presets:`**, thrown by the
10
+ `presets()` call in `maizzle.config.ts` when the config loads, so
11
+ `maizzle build` and `maizzle serve` stop before any template is built. Fix
12
+ the call.
13
+ - **The other failures come from the packages the presets are built with.**
14
+ `@nxgt/mail-i18n` prints `i18n: …`, and a missing `ui()` shows first as
15
+ Vue's `Failed to resolve component` warnings.
16
+ Most of them mean one of the three lines that wire the presets is missing:
17
+ `ui()`, a catalogue in `catalogues`, or the templates in `templates`. This
18
+ page covers the ones the presets cause. The rest are in
19
+ [`@nxgt/mail-i18n`'s troubleshooting](https://github.com/softistx/nxgt-mail/blob/develop/packages/mail-i18n/docs/troubleshooting.md)
20
+ and
21
+ [`@nxgt/mail-ui`'s](https://github.com/softistx/nxgt-mail/blob/develop/packages/mail-ui/docs/troubleshooting.md).
22
+
23
+ Every fix below ends in the same config, which builds every preset in `en`
24
+ and `fr`:
25
+
26
+ ```ts
27
+ // maizzle.config.ts
28
+ import { defineMailConfig } from '@nxgt/mail-config';
29
+ import { i18n } from '@nxgt/mail-i18n';
30
+ import { presets } from '@nxgt/mail-presets';
31
+ import { ui, uiCatalogues } from '@nxgt/mail-ui';
32
+
33
+ const mails = presets(); // or presets({ only: ['verify-email', 'reset-password'] })
34
+
35
+ export default defineMailConfig({
36
+ plugins: [
37
+ ui({ brand: { name: 'Acme', url: 'https://acme.example' } }),
38
+ i18n({
39
+ locales: ['en', 'fr'],
40
+ catalogues: [uiCatalogues, mails.catalogues],
41
+ templates: [mails.templates],
42
+ }),
43
+ ],
44
+ });
45
+ ```
46
+
47
+ The samples below use the locales `en` and `fr`, the preset `verify-email`,
48
+ and the brand `Acme`.
49
+
50
+ ## Index
51
+
52
+ **Wiring**: when `maizzle.config.ts` loads
53
+ - [`presets: options must be an object, as { only: ['verify-email'] }`](#presets-options-must-be-an-object-as--only-verify-email-)
54
+ - [`presets: only must list at least one preset, as ['verify-email']`](#presets-only-must-list-at-least-one-preset-as-verify-email)
55
+ - [`presets: only holds something that is not a preset — name one of verify-email, reset-password, …`](#presets-only-holds-something-that-is-not-a-preset--name-one-of-verify-email-reset-password-password-changed-email-changed-sign-in-code-magic-link-new-sign-in-welcome-invitation)
56
+ - [`presets: only holds the same preset twice`](#presets-only-holds-the-same-preset-twice)
57
+ - [`i18n: templates must be a list of template folders, as [{ dir: '/abs/path/emails' }] — emails, when given, names at least one, each once`](#i18n-templates-must-be-a-list-of-template-folders-as--dir-abspathemails---emails-when-given-names-at-least-one-each-once)
58
+ - [`i18n: templates[0] and templates[1] both have welcome.vue — keep one with emails: [...], or write the project's own in its folder`](#i18n-templates0-and-templates1-both-have-welcomevue--keep-one-with-emails--or-write-the-projects-own-in-its-folder)
59
+ - [`i18n: de: presets.linkFallback is missing — en, the fallback locale, has it`](#i18n-de-presetslinkfallback-is-missing--en-the-fallback-locale-has-it)
60
+ - [`i18n: fr: verifyEmail.body uses {brand}, which en does not declare`](#i18n-fr-verifyemailbody-uses-brand-which-en-does-not-declare)
61
+
62
+ **Build**: while `maizzle build` renders
63
+ - [`i18n: en: verify-email calls t('common.footer.why'), which is not a key of the catalogues`](#i18n-en-verify-email-calls-tcommonfooterwhy-which-is-not-a-key-of-the-catalogues)
64
+ - [`i18n: en: verify-email calls t('verifyEmail.preheader'), which is not a key of the catalogues`](#i18n-en-verify-email-calls-tverifyemailpreheader-which-is-not-a-key-of-the-catalogues)
65
+ - [`TypeError: Cannot read properties of undefined (reading 'name')`](#typeerror-cannot-read-properties-of-undefined-reading-name)
66
+ - [`i18n: en/new-sign-in.html is empty — a tag of its template resolved to no component; list the plugin that brings it, as ui()`](#i18n-ennew-sign-inhtml-is-empty--a-tag-of-its-template-resolved-to-no-component-list-the-plugin-that-brings-it-as-ui)
67
+ - [`i18n: en: verify-email passes {brand} to verifyEmail.body, which does not use it`](#i18n-en-verify-email-passes-brand-to-verifyemailbody-which-does-not-use-it)
68
+
69
+ **Traps: a build that succeeds and is wrong**
70
+ - [A bug in `@nxgt/mail-presets` itself](#a-bug-in-nxgtmail-presets-itself)
71
+
72
+ **Contributing to this package**
73
+ - [``samples/ is what the build writes — run `bun run samples` after a change``](#samples-is-what-the-build-writes--run-bun-run-samples-after-a-change)
74
+
75
+ ---
76
+
77
+ ## Wiring
78
+
79
+ ### `presets: options must be an object, as { only: ['verify-email'] }`
80
+
81
+ **When:** loading `maizzle.config.ts`, when `presets` is called with the list
82
+ of names directly (`presets(['welcome'])`), a string (`presets('welcome')`),
83
+ `null`, or another value that is not an object.
84
+ **Why:** `presets` takes one optional object. Its one option, `only`, names
85
+ the presets to build. Call it with nothing to build every preset.
86
+ **Fix:**
87
+
88
+ ```ts
89
+ import { presets } from '@nxgt/mail-presets';
90
+
91
+ const mails = presets({ only: ['welcome'] }); // not presets(['welcome']), not presets('welcome')
92
+ ```
93
+
94
+ ### `presets: only must list at least one preset, as ['verify-email']`
95
+
96
+ **When:** loading `maizzle.config.ts`, when `only` is an empty list or a
97
+ single name rather than a list (`only: 'welcome'`).
98
+ **Why:** `only` keeps the presets it names and no other, so an empty list
99
+ would build none of them.
100
+ **Fix:** pass a list, or leave `only` out to build every preset:
101
+
102
+ ```ts
103
+ presets({ only: ['welcome'] }); // not only: 'welcome', not only: []
104
+ presets(); // every preset
105
+ ```
106
+
107
+ ### `presets: only holds something that is not a preset — name one of verify-email, reset-password, password-changed, email-changed, sign-in-code, magic-link, new-sign-in, welcome, invitation`
108
+
109
+ **When:** loading `maizzle.config.ts`, when `only` names an e-mail the
110
+ package does not ship. Common causes are a typo, a name in camelCase
111
+ (`'verifyEmail'`), a name with `.vue`, or a name of your own template such as
112
+ `'sign-in'`.
113
+ **Why:** `only` names the package's templates, by the name of their file and
114
+ of their built file (`dist/en/verify-email.html`). The message lists them.
115
+ TypeScript refuses such a name too, where the config is type-checked.
116
+ **Fix:**
117
+
118
+ ```ts
119
+ import { PRESETS, presets } from '@nxgt/mail-presets';
120
+
121
+ presets({ only: ['verify-email', 'sign-in-code'] }); // not 'verifyEmail', not 'sign-in'
122
+ console.log(PRESETS); // every name
123
+ ```
124
+
125
+ An e-mail of your own goes in the project's `emails/`, not in `only`.
126
+
127
+ ### `presets: only holds the same preset twice`
128
+
129
+ **When:** loading `maizzle.config.ts`, when `only` names a preset twice. This
130
+ usually happens when a list is joined from two others.
131
+ **Why:** each preset is built once. A name given twice is a mistake in the
132
+ list that builds it.
133
+ **Fix:**
134
+
135
+ ```ts
136
+ presets({ only: [...new Set([...authMails, ...accountMails])] });
137
+ ```
138
+
139
+ ### `i18n: templates must be a list of template folders, as [{ dir: '/abs/path/emails' }] — emails, when given, names at least one, each once`
140
+
141
+ **When:** loading `maizzle.config.ts`, most often when the presets' templates
142
+ are passed alone instead of in a list: `templates: mails.templates`.
143
+ **Why:** `@nxgt/mail-i18n` takes a list of template folders, so that several
144
+ packages can each ship templates. `presets()` answers one folder.
145
+ **Fix:** wrap it in a list, even when there is one:
146
+
147
+ ```ts
148
+ i18n({
149
+ locales: ['en', 'fr'],
150
+ catalogues: [uiCatalogues, mails.catalogues],
151
+ templates: [mails.templates], // not templates: mails.templates
152
+ });
153
+ ```
154
+
155
+ ### `i18n: templates[0] and templates[1] both have welcome.vue — keep one with emails: [...], or write the project's own in its folder`
156
+
157
+ **When:** loading `maizzle.config.ts`, when `templates` lists the presets'
158
+ folder twice with a preset in common. This usually happens when `presets()`
159
+ is called twice, once for each group of e-mails, the two `only` lists share a
160
+ preset or one call has no `only`, and both answers are listed.
161
+ **Why:** each e-mail is built once. Two entries that ship the same e-mail
162
+ leave no obvious one to build, so `@nxgt/mail-i18n` refuses to pick.
163
+ **Fix:** call `presets()` once, with every preset you build:
164
+
165
+ ```ts
166
+ const mails = presets({ only: ['verify-email', 'reset-password', 'welcome'] });
167
+
168
+ i18n({
169
+ locales: ['en', 'fr'],
170
+ catalogues: [uiCatalogues, mails.catalogues],
171
+ templates: [mails.templates], // not [authMails.templates, accountMails.templates]
172
+ });
173
+ ```
174
+
175
+ To replace a preset with your own, write `emails/welcome.vue` in the project.
176
+ It wins over the preset, and this error does not apply to it.
177
+
178
+ ### `i18n: de: presets.linkFallback is missing — en, the fallback locale, has it`
179
+
180
+ The message names your locale. The key starts `presets.` or with a preset's
181
+ key (`verifyEmail.`, `signInCode.`, …), or `common.` when the `common` keys
182
+ are missing as well (`i18n: de: common.footer.ignore is missing — …`).
183
+
184
+ **When:** loading `maizzle.config.ts`, when the project builds a locale other
185
+ than `en` and `fr`, such as `locales: ['en', 'de']`.
186
+ **Why:** the presets' messages ship in `en` and `fr` only, and so do
187
+ `@nxgt/mail-ui`'s `common` messages. Every locale must have every key of the
188
+ fallback locale.
189
+ **Fix:** write the missing messages in the project's own catalogue:
190
+
191
+ ```jsonc
192
+ // locales/de.json
193
+ {
194
+ "common": { "greeting": "Hallo {name},", "footer": { "why": "…", "ignore": "…" } },
195
+ "presets": { "linkFallback": "…", "notYou": "…" },
196
+ "verifyEmail": { "subject": "…", "preheader": "…", "title": "…", "body": "…", "action": "…" }
197
+ }
198
+ ```
199
+
200
+ The keys to write are the ones in `presetCatalogues.en` and
201
+ `uiCatalogues.en`. With `only`, write just the `presets` group and the groups
202
+ of the presets kept, as `presets({ only }).catalogues.en` shows:
203
+
204
+ ```ts
205
+ import { presets } from '@nxgt/mail-presets';
206
+
207
+ console.log(JSON.stringify(presets({ only: ['verify-email'] }).catalogues.en, null, 2));
208
+ ```
209
+
210
+ ### `i18n: fr: verifyEmail.body uses {brand}, which en does not declare`
211
+
212
+ The message names a locale the project did not override, a preset's key, and
213
+ an argument of the preset's message.
214
+
215
+ **When:** loading `maizzle.config.ts`, after the project overrides a preset's
216
+ message in `locales/en.json` with other arguments than the preset's, as
217
+ `"body": "Confirm your address for {company}."` in place of the preset's
218
+ `{brand}`.
219
+ **Why:** a project's message replaces the preset's in that locale only. The
220
+ other locale keeps the preset's text, and every locale must use only the
221
+ arguments that the fallback locale declares.
222
+ **Fix:** keep the preset's arguments in the override. They are the ones in
223
+ the preset's own message:
224
+
225
+ ```ts
226
+ import { presetCatalogues } from '@nxgt/mail-presets';
227
+
228
+ console.log(presetCatalogues.en.verifyEmail); // body: '… your {brand} account.'
229
+ ```
230
+
231
+ ```jsonc
232
+ // locales/en.json
233
+ { "verifyEmail": { "body": "Confirm your address to start using {brand}." } }
234
+ ```
235
+
236
+ When both locales are overridden with a new argument, as `{company}` in `en`
237
+ and in `fr`, the build stops later, on
238
+ `i18n: en: verify-email calls t('verifyEmail.body') without {company}`: the
239
+ preset's template passes `brand`, not `company`. To add an argument, write
240
+ the project's own template in `emails/verify-email.vue`, which replaces the
241
+ preset's.
242
+
243
+ ---
244
+
245
+ ## Build
246
+
247
+ These fail while `maizzle build` renders a template. The build stops, and the
248
+ line to read starts `Error:` or `TypeError:`, after Vue's warnings and a stack
249
+ trace. Maizzle builds the locales in no set order, so the locale in the
250
+ message is `en` in one run and `fr` in the next.
251
+
252
+ ### `i18n: en: verify-email calls t('common.footer.why'), which is not a key of the catalogues`
253
+
254
+ The message names a preset, and the key starts `common.`.
255
+
256
+ **When:** `maizzle build`, on the first preset, when `catalogues` holds the
257
+ presets' messages but not `uiCatalogues`.
258
+ **Why:** a preset's layout and greeting use `@nxgt/mail-ui`'s shared
259
+ `common.*` messages, which ship in `uiCatalogues`. `presets().catalogues`
260
+ holds only the presets' own messages.
261
+ **Fix:** pass both, `uiCatalogues` first:
262
+
263
+ ```ts
264
+ i18n({
265
+ locales: ['en', 'fr'],
266
+ catalogues: [uiCatalogues, mails.catalogues], // not [mails.catalogues]
267
+ templates: [mails.templates],
268
+ });
269
+ ```
270
+
271
+ ### `i18n: en: verify-email calls t('verifyEmail.preheader'), which is not a key of the catalogues`
272
+
273
+ The message names a preset, and the key starts with that preset's key
274
+ (`verifyEmail.`, `signInCode.`, …) or `presets.`.
275
+
276
+ **When:** `maizzle build`, on the first preset, when `templates` holds the
277
+ presets' templates but `catalogues` does not hold their messages.
278
+ **Why:** `presets()` answers the templates and their messages separately,
279
+ because `@nxgt/mail-i18n` takes each in its own option. Passing one without
280
+ the other builds templates that have no text.
281
+ **Fix:** pass `mails.catalogues` with `mails.templates`, from the same
282
+ `presets()` call:
283
+
284
+ ```ts
285
+ const mails = presets({ only: ['verify-email'] });
286
+
287
+ i18n({
288
+ locales: ['en', 'fr'],
289
+ catalogues: [uiCatalogues, mails.catalogues],
290
+ templates: [mails.templates],
291
+ });
292
+ ```
293
+
294
+ When `only` differs between two `presets()` calls, the catalogues of one lack
295
+ the messages of the templates of the other. Call it once.
296
+
297
+ ### `TypeError: Cannot read properties of undefined (reading 'name')`
298
+
299
+ It follows `[Vue warn]: Failed to resolve component: NxLayout` (and
300
+ `NxTypography`, `NxButton`, …) and
301
+ `[Vue warn]: Property "brand" was accessed during render but is not defined on instance.`
302
+
303
+ **When:** `maizzle build`, on the first preset, when `ui()` is not in the
304
+ plugins. That includes a project that registers `@nxgt/mail-ui`'s components
305
+ itself, with `COMPONENTS_DIR` in `components.source`, instead of calling
306
+ `ui()`.
307
+ **Why:** the presets are built with `@nxgt/mail-ui`'s components and read
308
+ the brand that `ui()` gives every template (`brand.name`). Maizzle resolves
309
+ no component in a template under `node_modules`, where the presets are
310
+ installed; `ui()` does it for them. Without `ui()`, the components do not
311
+ resolve and `brand` is undefined.
312
+ **Fix:** add `ui()`, with your brand, and remove any `components.source`
313
+ entry that points at `COMPONENTS_DIR`:
314
+
315
+ ```ts
316
+ export default defineMailConfig({
317
+ plugins: [
318
+ ui({ brand: { name: 'Acme', url: 'https://acme.example' } }),
319
+ i18n({ /* … */ }),
320
+ ],
321
+ });
322
+ ```
323
+
324
+ ### `i18n: en/new-sign-in.html is empty — a tag of its template resolved to no component; list the plugin that brings it, as ui()`
325
+
326
+ It follows `[Vue warn]: Failed to resolve component: NxLayout` (and
327
+ `NxTypography`, `NxButton`, …).
328
+
329
+ **When:** `maizzle build`, after the templates, when `ui()` is not in the
330
+ plugins and the presets built read no brand, as with
331
+ `presets({ only: ['new-sign-in'] })`. The other presets stop earlier, on the
332
+ `TypeError` above.
333
+ **Why:** without `ui()`, the presets' components do not resolve, and Vue
334
+ renders a component it cannot resolve as nothing. The e-mail would go out
335
+ blank.
336
+ **Fix:** add `ui()`, as above.
337
+
338
+ ### `i18n: en: verify-email passes {brand} to verifyEmail.body, which does not use it`
339
+
340
+ **When:** `maizzle build`, on that preset, after the project overrides one of
341
+ its messages in every locale with a text that leaves out an argument the
342
+ preset's template passes, as `"body": "Confirm your address."` in
343
+ `locales/en.json` and `"body": "Confirmez votre adresse."` in
344
+ `locales/fr.json`.
345
+ **Why:** a template passes exactly the arguments its message uses, and one
346
+ more is refused: the message and the template disagree. The preset's
347
+ template still passes `brand`.
348
+ **Fix:** keep the argument in the override, or write the project's own
349
+ template in `emails/verify-email.vue`, which replaces the preset's:
350
+
351
+ ```jsonc
352
+ // locales/en.json
353
+ { "verifyEmail": { "body": "Confirm your address to start using {brand}." } }
354
+ ```
355
+
356
+ When only `en` leaves the argument out, the build stops earlier, when the
357
+ config loads, on `i18n: fr: verifyEmail.body uses {brand}, which en does not
358
+ declare`.
359
+
360
+ ---
361
+
362
+ ## Traps: a build that succeeds and is wrong
363
+
364
+ ### A bug in `@nxgt/mail-presets` itself
365
+
366
+ A preset that fails to build with the config at the top of this page, or a
367
+ text that differs between `en` and `fr` in meaning, is a bug in this package.
368
+ The same goes for a built e-mail that differs from its sample in `samples/`
369
+ for the same brand and theme. Open an issue on
370
+ [`softistx/nxgt-mail`](https://github.com/softistx/nxgt-mail/issues) with the
371
+ message, the package version, the Maizzle version, and your
372
+ `maizzle.config.ts`. Never include a real address or link.
373
+
374
+ ---
375
+
376
+ ## Contributing to this package
377
+
378
+ ### ``samples/ is what the build writes — run `bun run samples` after a change``
379
+
380
+ **When:** `bun test` in `packages/mail-presets`, after a change to a template
381
+ in `emails/`, a message in `src/locales/`, or anything that changes the
382
+ built HTML, including a change to `@nxgt/mail-ui`'s components or theme. The
383
+ diff shows the old text as expected and the new text as received.
384
+ **Why:** `samples/` holds each preset as the test fixture builds it, and
385
+ the spec compares a fresh build with it, file by file. The samples must stay
386
+ what the package builds.
387
+ **Fix:** rebuild them, check the diff, and commit it with the change:
388
+
389
+ ```sh
390
+ cd packages/mail-presets
391
+ bun run samples # builds test/fixture, copies its HTML to samples/, rewrites samples/README.md
392
+ git diff samples/
393
+ ```
394
+
395
+ Never edit `samples/` by hand.
@@ -0,0 +1,14 @@
1
+ <template>
2
+ <NxLayout :preheader="t('emailChanged.preheader')">
3
+ <NxTypography variant="headline-small">{{ t('emailChanged.title') }}</NxTypography>
4
+ <NxTypography>{{ t('common.greeting', { name: placeholder('name') }) }}</NxTypography>
5
+ <NxTypography>{{ t('emailChanged.body', { brand: brand.name, newEmail: placeholder('newEmail') }) }}</NxTypography>
6
+ <NxAlert variant="warning" :description="t('presets.notYou')" />
7
+ <NxButton :href="placeholder('link')">{{ t('emailChanged.action') }}</NxButton>
8
+ <Spacer class="h-6" />
9
+ <NxTypography variant="body-small" class="text-muted-foreground">
10
+ {{ t('presets.linkFallback') }}
11
+ <NxLink :href="placeholder('link')">{{ placeholder('link') }}</NxLink>
12
+ </NxTypography>
13
+ </NxLayout>
14
+ </template>
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <NxLayout :preheader="t('invitation.preheader', { organization: placeholder('organization'), brand: brand.name })">
3
+ <NxTypography variant="headline-small">{{ t('invitation.title', { organization: placeholder('organization') }) }}</NxTypography>
4
+ <NxTypography>{{ t('invitation.body', { inviter: placeholder('inviter'), organization: placeholder('organization'), brand: brand.name }) }}</NxTypography>
5
+ <NxButton :href="placeholder('link')">{{ t('invitation.action') }}</NxButton>
6
+ <Spacer class="h-6" />
7
+ <NxTypography variant="body-small" class="text-muted-foreground">
8
+ {{ t('presets.linkFallback') }}
9
+ <NxLink :href="placeholder('link')">{{ placeholder('link') }}</NxLink>
10
+ </NxTypography>
11
+ </NxLayout>
12
+ </template>
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <NxLayout :preheader="t('magicLink.preheader')">
3
+ <NxTypography variant="headline-small">{{ t('magicLink.title', { brand: brand.name }) }}</NxTypography>
4
+ <NxTypography>{{ t('magicLink.body') }}</NxTypography>
5
+ <NxButton :href="placeholder('link')">{{ t('magicLink.action') }}</NxButton>
6
+ <Spacer class="h-6" />
7
+ <NxTypography variant="body-small" class="text-muted-foreground">
8
+ {{ t('presets.linkFallback') }}
9
+ <NxLink :href="placeholder('link')">{{ placeholder('link') }}</NxLink>
10
+ </NxTypography>
11
+ <NxTypography variant="caption">{{ t('common.footer.ignore') }}</NxTypography>
12
+ </NxLayout>
13
+ </template>
@@ -0,0 +1,21 @@
1
+ <template>
2
+ <NxLayout :preheader="t('newSignIn.preheader')">
3
+ <NxTypography variant="headline-small">{{ t('newSignIn.title') }}</NxTypography>
4
+ <NxTypography>{{ t('common.greeting', { name: placeholder('name') }) }}</NxTypography>
5
+ <NxBanner tone="warning" :title="t('newSignIn.banner')" />
6
+ <NxSummaryData
7
+ :data="[
8
+ { label: t('newSignIn.device'), value: placeholder('device') },
9
+ { label: t('newSignIn.location'), value: placeholder('location') },
10
+ { label: t('newSignIn.time'), value: placeholder('time') },
11
+ ]"
12
+ />
13
+ <NxTypography>{{ t('newSignIn.body') }} {{ t('presets.notYou') }}</NxTypography>
14
+ <NxButton :href="placeholder('link')">{{ t('newSignIn.action') }}</NxButton>
15
+ <Spacer class="h-6" />
16
+ <NxTypography variant="body-small" class="text-muted-foreground">
17
+ {{ t('presets.linkFallback') }}
18
+ <NxLink :href="placeholder('link')">{{ placeholder('link') }}</NxLink>
19
+ </NxTypography>
20
+ </NxLayout>
21
+ </template>
@@ -0,0 +1,14 @@
1
+ <template>
2
+ <NxLayout :preheader="t('passwordChanged.preheader')">
3
+ <NxTypography variant="headline-small">{{ t('passwordChanged.title') }}</NxTypography>
4
+ <NxTypography>{{ t('common.greeting', { name: placeholder('name') }) }}</NxTypography>
5
+ <NxTypography>{{ t('passwordChanged.body', { brand: brand.name }) }}</NxTypography>
6
+ <NxAlert variant="warning" :description="t('presets.notYou')" />
7
+ <NxButton :href="placeholder('link')">{{ t('passwordChanged.action') }}</NxButton>
8
+ <Spacer class="h-6" />
9
+ <NxTypography variant="body-small" class="text-muted-foreground">
10
+ {{ t('presets.linkFallback') }}
11
+ <NxLink :href="placeholder('link')">{{ placeholder('link') }}</NxLink>
12
+ </NxTypography>
13
+ </NxLayout>
14
+ </template>
@@ -0,0 +1,14 @@
1
+ <template>
2
+ <NxLayout :preheader="t('resetPassword.preheader')">
3
+ <NxTypography variant="headline-small">{{ t('resetPassword.title') }}</NxTypography>
4
+ <NxTypography>{{ t('common.greeting', { name: placeholder('name') }) }}</NxTypography>
5
+ <NxTypography>{{ t('resetPassword.body', { brand: brand.name }) }}</NxTypography>
6
+ <NxButton :href="placeholder('link')">{{ t('resetPassword.action') }}</NxButton>
7
+ <Spacer class="h-6" />
8
+ <NxTypography variant="body-small" class="text-muted-foreground">
9
+ {{ t('presets.linkFallback') }}
10
+ <NxLink :href="placeholder('link')">{{ placeholder('link') }}</NxLink>
11
+ </NxTypography>
12
+ <NxTypography variant="caption">{{ t('common.footer.ignore') }}</NxTypography>
13
+ </NxLayout>
14
+ </template>
@@ -0,0 +1,8 @@
1
+ <template>
2
+ <NxLayout :preheader="t('signInCode.preheader')">
3
+ <NxTypography variant="headline-small">{{ t('signInCode.title') }}</NxTypography>
4
+ <NxTypography>{{ t('signInCode.body', { brand: brand.name }) }}</NxTypography>
5
+ <NxCode>{{ placeholder('code') }}</NxCode>
6
+ <NxTypography variant="caption">{{ t('signInCode.ignore') }}</NxTypography>
7
+ </NxLayout>
8
+ </template>
@@ -0,0 +1,14 @@
1
+ <template>
2
+ <NxLayout :preheader="t('verifyEmail.preheader')">
3
+ <NxTypography variant="headline-small">{{ t('verifyEmail.title') }}</NxTypography>
4
+ <NxTypography>{{ t('common.greeting', { name: placeholder('name') }) }}</NxTypography>
5
+ <NxTypography>{{ t('verifyEmail.body', { brand: brand.name }) }}</NxTypography>
6
+ <NxButton :href="placeholder('link')">{{ t('verifyEmail.action') }}</NxButton>
7
+ <Spacer class="h-6" />
8
+ <NxTypography variant="body-small" class="text-muted-foreground">
9
+ {{ t('presets.linkFallback') }}
10
+ <NxLink :href="placeholder('link')">{{ placeholder('link') }}</NxLink>
11
+ </NxTypography>
12
+ <NxTypography variant="caption">{{ t('common.footer.ignore') }}</NxTypography>
13
+ </NxLayout>
14
+ </template>
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <NxLayout :preheader="t('welcome.preheader')">
3
+ <NxTypography variant="headline-small">{{ t('welcome.title', { brand: brand.name }) }}</NxTypography>
4
+ <NxTypography>{{ t('common.greeting', { name: placeholder('name') }) }}</NxTypography>
5
+ <NxTypography>{{ t('welcome.body') }}</NxTypography>
6
+ <NxButton :href="placeholder('link')">{{ t('welcome.action') }}</NxButton>
7
+ <Spacer class="h-6" />
8
+ <NxTypography variant="body-small" class="text-muted-foreground">
9
+ {{ t('presets.linkFallback') }}
10
+ <NxLink :href="placeholder('link')">{{ placeholder('link') }}</NxLink>
11
+ </NxTypography>
12
+ </NxLayout>
13
+ </template>
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@nxgt/mail-presets",
3
+ "version": "0.1.0",
4
+ "description": "Ready transactional e-mails for a Maizzle project built with @nxgt/mail-ui and @nxgt/mail-i18n — verify-email, reset-password, sign-in-code, magic-link, new-sign-in, welcome, invitation… in en and fr — with their built HTML as samples.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "emails",
12
+ "docs",
13
+ "README.md",
14
+ "package.json",
15
+ "LICENSE"
16
+ ],
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js",
21
+ "default": "./dist/index.js"
22
+ },
23
+ "./package.json": "./package.json"
24
+ },
25
+ "keywords": [
26
+ "email",
27
+ "maizzle",
28
+ "templates",
29
+ "transactional",
30
+ "i18n",
31
+ "vue"
32
+ ],
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/softistx/nxgt-mail.git",
36
+ "directory": "packages/mail-presets"
37
+ },
38
+ "publishConfig": {
39
+ "registry": "https://registry.npmjs.org",
40
+ "access": "public"
41
+ },
42
+ "scripts": {
43
+ "build": "bun run ../../build.ts",
44
+ "test": "bun test src",
45
+ "typecheck": "tsc --noEmit && bun run typecheck:templates",
46
+ "typecheck:templates": "bun run prepare:templates && cd test/fixture && vue-tsc -p tsconfig.json",
47
+ "prepare:templates": "cd test/fixture && maizzle prepare",
48
+ "samples": "bun run scripts/samples.ts"
49
+ },
50
+ "devDependencies": {
51
+ "@maizzle/framework": "6.1.7",
52
+ "@maizzle/tailwindcss": "1.5.6",
53
+ "@nxgt/mail": "0.1.0",
54
+ "@nxgt/mail-config": "0.1.0",
55
+ "@nxgt/mail-i18n": "0.1.0",
56
+ "@nxgt/mail-ui": "0.1.0",
57
+ "@types/bun": "^1.4.2",
58
+ "vue": "3.5.43",
59
+ "vue-tsc": "^3.3.11"
60
+ },
61
+ "peerDependencies": {
62
+ "@maizzle/framework": "^6.1.7",
63
+ "@nxgt/mail-i18n": "^0.1.0",
64
+ "@nxgt/mail-ui": "^0.1.0",
65
+ "typescript": "^6.0.3",
66
+ "vue": "^3.5.0"
67
+ }
68
+ }