best-email-builder 0.4.0 → 0.5.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.
- package/CHANGELOG.md +57 -0
- package/README.md +119 -44
- package/dist/ai-server.js +68 -0
- package/dist/ai-server.js.map +1 -0
- package/dist/ai.js +852 -0
- package/dist/ai.js.map +1 -0
- package/dist/builder.js +16 -8
- package/dist/chunk-2RZHGAH5.js +64 -0
- package/dist/chunk-2RZHGAH5.js.map +1 -0
- package/dist/chunk-3LKF4QBL.js +595 -0
- package/dist/chunk-3LKF4QBL.js.map +1 -0
- package/dist/chunk-5SASKCUC.js +251 -0
- package/dist/chunk-5SASKCUC.js.map +1 -0
- package/dist/{chunk-NAEGU6PR.js → chunk-6D3SLT5W.js} +18 -29
- package/dist/chunk-6D3SLT5W.js.map +1 -0
- package/dist/chunk-7U6BAKM7.js +119 -0
- package/dist/chunk-7U6BAKM7.js.map +1 -0
- package/dist/{chunk-HHLOE6OZ.js → chunk-DFNHICTF.js} +10 -333
- package/dist/chunk-DFNHICTF.js.map +1 -0
- package/dist/chunk-ECHGJZ2W.js +327 -0
- package/dist/chunk-ECHGJZ2W.js.map +1 -0
- package/dist/chunk-KXJJSVN5.js +98 -0
- package/dist/chunk-KXJJSVN5.js.map +1 -0
- package/dist/{chunk-AT73Y7JA.js → chunk-LXR4QTGP.js} +49 -581
- package/dist/chunk-LXR4QTGP.js.map +1 -0
- package/dist/{chunk-TGDZ4NFI.js → chunk-LYMJ2TBX.js} +3 -44
- package/dist/chunk-LYMJ2TBX.js.map +1 -0
- package/dist/{chunk-JNHFZXDL.js → chunk-MPX5CWTZ.js} +560 -649
- package/dist/chunk-MPX5CWTZ.js.map +1 -0
- package/dist/{chunk-MY6WPDT4.js → chunk-PB7YZ3WP.js} +463 -938
- package/dist/chunk-PB7YZ3WP.js.map +1 -0
- package/dist/chunk-UFKCLU2D.js +255 -0
- package/dist/chunk-UFKCLU2D.js.map +1 -0
- package/dist/index.js +31 -37
- package/dist/index.js.map +1 -1
- package/dist/library.js +12 -7
- package/dist/server.js +33 -74
- package/dist/server.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/ai/ConnectAi.d.ts +12 -0
- package/dist/types/ai/GenerateButton.d.ts +4 -0
- package/dist/types/ai/SubjectIdeas.d.ts +25 -0
- package/dist/types/ai/createAi.d.ts +66 -0
- package/dist/types/{features/generate → ai}/draft.d.ts +44 -3
- package/dist/types/{features/generate → ai}/generator.d.ts +7 -2
- package/dist/types/ai/i18n/fr.d.ts +2 -0
- package/dist/types/ai/i18n/index.d.ts +2 -0
- package/dist/types/ai/index.d.ts +9 -0
- package/dist/types/ai/keys.d.ts +46 -0
- package/dist/types/ai/providers.d.ts +67 -0
- package/dist/types/{features/generate → ai}/rewrite.d.ts +1 -1
- package/dist/types/ai/server.d.ts +9 -0
- package/dist/types/{features/generate → ai}/subjects.d.ts +18 -4
- package/dist/types/core/constants.d.ts +1 -1
- package/dist/types/engine/NativeAdapter.d.ts +1 -1
- package/dist/types/features/preview/darkMode.d.ts +33 -16
- package/dist/types/features/variables/VariablePicker.d.ts +3 -2
- package/dist/types/i18n/index.d.ts +8 -0
- package/dist/types/index.d.ts +1 -7
- package/dist/types/server/handler.d.ts +5 -4
- package/dist/types/server/index.d.ts +1 -8
- package/dist/types/storage/client.d.ts +22 -40
- package/dist/types/ui/EmailBuilder.d.ts +5 -1
- package/dist/types/ui/EmailStudio.d.ts +6 -1
- package/dist/types/ui/PropertiesPanel.d.ts +2 -1
- package/dist/types/ui/primitives/searchShortcut.d.ts +16 -0
- package/package.json +15 -1
- package/dist/chunk-AT73Y7JA.js.map +0 -1
- package/dist/chunk-HHLOE6OZ.js.map +0 -1
- package/dist/chunk-JNHFZXDL.js.map +0 -1
- package/dist/chunk-MY6WPDT4.js.map +0 -1
- package/dist/chunk-NAEGU6PR.js.map +0 -1
- package/dist/chunk-TGDZ4NFI.js.map +0 -1
- package/dist/types/features/generate/GenerateButton.d.ts +0 -3
- package/dist/types/features/generate/SubjectIdeas.d.ts +0 -16
- package/dist/types/features/generate/index.d.ts +0 -2
- /package/dist/types/{features/generate → ai}/RewriteText.d.ts +0 -0
- /package/dist/types/{features/generate → ai}/chip.d.ts +0 -0
- /package/dist/types/{features/generate → ai}/claude.d.ts +0 -0
- /package/dist/types/{features/generate → ai}/prompt.d.ts +0 -0
- /package/dist/types/{features/generate → ai}/purposes.d.ts +0 -0
|
@@ -1,80 +1,3 @@
|
|
|
1
|
-
// src/core/constants.js
|
|
2
|
-
var EMAIL_BUILDER_VERSION = "0.4.0";
|
|
3
|
-
var EMAIL_DOCUMENT_SCHEMA_VERSION = 1;
|
|
4
|
-
var EMAIL_DEVICES = ["desktop", "mobile"];
|
|
5
|
-
var EMAIL_MOBILE_WIDTH = 375;
|
|
6
|
-
|
|
7
|
-
// src/core/document.js
|
|
8
|
-
var MIGRATIONS = {};
|
|
9
|
-
var EmailDocumentError = class extends Error {
|
|
10
|
-
/** @param {string} message */
|
|
11
|
-
constructor(message) {
|
|
12
|
-
super(message);
|
|
13
|
-
this.name = "EmailDocumentError";
|
|
14
|
-
this.status = 422;
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
function isPlainObject(value) {
|
|
18
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
19
|
-
}
|
|
20
|
-
function createDocument({ engine, engineVersion, project }) {
|
|
21
|
-
if (!engine) throw new EmailDocumentError("Document: missing engine");
|
|
22
|
-
if (!isPlainObject(project)) throw new EmailDocumentError("Document: invalid engine project");
|
|
23
|
-
return {
|
|
24
|
-
schemaVersion: EMAIL_DOCUMENT_SCHEMA_VERSION,
|
|
25
|
-
engine,
|
|
26
|
-
engineVersion: String(engineVersion || ""),
|
|
27
|
-
builderVersion: EMAIL_BUILDER_VERSION,
|
|
28
|
-
project: (
|
|
29
|
-
/** @type {Record<string, any>} */
|
|
30
|
-
project
|
|
31
|
-
)
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
function readDocument(raw) {
|
|
35
|
-
let value = raw;
|
|
36
|
-
if (typeof value === "string") {
|
|
37
|
-
try {
|
|
38
|
-
value = JSON.parse(value);
|
|
39
|
-
} catch {
|
|
40
|
-
throw new EmailDocumentError("Unreadable document: invalid JSON");
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
if (!isPlainObject(value)) throw new EmailDocumentError("Unreadable document: object expected");
|
|
44
|
-
let document = { .../** @type {object} */
|
|
45
|
-
value };
|
|
46
|
-
const version = Number(document.schemaVersion);
|
|
47
|
-
if (!Number.isInteger(version) || version < 1) {
|
|
48
|
-
throw new EmailDocumentError("Unreadable document: missing schema version");
|
|
49
|
-
}
|
|
50
|
-
if (version > EMAIL_DOCUMENT_SCHEMA_VERSION) {
|
|
51
|
-
throw new EmailDocumentError(
|
|
52
|
-
`Document written by a newer version of the builder (schema ${version}) \u2014 reload the page`
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
for (let v = version; v < EMAIL_DOCUMENT_SCHEMA_VERSION; v += 1) {
|
|
56
|
-
const migrate = MIGRATIONS[v];
|
|
57
|
-
if (!migrate) throw new EmailDocumentError(`Document: no migration from schema ${v}`);
|
|
58
|
-
document = migrate(document);
|
|
59
|
-
}
|
|
60
|
-
if (typeof document.engine !== "string" || !document.engine) {
|
|
61
|
-
throw new EmailDocumentError("Unreadable document: missing engine");
|
|
62
|
-
}
|
|
63
|
-
if (!isPlainObject(document.project)) {
|
|
64
|
-
throw new EmailDocumentError("Unreadable document: missing engine project");
|
|
65
|
-
}
|
|
66
|
-
return {
|
|
67
|
-
schemaVersion: EMAIL_DOCUMENT_SCHEMA_VERSION,
|
|
68
|
-
engine: document.engine,
|
|
69
|
-
engineVersion: String(document.engineVersion || ""),
|
|
70
|
-
builderVersion: String(document.builderVersion || ""),
|
|
71
|
-
project: document.project
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
function serializeDocument(document) {
|
|
75
|
-
return JSON.stringify(readDocument(document));
|
|
76
|
-
}
|
|
77
|
-
|
|
78
1
|
// src/i18n/fr.js
|
|
79
2
|
var fr = {
|
|
80
3
|
"1. Complete your profile": "1. Compl\xE9tez votre profil",
|
|
@@ -134,7 +57,6 @@ var fr = {
|
|
|
134
57
|
"Email settings": "R\xE9glages de l'e-mail",
|
|
135
58
|
"Email template library": "Biblioth\xE8que de mod\xE8les e-mail",
|
|
136
59
|
"Equal": "\xC9gales",
|
|
137
|
-
"Event invitation": "Invitation",
|
|
138
60
|
"Facebook": "Facebook",
|
|
139
61
|
"Favorites": "Favoris",
|
|
140
62
|
"Fill the section": "Remplir la section",
|
|
@@ -165,7 +87,6 @@ var fr = {
|
|
|
165
87
|
"Menu link": "Lien du menu",
|
|
166
88
|
"Monthly news: banner, two articles, highlights": "Les nouvelles du mois : banni\xE8re, deux articles, br\xE8ves",
|
|
167
89
|
"Network": "R\xE9seau",
|
|
168
|
-
"Newsletter": "Newsletter",
|
|
169
90
|
"No preview: this storage cannot render emails.": "Pas d'aper\xE7u : ce stockage ne sait pas compiler les e-mails.",
|
|
170
91
|
"No template yet. Start from a base, or create a new one.": "Aucun mod\xE8le pour l\u2019instant. Partez d\u2019une base, ou cr\xE9ez-en un.",
|
|
171
92
|
"Nothing matches \u201C{query}\u201D.": "Aucun r\xE9sultat pour \xAB {query} \xBB.",
|
|
@@ -223,7 +144,6 @@ var fr = {
|
|
|
223
144
|
"Underline (Ctrl+U)": "Soulign\xE9 (Ctrl+U)",
|
|
224
145
|
"Updated": "Modifi\xE9",
|
|
225
146
|
"Vertical": "Verticale",
|
|
226
|
-
"Welcome": "Bienvenue",
|
|
227
147
|
"Welcome aboard!": "Bienvenue \xE0 bord !",
|
|
228
148
|
"Welcome, {name}!": "Bienvenue, {name} !",
|
|
229
149
|
"What changed, what is coming, and two stories worth your time.": "Ce qui a chang\xE9, ce qui arrive, et deux articles qui valent le d\xE9tour.",
|
|
@@ -525,134 +445,16 @@ var fr = {
|
|
|
525
445
|
"Your text.": "Votre texte.",
|
|
526
446
|
"\u201C{name}\u201D template applied.": "Mod\xE8le \xAB {name} \xBB appliqu\xE9.",
|
|
527
447
|
"\u20AC49 instead of \u20AC70": "49 \u20AC au lieu de 70 \u20AC",
|
|
528
|
-
"Generate": "G\xE9n\xE9rer",
|
|
529
|
-
"Generate an email": "G\xE9n\xE9rer un e-mail",
|
|
530
|
-
"Pick what it is for. AI writes a complete email that opens here, ready to edit.": "Choisissez \xE0 quoi il sert. L'IA \xE9crit un e-mail complet qui s'ouvre ici, pr\xEAt \xE0 modifier.",
|
|
531
|
-
"Search": "Rechercher",
|
|
532
|
-
"Search: sale, password, birthday\u2026": "Rechercher : soldes, mot de passe, anniversaire\u2026",
|
|
533
|
-
"What is the email for?": "\xC0 quoi sert l'e-mail ?",
|
|
534
|
-
"Nothing matches. Describe your email in the details below.": "Aucun r\xE9sultat. D\xE9crivez votre e-mail dans les pr\xE9cisions ci-dessous.",
|
|
535
|
-
"Details (optional)": "Pr\xE9cisions (facultatif)",
|
|
536
|
-
"Details (optional): product, dates, offer, tone, language\u2026": "Pr\xE9cisions (facultatif) : produit, dates, offre, ton, langue\u2026",
|
|
537
|
-
"The email being edited will be replaced, unsaved changes included.": "L'e-mail en cours sera remplac\xE9, modifications non enregistr\xE9es comprises.",
|
|
538
|
-
"Writing your email\u2026 {seconds} s": "R\xE9daction de votre e-mail\u2026 {seconds} s",
|
|
539
|
-
"Your email is ready. Edit anything, then save.": "Votre e-mail est pr\xEAt. Modifiez ce que vous voulez, puis enregistrez.",
|
|
540
448
|
"Cancelled": "Annul\xE9",
|
|
541
449
|
"Email generation is not configured": "La g\xE9n\xE9ration d'e-mails n'est pas configur\xE9e",
|
|
542
450
|
"Too many generated emails \u2014 try again later": "Trop d'e-mails g\xE9n\xE9r\xE9s \u2014 r\xE9essayez plus tard",
|
|
543
451
|
"The AI service did not answer \u2014 try again in a moment.": "Le service d'IA n'a pas r\xE9pondu \u2014 r\xE9essayez dans un instant.",
|
|
544
|
-
"Pick what the email is for, or describe it.": "Choisissez \xE0 quoi sert l'e-mail, ou d\xE9crivez-le.",
|
|
545
|
-
"The AI declined to write this email. Try other details.": "L'IA a refus\xE9 d'\xE9crire cet e-mail. Essayez d'autres pr\xE9cisions.",
|
|
546
|
-
"The email was too long to finish. Ask for a shorter one.": "L'e-mail \xE9tait trop long pour \xEAtre termin\xE9. Demandez-en un plus court.",
|
|
547
|
-
"The AI answer could not be read. Try again.": "La r\xE9ponse de l'IA est illisible. R\xE9essayez.",
|
|
548
|
-
"The generated email could not be used. Try again.": "L'e-mail g\xE9n\xE9r\xE9 est inutilisable. R\xE9essayez.",
|
|
549
|
-
"Sales and promotions": "Ventes et promotions",
|
|
550
|
-
"Holidays and occasions": "F\xEAtes et occasions",
|
|
551
|
-
"Events and appointments": "\xC9v\xE9nements et rendez-vous",
|
|
552
|
-
"News and content": "Actualit\xE9s et contenus",
|
|
553
|
-
"Account and security": "Compte et s\xE9curit\xE9",
|
|
554
|
-
"Orders and payments": "Commandes et paiements",
|
|
555
|
-
"Customer relationship": "Relation client",
|
|
556
|
-
"Business and organization": "Entreprise et organisation",
|
|
557
|
-
"Store sale": "Soldes en boutique",
|
|
558
|
-
"Flash sale": "Vente flash",
|
|
559
|
-
"Discount code": "Code promo",
|
|
560
|
-
"New product": "Nouveau produit",
|
|
561
|
-
"Back in stock": "De retour en stock",
|
|
562
|
-
"Price drop": "Baisse de prix",
|
|
563
|
-
"Abandoned cart": "Panier abandonn\xE9",
|
|
564
|
-
"Black Friday": "Black Friday",
|
|
565
|
-
"Loyalty reward": "R\xE9compense fid\xE9lit\xE9",
|
|
566
|
-
"Refer a friend": "Parrainage",
|
|
567
|
-
"Christmas": "No\xEBl",
|
|
568
|
-
"New Year": "Nouvel An",
|
|
569
|
-
"Season's greetings": "V\u0153ux de fin d'ann\xE9e",
|
|
570
|
-
"Valentine's Day": "Saint-Valentin",
|
|
571
|
-
"Easter": "P\xE2ques",
|
|
572
|
-
"Mother's Day": "F\xEAte des m\xE8res",
|
|
573
|
-
"Father's Day": "F\xEAte des p\xE8res",
|
|
574
|
-
"Halloween": "Halloween",
|
|
575
|
-
"Back to school": "Rentr\xE9e",
|
|
576
|
-
"Summer holidays": "Vacances d'\xE9t\xE9",
|
|
577
|
-
"Birthday wishes": "Joyeux anniversaire",
|
|
578
|
-
"Customer anniversary": "Anniversaire client",
|
|
579
|
-
"Women's Day": "Journ\xE9e des femmes",
|
|
580
|
-
"Thanksgiving": "Thanksgiving",
|
|
581
|
-
"Lunar New Year": "Nouvel An lunaire",
|
|
582
|
-
"Ramadan and Eid": "Ramadan et A\xEFd",
|
|
583
|
-
"Diwali": "Diwali",
|
|
584
|
-
"Meeting reminder": "Rappel de r\xE9union",
|
|
585
|
-
"Appointment confirmation": "Confirmation de rendez-vous",
|
|
586
|
-
"Booking confirmation": "Confirmation de r\xE9servation",
|
|
587
|
-
"Webinar invitation": "Invitation \xE0 un webinaire",
|
|
588
|
-
"Save the date": "Save the date",
|
|
589
|
-
"Registration confirmed": "Inscription confirm\xE9e",
|
|
590
|
-
"Cancellation or new date": "Annulation ou report",
|
|
591
|
-
"Thanks for attending": "Merci de votre participation",
|
|
592
|
-
"New article": "Nouvel article",
|
|
593
|
-
"What's new": "Nouveaut\xE9s",
|
|
594
|
-
"Announcement": "Annonce",
|
|
595
|
-
"Tips and how-to": "Conseils et tutoriels",
|
|
596
|
-
"Email verification": "V\xE9rification de l'e-mail",
|
|
597
|
-
"Password reset": "R\xE9initialisation du mot de passe",
|
|
598
|
-
"Login code": "Code de connexion",
|
|
599
|
-
"Security alert": "Alerte de s\xE9curit\xE9",
|
|
600
|
-
"Getting started": "Premiers pas",
|
|
601
|
-
"Trial ending": "Fin de l'essai",
|
|
602
|
-
"Order confirmation": "Confirmation de commande",
|
|
603
|
-
"Order shipped": "Commande exp\xE9di\xE9e",
|
|
604
|
-
"Delivery delay": "Retard de livraison",
|
|
605
|
-
"Receipt or invoice": "Re\xE7u ou facture",
|
|
606
|
-
"Payment failed": "\xC9chec du paiement",
|
|
607
|
-
"Subscription renewal": "Renouvellement d'abonnement",
|
|
608
|
-
"Refund issued": "Remboursement effectu\xE9",
|
|
609
|
-
"Thank you": "Remerciements",
|
|
610
|
-
"Review request": "Demande d'avis",
|
|
611
|
-
"Survey": "Enqu\xEAte de satisfaction",
|
|
612
|
-
"We miss you": "Vous nous manquez",
|
|
613
|
-
"Follow-up": "Relance",
|
|
614
|
-
"Apology": "Excuses",
|
|
615
|
-
"We're hiring": "On recrute",
|
|
616
|
-
"Policy update": "Mise \xE0 jour des conditions",
|
|
617
|
-
"Price change": "Changement de prix",
|
|
618
|
-
"Scheduled maintenance": "Maintenance planifi\xE9e",
|
|
619
|
-
"Closure or opening hours": "Fermeture ou horaires",
|
|
620
|
-
"Donation appeal": "Appel aux dons",
|
|
621
|
-
"Internal update": "Communication interne",
|
|
622
|
-
"Rewrite with AI": "R\xE9\xE9crire avec l'IA",
|
|
623
|
-
"Shorter": "Plus court",
|
|
624
|
-
"Longer": "Plus long",
|
|
625
|
-
"Fix mistakes": "Corriger les fautes",
|
|
626
|
-
"Friendlier": "Plus chaleureux",
|
|
627
|
-
"More formal": "Plus formel",
|
|
628
|
-
"Translate": "Traduire",
|
|
629
|
-
"Translate into": "Traduire en",
|
|
630
|
-
"Or say what to change\u2026": "Ou dites ce qu'il faut changer\u2026",
|
|
631
|
-
"What to change": "Ce qu'il faut changer",
|
|
632
|
-
"Rewrite": "R\xE9\xE9crire",
|
|
633
|
-
"Rewriting\u2026": "R\xE9\xE9criture\u2026",
|
|
634
452
|
"Color scheme": "Th\xE8me de couleurs",
|
|
635
453
|
"Light mode": "Mode clair",
|
|
636
454
|
"Dark mode": "Mode sombre",
|
|
637
455
|
"Dark mode as Gmail and Outlook apps show it: light backgrounds turn dark, dark text turns light, images stay as they are.": "Mode sombre tel que l'affichent les applis Gmail et Outlook : les fonds clairs deviennent sombres, le texte fonc\xE9 devient clair, les images restent telles quelles.",
|
|
638
|
-
"Suggest subjects": "Sugg\xE9rer des objets",
|
|
639
|
-
"Subject ideas": "Id\xE9es d'objet",
|
|
640
|
-
"More ideas": "Autres id\xE9es",
|
|
641
|
-
"Done": "Termin\xE9",
|
|
642
|
-
"yours": "le v\xF4tre",
|
|
643
|
-
"Reading the email\u2026": "Lecture de l'e-mail\u2026",
|
|
644
|
-
"No subject could be suggested.": "Aucun objet n'a pu \xEAtre sugg\xE9r\xE9.",
|
|
645
456
|
"Subject ideas are not configured": "Les id\xE9es d'objet ne sont pas configur\xE9es",
|
|
646
457
|
"Too many subject ideas \u2014 try again later": "Trop de demandes d'id\xE9es d'objet \u2014 r\xE9essayez plus tard",
|
|
647
|
-
"Write the email or a subject first: the ideas are drawn from it.": "R\xE9digez d'abord l'e-mail ou un objet : les id\xE9es en sont tir\xE9es.",
|
|
648
|
-
"The AI declined to suggest subjects for this email.": "L'IA a refus\xE9 de sugg\xE9rer des objets pour cet e-mail.",
|
|
649
|
-
"No usable subject came back. Try again.": "Aucun objet utilisable n'a \xE9t\xE9 propos\xE9. R\xE9essayez.",
|
|
650
|
-
"Text rewritten. Ctrl+Z brings back the previous one.": "Texte r\xE9\xE9crit. Ctrl+Z r\xE9tablit le pr\xE9c\xE9dent.",
|
|
651
|
-
"The text changed in the meantime, so it was left as it is.": "Le texte a chang\xE9 entre-temps : il a \xE9t\xE9 laiss\xE9 tel quel.",
|
|
652
|
-
"The text could not be rewritten.": "Le texte n'a pas pu \xEAtre r\xE9\xE9crit.",
|
|
653
|
-
"There is no text to rewrite.": "Il n'y a pas de texte \xE0 r\xE9\xE9crire.",
|
|
654
|
-
"The AI declined to rewrite this text.": "L'IA a refus\xE9 de r\xE9\xE9crire ce texte.",
|
|
655
|
-
"The rewritten text lost a link or a variable, so nothing was changed. Try again.": "Le texte r\xE9\xE9crit avait perdu un lien ou une variable : rien n'a \xE9t\xE9 modifi\xE9. R\xE9essayez.",
|
|
656
458
|
"Text rewriting is not configured": "La r\xE9\xE9criture de texte n'est pas configur\xE9e",
|
|
657
459
|
"Too many rewrites \u2014 try again later": "Trop de r\xE9\xE9critures \u2014 r\xE9essayez plus tard",
|
|
658
460
|
"Brand": "Marque",
|
|
@@ -712,8 +514,13 @@ function createTranslator(messages = {}) {
|
|
|
712
514
|
};
|
|
713
515
|
}
|
|
714
516
|
function translatorFor(locale = "en", overrides = {}) {
|
|
715
|
-
|
|
716
|
-
|
|
517
|
+
return createTranslator({ ...messagesOf(LOCALES, locale), ...overrides });
|
|
518
|
+
}
|
|
519
|
+
function messagesOf(dictionaries, locale = "en") {
|
|
520
|
+
if (!dictionaries) return {};
|
|
521
|
+
const code = String(locale).toLowerCase();
|
|
522
|
+
const own = (key) => Object.prototype.hasOwnProperty.call(dictionaries, key) ? dictionaries[key] : null;
|
|
523
|
+
return own(code) || own(code.slice(0, 2)) || {};
|
|
717
524
|
}
|
|
718
525
|
var identity = createTranslator();
|
|
719
526
|
|
|
@@ -1466,100 +1273,6 @@ function mergeVariables(system, custom = []) {
|
|
|
1466
1273
|
return [...system, ...custom.filter((v) => !keys.has(v.key)).map((v) => ({ ...v, custom: true }))];
|
|
1467
1274
|
}
|
|
1468
1275
|
|
|
1469
|
-
// src/features/preview/darkMode.js
|
|
1470
|
-
var DARK_PAGE = "#121212";
|
|
1471
|
-
var DARK_TEXT = "#e8e8e8";
|
|
1472
|
-
var NAMED = {
|
|
1473
|
-
white: "#ffffff",
|
|
1474
|
-
black: "#000000",
|
|
1475
|
-
snow: "#fffafa",
|
|
1476
|
-
ivory: "#fffff0",
|
|
1477
|
-
whitesmoke: "#f5f5f5",
|
|
1478
|
-
ghostwhite: "#f8f8ff",
|
|
1479
|
-
gainsboro: "#dcdcdc",
|
|
1480
|
-
lightgray: "#d3d3d3",
|
|
1481
|
-
lightgrey: "#d3d3d3",
|
|
1482
|
-
silver: "#c0c0c0",
|
|
1483
|
-
gray: "#808080",
|
|
1484
|
-
grey: "#808080",
|
|
1485
|
-
navy: "#000080"
|
|
1486
|
-
};
|
|
1487
|
-
function parseCssColor(token) {
|
|
1488
|
-
const value = token.trim().toLowerCase();
|
|
1489
|
-
const hex = NAMED[
|
|
1490
|
-
/** @type {keyof typeof NAMED} */
|
|
1491
|
-
value
|
|
1492
|
-
] || value;
|
|
1493
|
-
let match = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/.exec(hex);
|
|
1494
|
-
if (match) {
|
|
1495
|
-
let digits = match[1];
|
|
1496
|
-
if (digits.length <= 4) digits = [...digits].map((d) => d + d).join("");
|
|
1497
|
-
const n = (i) => parseInt(digits.slice(i, i + 2), 16);
|
|
1498
|
-
return { r: n(0), g: n(2), b: n(4), a: digits.length === 8 ? n(6) / 255 : 1 };
|
|
1499
|
-
}
|
|
1500
|
-
match = /^rgba?\(\s*([\d.]+%?)[\s,]+([\d.]+%?)[\s,]+([\d.]+%?)(?:[\s,/]+([\d.]+%?))?\s*\)$/.exec(value);
|
|
1501
|
-
if (match) {
|
|
1502
|
-
const channel = (v) => Math.min(255, v.endsWith("%") ? parseFloat(v) * 255 / 100 : parseFloat(v));
|
|
1503
|
-
const alpha = match[4] === void 0 ? 1 : match[4].endsWith("%") ? parseFloat(match[4]) / 100 : parseFloat(match[4]);
|
|
1504
|
-
return { r: channel(match[1]), g: channel(match[2]), b: channel(match[3]), a: Math.min(1, alpha) };
|
|
1505
|
-
}
|
|
1506
|
-
return null;
|
|
1507
|
-
}
|
|
1508
|
-
function luminance2({ r, g, b }) {
|
|
1509
|
-
const linear = (c) => {
|
|
1510
|
-
const v = c / 255;
|
|
1511
|
-
return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
|
|
1512
|
-
};
|
|
1513
|
-
return 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b);
|
|
1514
|
-
}
|
|
1515
|
-
function toHsl2({ r, g, b }) {
|
|
1516
|
-
const [R, G, B] = [r / 255, g / 255, b / 255];
|
|
1517
|
-
const max = Math.max(R, G, B);
|
|
1518
|
-
const min = Math.min(R, G, B);
|
|
1519
|
-
const l = (max + min) / 2;
|
|
1520
|
-
if (max === min) return [0, 0, l];
|
|
1521
|
-
const d = max - min;
|
|
1522
|
-
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
1523
|
-
const h = max === R ? (G - B) / d + (G < B ? 6 : 0) : max === G ? (B - R) / d + 2 : (R - G) / d + 4;
|
|
1524
|
-
return [h * 60, s, l];
|
|
1525
|
-
}
|
|
1526
|
-
function fromHsl2(h, s, l, a) {
|
|
1527
|
-
const k = (n) => (n + h / 30) % 12;
|
|
1528
|
-
const q = s * Math.min(l, 1 - l);
|
|
1529
|
-
const f = (n) => Math.round(255 * (l - q * Math.max(-1, Math.min(k(n) - 3, 9 - k(n), 1))));
|
|
1530
|
-
const [r, g, b] = [f(0), f(8), f(4)];
|
|
1531
|
-
if (a < 1) return `rgba(${r}, ${g}, ${b}, ${Math.round(a * 100) / 100})`;
|
|
1532
|
-
return `#${[r, g, b].map((c) => c.toString(16).padStart(2, "0")).join("")}`;
|
|
1533
|
-
}
|
|
1534
|
-
function darkColor(token, role) {
|
|
1535
|
-
const color = parseCssColor(token);
|
|
1536
|
-
if (!color) return token;
|
|
1537
|
-
const lum = luminance2(color);
|
|
1538
|
-
const [h, s] = toHsl2(color);
|
|
1539
|
-
if (role === "surface") {
|
|
1540
|
-
return lum > 0.45 ? fromHsl2(h, s * 0.5, 0.07 + (1 - lum) * 0.35, color.a) : token;
|
|
1541
|
-
}
|
|
1542
|
-
return lum < 0.3 ? fromHsl2(h, s * 0.7, 0.91 - lum * 0.5, color.a) : token;
|
|
1543
|
-
}
|
|
1544
|
-
var COLOR_TOKEN = new RegExp(`url\\([^)]*\\)|(#[0-9a-f]{3,8}\\b|rgba?\\([^)]*\\)|\\b(?:${Object.keys(NAMED).join("|")})\\b)`, "gi");
|
|
1545
|
-
var COLOR_PROPERTY = /(^|[;{\s])(color|background(?:-color)?|border(?:-(?:top|right|bottom|left))?(?:-color)?|outline(?:-color)?)(\s*:\s*)([^;}]*)/gi;
|
|
1546
|
-
function darkCss(css) {
|
|
1547
|
-
return css.replace(COLOR_PROPERTY, (_, before, property, colon, value) => {
|
|
1548
|
-
const role = property.toLowerCase() === "color" ? "text" : "surface";
|
|
1549
|
-
const changed = value.replace(
|
|
1550
|
-
COLOR_TOKEN,
|
|
1551
|
-
(whole, color) => color ? darkColor(color, role) : whole
|
|
1552
|
-
);
|
|
1553
|
-
return `${before}${property}${colon}${changed}`;
|
|
1554
|
-
});
|
|
1555
|
-
}
|
|
1556
|
-
var DARK_SHEET = `<style data-eb-dark>:root{color-scheme:dark}html,body{background-color:${DARK_PAGE};color:${DARK_TEXT}}</style>`;
|
|
1557
|
-
function simulateDarkMode(html) {
|
|
1558
|
-
if (!html) return "";
|
|
1559
|
-
const recolored = String(html).replace(/(<style\b[^>]*>)([\s\S]*?)(<\/style>)/gi, (_, open, css, close) => open + darkCss(css) + close).replace(/(\sstyle\s*=\s*)(["'])([\s\S]*?)\2/gi, (_, attr, quote, css) => attr + quote + darkCss(css) + quote).replace(/(\sbgcolor\s*=\s*)(["']?)([#\w]+)\2/gi, (_, attr, quote, color) => attr + quote + darkColor(color, "surface") + quote);
|
|
1560
|
-
return /<head\b[^>]*>/i.test(recolored) ? recolored.replace(/<head\b[^>]*>/i, (head) => head + DARK_SHEET) : DARK_SHEET + recolored;
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
1276
|
// src/renderer/links.js
|
|
1564
1277
|
var UNSUBSCRIBE = /\{\{\s*unsubscribe\s*\}\}|\[UNSUBSCRIBE\]/gi;
|
|
1565
1278
|
var MIRROR = /\{\{\s*mirror\s*\}\}/gi;
|
|
@@ -1585,40 +1298,11 @@ function applyServiceLinks(html, { unsubscribeUrl }) {
|
|
|
1585
1298
|
return String(html || "").replace(UNSUBSCRIBE, () => escapeAttribute(unsubscribeUrl)).replace(MIRROR, "#");
|
|
1586
1299
|
}
|
|
1587
1300
|
|
|
1588
|
-
// src/validation/images.js
|
|
1589
|
-
var MAX_IMAGE_BYTES = 2 * 1024 * 1024;
|
|
1590
|
-
var IMAGE_TYPES = { "image/png": "png", "image/jpeg": "jpg", "image/gif": "gif" };
|
|
1591
|
-
var ASSET_KEY_PATTERN = /^[a-f0-9]{32}\.(png|jpg|gif)$/;
|
|
1592
|
-
var SIGNATURES = [
|
|
1593
|
-
{ type: "image/png", bytes: [137, 80, 78, 71, 13, 10, 26, 10] },
|
|
1594
|
-
{ type: "image/jpeg", bytes: [255, 216, 255] },
|
|
1595
|
-
{ type: "image/gif", bytes: [71, 73, 70, 56] }
|
|
1596
|
-
];
|
|
1597
|
-
function detectImage(bytes) {
|
|
1598
|
-
if (!bytes || bytes.length < 8) return null;
|
|
1599
|
-
const found = SIGNATURES.find((s) => s.bytes.every((b, i) => bytes[i] === b));
|
|
1600
|
-
return found ? { type: found.type, ext: IMAGE_TYPES[found.type] } : null;
|
|
1601
|
-
}
|
|
1602
|
-
function imageUploadError(file, { t = identity } = {}) {
|
|
1603
|
-
if (!(String(file?.type || "") in IMAGE_TYPES)) return t("Format rejected: PNG, JPEG or GIF expected");
|
|
1604
|
-
if (Number(file?.size || 0) > MAX_IMAGE_BYTES) {
|
|
1605
|
-
return t("Image too large: {max} MB maximum", { max: MAX_IMAGE_BYTES / (1024 * 1024) });
|
|
1606
|
-
}
|
|
1607
|
-
return null;
|
|
1608
|
-
}
|
|
1609
|
-
|
|
1610
1301
|
export {
|
|
1611
|
-
EMAIL_BUILDER_VERSION,
|
|
1612
|
-
EMAIL_DOCUMENT_SCHEMA_VERSION,
|
|
1613
|
-
EMAIL_DEVICES,
|
|
1614
|
-
EMAIL_MOBILE_WIDTH,
|
|
1615
|
-
EmailDocumentError,
|
|
1616
|
-
createDocument,
|
|
1617
|
-
readDocument,
|
|
1618
|
-
serializeDocument,
|
|
1619
1302
|
LOCALES,
|
|
1620
1303
|
createTranslator,
|
|
1621
1304
|
translatorFor,
|
|
1305
|
+
messagesOf,
|
|
1622
1306
|
identity,
|
|
1623
1307
|
escapeXml,
|
|
1624
1308
|
PALETTE,
|
|
@@ -1667,16 +1351,9 @@ export {
|
|
|
1667
1351
|
defineVariables,
|
|
1668
1352
|
validateCustomVariable,
|
|
1669
1353
|
mergeVariables,
|
|
1670
|
-
DARK_PAGE,
|
|
1671
|
-
simulateDarkMode,
|
|
1672
1354
|
DEFAULT_ASSETS_PATH,
|
|
1673
1355
|
isAssetPath,
|
|
1674
1356
|
absoluteAssetUrls,
|
|
1675
|
-
applyServiceLinks
|
|
1676
|
-
MAX_IMAGE_BYTES,
|
|
1677
|
-
IMAGE_TYPES,
|
|
1678
|
-
ASSET_KEY_PATTERN,
|
|
1679
|
-
detectImage,
|
|
1680
|
-
imageUploadError
|
|
1357
|
+
applyServiceLinks
|
|
1681
1358
|
};
|
|
1682
|
-
//# sourceMappingURL=chunk-
|
|
1359
|
+
//# sourceMappingURL=chunk-DFNHICTF.js.map
|