From 4a318413bb85a1db2037fef74b7e6c1ed645cb4c Mon Sep 17 00:00:00 2001 From: Jimmy Vo Date: Thu, 12 Feb 2026 17:23:56 -0500 Subject: [PATCH] [PM-30610] Break shared components into AC versions --- src/Core/MailTemplates/Mjml/.mjmlconfig | 5 +- .../AdminConsole/components/mj-bw-ac-hero.js | 92 ++++++++++++++++ .../components/mj-bw-ac-icon-row.js | 103 ++++++++++++++++++ .../components/mj-bw-ac-learn-more-footer.js | 55 ++++++++++ 4 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 src/Core/MailTemplates/Mjml/emails/AdminConsole/components/mj-bw-ac-hero.js create mode 100644 src/Core/MailTemplates/Mjml/emails/AdminConsole/components/mj-bw-ac-icon-row.js create mode 100644 src/Core/MailTemplates/Mjml/emails/AdminConsole/components/mj-bw-ac-learn-more-footer.js diff --git a/src/Core/MailTemplates/Mjml/.mjmlconfig b/src/Core/MailTemplates/Mjml/.mjmlconfig index a71e3b5ee9..caff8a7d40 100644 --- a/src/Core/MailTemplates/Mjml/.mjmlconfig +++ b/src/Core/MailTemplates/Mjml/.mjmlconfig @@ -4,6 +4,9 @@ "components/mj-bw-simple-hero", "components/mj-bw-icon-row", "components/mj-bw-learn-more-footer", - "emails/AdminConsole/components/mj-bw-inviter-info" + "emails/AdminConsole/components/mj-bw-inviter-info", + "emails/AdminConsole/components/mj-bw-ac-hero", + "emails/AdminConsole/components/mj-bw-ac-icon-row", + "emails/AdminConsole/components/mj-bw-ac-learn-more-footer" ] } diff --git a/src/Core/MailTemplates/Mjml/emails/AdminConsole/components/mj-bw-ac-hero.js b/src/Core/MailTemplates/Mjml/emails/AdminConsole/components/mj-bw-ac-hero.js new file mode 100644 index 0000000000..a8c5158982 --- /dev/null +++ b/src/Core/MailTemplates/Mjml/emails/AdminConsole/components/mj-bw-ac-hero.js @@ -0,0 +1,92 @@ +const { BodyComponent } = require("mjml-core"); +class MjBwAcHero extends BodyComponent { + static dependencies = { + // Tell the validator which tags are allowed as our component's parent + "mj-column": ["mj-bw-ac-hero"], + "mj-wrapper": ["mj-bw-ac-hero"], + // Tell the validator which tags are allowed as our component's children + "mj-bw-ac-hero": [], + }; + + static allowedAttributes = { + "img-src": "string", // REQUIRED: Source for the image displayed in the right-hand side of the blue header area + title: "string", // REQUIRED: large text stating primary purpose of the email + "button-text": "string", // OPTIONAL: text to display in the button + "button-url": "string", // OPTIONAL: URL to navigate to when the button is clicked + "sub-title": "string", // OPTIONAL: smaller text providing additional context for the title + }; + + static defaultAttributes = {}; + + componentHeadStyle = breakpoint => { + return ` + @media only screen and (max-width:${breakpoint}) { + .mj-bw-ac-hero-responsive-img { + display: none !important; + } + } + ` + } + + render() { + const buttonElement = this.getAttribute("button-text") && this.getAttribute("button-url") ? + ` + ${this.getAttribute("button-text")} + ` : ""; + const subTitleElement = this.getAttribute("sub-title") ? + ` +

+ ${this.getAttribute("sub-title")} +

+
` : ""; + + return this.renderMJML( + ` + + + + +

+ ${this.getAttribute("title")} +

+ ` + + subTitleElement + + ` +
` + + buttonElement + + ` +
+ + + +
+ `, + ); + } +} + +module.exports = MjBwAcHero; \ No newline at end of file diff --git a/src/Core/MailTemplates/Mjml/emails/AdminConsole/components/mj-bw-ac-icon-row.js b/src/Core/MailTemplates/Mjml/emails/AdminConsole/components/mj-bw-ac-icon-row.js new file mode 100644 index 0000000000..8d3ac80a2a --- /dev/null +++ b/src/Core/MailTemplates/Mjml/emails/AdminConsole/components/mj-bw-ac-icon-row.js @@ -0,0 +1,103 @@ +const { BodyComponent } = require("mjml-core"); + +const BODY_TEXT_STYLES = ` + font-family="'Helvetica Neue', Helvetica, Arial, sans-serif" + font-size="16px" + font-weight="400" + line-height="24px" +`; + +class MjBwAcIconRow extends BodyComponent { + static dependencies = { + "mj-column": ["mj-bw-ac-icon-row"], + "mj-wrapper": ["mj-bw-ac-icon-row"], + "mj-bw-ac-icon-row": [], + }; + + static allowedAttributes = { + "icon-src": "string", + "icon-alt": "string", + "head-url-text": "string", + "head-url": "string", + text: "string", + "foot-url-text": "string", + "foot-url": "string", + }; + + static defaultAttributes = {}; + + headStyle = (breakpoint) => { + return ` + @media only screen and (max-width:${breakpoint}) { + .mj-bw-ac-icon-row-text { + padding-left: 15px !important; + padding-right: 15px !important; + line-height: 20px; + } + .mj-bw-ac-icon-row-icon { + display: none !important; + width: 0 !important; + max-width: 0 !important; + } + .mj-bw-ac-icon-row-text-column { + width: 100% !important; + } + } + `; + }; + + render() { + const headAnchorElement = + this.getAttribute("head-url-text") && this.getAttribute("head-url") + ? ` + + + ${this.getAttribute("head-url-text")} + + External Link Icon + + + ` + : ""; + + const footAnchorElement = + this.getAttribute("foot-url-text") && this.getAttribute("foot-url") + ? ` + + ${this.getAttribute("foot-url-text")} + + ` + : ""; + + return this.renderMJML( + ` + + + + + + + ${headAnchorElement} + + ${this.getAttribute("text")} + + ${footAnchorElement} + + + + `, + ); + } +} + +module.exports = MjBwAcIconRow; \ No newline at end of file diff --git a/src/Core/MailTemplates/Mjml/emails/AdminConsole/components/mj-bw-ac-learn-more-footer.js b/src/Core/MailTemplates/Mjml/emails/AdminConsole/components/mj-bw-ac-learn-more-footer.js new file mode 100644 index 0000000000..273328804a --- /dev/null +++ b/src/Core/MailTemplates/Mjml/emails/AdminConsole/components/mj-bw-ac-learn-more-footer.js @@ -0,0 +1,55 @@ +const { BodyComponent } = require("mjml-core"); +class MjBwAcLearnMoreFooter extends BodyComponent { + static dependencies = { + // Tell the validator which tags are allowed as our component's parent + "mj-column": ["mj-bw-ac-learn-more-footer"], + "mj-wrapper": ["mj-bw-ac-learn-more-footer"], + // Tell the validator which tags are allowed as our component's children + "mj-bw-ac-learn-more-footer": [], + }; + + static allowedAttributes = {}; + + static defaultAttributes = {}; + + componentHeadStyle = (breakpoint) => { + return ` + @media only screen and (max-width:${breakpoint}) { + .mj-bw-ac-learn-more-footer-responsive-img { + display: none !important; + } + } + `; + }; + + render() { + return this.renderMJML( + ` + + + +

+ Learn more about Bitwarden +

+

+ Find user guides, product documentation, and videos on the + Bitwarden Help Center. +

+
+
+ + + +
+ `, + ); + } +} + +module.exports = MjBwAcLearnMoreFooter; \ No newline at end of file