, , etc.)
24 | */
25 |
26 | {% include './elements/_typography.css' %}
27 | {% include './elements/_buttons.css' %}
28 | {% include './elements/_forms.css' %}
29 | {% include './elements/_tables.css' %}
30 |
31 | /* Components
32 | Specific pieces of UI that are stylized. Typically used for global partial styling
33 | */
34 |
35 | {% include './components/_header.css' %}
36 | {% include './components/_default-modules.css' %}
37 |
38 | /* Utilities
39 | Helper classes with ability to override anything that comes before it
40 | */
41 |
42 | {% include './utilities/_helper.css' %}
43 |
--------------------------------------------------------------------------------
/src/templates/about.html:
--------------------------------------------------------------------------------
1 |
7 | {% extends "./layouts/base.html" %}
8 |
9 | {% block body %}
10 | {% dnd_area "dnd_area"
11 | label="Main section",
12 | class="body-container body-container--about"
13 | %}
14 |
15 | {# Two column image left #}
16 |
17 | {% dnd_section
18 | vertical_alignment="TOP"
19 | %}
20 | {% dnd_module
21 | path="@hubspot/linked_image",
22 | img={
23 | "alt": "Coworkers sitting together and smiling outside.",
24 | "loading": "disabled",
25 | "max_height": 449,
26 | "max_width": 605,
27 | "size_type": "auto_custom_max",
28 | "src": get_asset_url("../images/team-image.jpg")
29 | },
30 | offset=0,
31 | width=6
32 | %}
33 | {% end_dnd_module %}
34 | {% dnd_module
35 | path="@hubspot/rich_text",
36 | html="Meet our team Use this page to help your visitors learn more about you. Include images so that folks will recognize you at conferences and events.
"
37 | offset=6,
38 | width=6
39 | %}
40 | {% end_dnd_module %}
41 | {% end_dnd_section %}
42 |
43 | {% end_dnd_area %}
44 | {% endblock body %}
45 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: feature request
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
12 | **Is your feature request related to a problem? Please describe.**
13 |
14 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
15 |
16 | **Describe the solution you'd like**
17 |
18 | A clear and concise description of what you want to happen.
19 |
20 | **Screenshots/source code/links**
21 |
22 | Add any images, code, or example links that would be relevant in explaining the feature.
23 |
24 | **Additional context**
25 |
26 | Add any other context about the feature request here.
27 |
28 | **Checklist**
29 |
30 | - [ ] I have read the [CONTRIBUTING](https://github.com/HubSpot/cms-theme-boilerplate/blob/master/CONTRIBUTING.md) document.
31 | - [ ] I have checked the [issue tracker](https://github.com/HubSpot/cms-theme-boilerplate/issues) to make sure there isn’t already an open issue.
--------------------------------------------------------------------------------
/src/templates/partials/footer.html:
--------------------------------------------------------------------------------
1 |
5 |
44 |
--------------------------------------------------------------------------------
/src/css/tools/_macros.css:
--------------------------------------------------------------------------------
1 | {###########################################################################}
2 | {######################## HubSpot Helper Macros ########################}
3 | {###########################################################################}
4 |
5 | {## Table of contents:
6 |
7 | 1. Color Field CSS Mapper
8 |
9 | ##}
10 |
11 | {% set macros = true %}
12 |
13 | {###########################################################################}
14 | {######################## Color Field CSS Mapper #######################}
15 | {###########################################################################}
16 |
17 | {#
18 |
19 | Creation of an rgba value that maps from a color field
20 |
21 | Usage:
22 |
23 | * Inside CSS block for an element, call macro using the base name for the color field in your fields.json file
24 | * The macro checks to see if opacity has a set value and uses '1' as a fallback should the parameter be hidden or unset.
25 |
26 | Example:
27 |
28 | .my-selector {
29 | color: {{ color('theme.color_field_name') }}
30 | }
31 |
32 | #}
33 |
34 | {% macro color(value) %}
35 |
36 | {% set colorhex = value.color|convert_rgb %}
37 | {% if value.opacity != null %}
38 | {% set coloropacity = value.opacity / 100 %}
39 | {% else %}
40 | {% set coloropacity = '1' %}
41 | {% endif %}
42 |
43 |
44 | rgba({{ colorhex }}, {{ coloropacity }})
45 |
46 | {% endmacro %}
--------------------------------------------------------------------------------
/src/templates/system/membership-reset-password.html:
--------------------------------------------------------------------------------
1 |
7 | {% set template_css = "../../css/templates/system.css" %}
8 | {% extends "../layouts/base.html" %}
9 | {# pageTitle is used on system templates for setting a value for the title tag #}
10 | {% set pageTitle = "Membership | Reset password" %}
11 |
12 | {% block header %}
13 | {% endblock %}
14 |
15 | {% block body %}
16 |
17 |
18 | {% module "content"
19 | path="@hubspot/rich_text",
20 | html="
Reset your password Enter a new password.
"
21 | %}
22 |
23 | {% password_reset "my_password_reset"
24 | password_confirm_label="Confirm Password",
25 | password_label="Password",
26 | submit_button_text= "Save Password"
27 | %}
28 |
29 |
30 | {% module_block module "membership_admin_content"
31 | label="Contact admin",
32 | path="@hubspot/rich_text"
33 | %}
34 | {% module_attribute "html" %}
35 |
Having trouble? Contact the admin .
36 | {% end_module_attribute %}
37 | {% end_module_block %}
38 |
39 |
40 |
41 | {% endblock %}
42 |
--------------------------------------------------------------------------------
/src/sections/hero-banner.html:
--------------------------------------------------------------------------------
1 |
8 | {% dnd_section
9 | background_color={{ context.background_color or "#f8fafc" }},
10 | vertical_alignment="MIDDLE"
11 | %}
12 | {% dnd_module
13 | path="@hubspot/linked_image",
14 | img={
15 | "alt": context.image_alt or "Stock placeholder image with grayscale geometrical mountain landscape",
16 | "loading": context.image_loading or "disabled",
17 | "max_height": context.image_height or 451,
18 | "max_width": context.image_width or 605,
19 | "size_type": "auto_custom_max",
20 | "src": context.image or get_asset_url("../images/grayscale-mountain.png")
21 | },
22 | offset=0,
23 | width=6
24 | %}
25 | {% end_dnd_module %}
26 | {% dnd_column
27 | offset=6,
28 | width=6
29 | %}
30 | {% dnd_row %}
31 | {% dnd_module
32 | path="@hubspot/rich_text"
33 | html={{ context.content or "This is your main headline. Use this space to tell everyone about what you have to offer.
" }}
34 | %}
35 | {% end_dnd_module %}
36 | {% end_dnd_row %}
37 | {% dnd_row %}
38 | {% dnd_module path="@hubspot/form" %}
39 | {% end_dnd_module %}
40 | {% end_dnd_row %}
41 | {% end_dnd_column %}
42 | {% end_dnd_section %}
43 |
--------------------------------------------------------------------------------
/src/templates/system/membership-reset-password-request.html:
--------------------------------------------------------------------------------
1 |
7 | {% set template_css = "../../css/templates/system.css" %}
8 | {% extends "../layouts/base.html" %}
9 | {# pageTitle is used on system templates for setting a value for the title tag #}
10 | {% set pageTitle = "Membership | Reset password request" %}
11 |
12 | {% block header %}
13 | {% endblock %}
14 |
15 | {% block body %}
16 |
17 |
18 | {% module "content"
19 | path="@hubspot/rich_text",
20 | html="
Reset your password What email address should we send a password reset email to?
"
21 | %}
22 |
23 | {% password_reset_request "my_password_reset_request"
24 | email_label="Email",
25 | submit_button_text="Send Reset Email"
26 | %}
27 |
28 |
29 | {% module_block module "membership_admin_content"
30 | label="Contact admin",
31 | path="@hubspot/rich_text"
32 | %}
33 | {% module_attribute "html" %}
34 |
Having trouble? Contact the admin .
35 | {% end_module_attribute %}
36 | {% end_module_block %}
37 |
38 |
39 |
40 | {% endblock %}
41 |
--------------------------------------------------------------------------------
/src/templates/system/membership-register.html:
--------------------------------------------------------------------------------
1 |
7 | {% set template_css = "../../css/templates/system.css" %}
8 | {% extends "../layouts/base.html" %}
9 | {# pageTitle is used on system templates for setting a value for the title tag #}
10 | {% set pageTitle = "Membership | Register" %}
11 |
12 | {% block header %}
13 | {% endblock %}
14 |
15 | {% block body %}
16 |
17 |
18 | {% module "content"
19 | path="@hubspot/rich_text",
20 | html="
Welcome! Set up your password to sign in and see the content you now have access to.
"
21 | %}
22 |
23 | {% member_register "my_register"
24 | email_label="Email",
25 | password_confirm_label="Confirm Password",
26 | password_label="Password",
27 | submit_button_text="Save Password"
28 | %}
29 |
30 |
31 | {% module_block module "membership_admin_content"
32 | label="Contact admin",
33 | path="@hubspot/rich_text"
34 | %}
35 | {% module_attribute "html" %}
36 |
Having trouble? Contact the admin .
37 | {% end_module_attribute %}
38 | {% end_module_block %}
39 |
40 |
41 |
42 | {% endblock %}
43 |
--------------------------------------------------------------------------------
/src/templates/system/membership-login.html:
--------------------------------------------------------------------------------
1 |
7 | {% set template_css = "../../css/templates/system.css" %}
8 | {% extends "../layouts/base.html" %}
9 | {# pageTitle is used on system templates for setting a value for the title tag #}
10 | {% set pageTitle = "Membership | Login" %}
11 |
12 | {% block header %}
13 | {% endblock %}
14 |
15 | {% block body %}
16 |
17 |
18 | {% module "content"
19 | path="@hubspot/rich_text",
20 | html="
Sign in to view this page This page is only available to people who have been given access.
"
21 | %}
22 |
23 | {% member_login "my_login"
24 | email_label= "Email",
25 | password_label= "Password",
26 | remember_me_label= "Remember Me",
27 | reset_password_text= "Forgot your password?",
28 | submit_button_text= "Login"
29 | %}
30 |
31 |
32 | {% module_block module "membership_admin_content"
33 | label="Contact admin",
34 | path="@hubspot/rich_text"
35 | %}
36 | {% module_attribute "html" %}
37 |
Having trouble? Contact the admin .
38 | {% end_module_attribute %}
39 | {% end_module_block %}
40 |
41 |
42 |
43 | {% endblock %}
44 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
12 | **Description**
13 |
14 | A clear and concise description of what the bug is.
15 |
16 | **Expected behavior**
17 |
18 | A clear and concise description of what you expected to happen.
19 |
20 | **To Reproduce**
21 |
22 | Steps to reproduce the behavior:
23 | 1. Go to '...'
24 | 2. Click on '....'
25 | 3. Scroll down to '....'
26 | 4. See error
27 |
28 | **Screenshots/source code**
29 |
30 | If applicable, add screenshots or source code to help explain your problem.
31 |
32 | **Device information**
33 |
34 |
35 | Device: [e.g. iPhone6]
36 | OS: [e.g. iOS8.1]
37 | Browser: [e.g. stock browser, safari]
38 | Browser Version: [e.g. 22]
39 |
40 | **Additional context**
41 |
42 | Add any other context about the problem here.
43 |
44 | **Checklist**
45 |
46 | - [ ] I have read the [CONTRIBUTING](https://github.com/HubSpot/cms-theme-boilerplate/blob/master/CONTRIBUTING.md) document.
47 | - [ ] I have checked the [issue tracker](https://github.com/HubSpot/cms-theme-boilerplate/issues) to make sure there isn’t already an open issue.
--------------------------------------------------------------------------------
/src/templates/system/search-results.html:
--------------------------------------------------------------------------------
1 |
7 | {% set template_css = "../../css/templates/system.css" %}
8 | {% extends "../layouts/base.html" %}
9 | {# pageTitle is used on system templates for setting a value for the title tag #}
10 | {% set pageTitle = "Search results" %}
11 |
12 | {% block body %}
13 |
14 |
15 | {%- if (get_asset_version("@hubspot/search_results") == 0) -%}
16 | {% if request.query_dict.term %}
17 | {% set search_query = request.query_dict.term %}
18 | {% elif request.query_dict.q %}
19 | {# v3 search api support #}
20 | {% set search_query = request.query_dict.q %}
21 | {% endif %}
22 |
23 | {% module_block module 'search_results_content'
24 | label='Search results heading',
25 | path='@hubspot/rich_text'
26 | %}
27 | {% module_attribute 'html' %}
28 |
Results for “{{ search_query|escape_html }}”
29 | {% end_module_attribute %}
30 | {% end_module_block %}
31 |
32 | {% module "search_results"
33 | path="@hubspot/search_results"
34 | %}
35 |
36 | {%- else -%}
37 |
38 | {% module "search_results"
39 | path="@hubspot/search_results",
40 | title={
41 | "show_title": "true"
42 | }
43 | %}
44 |
45 | {%- endif -%}
46 |
47 |
48 | {% endblock body %}
49 |
--------------------------------------------------------------------------------
/src/css/templates/blog.css:
--------------------------------------------------------------------------------
1 | /* Blog post */
2 |
3 | .blog-post {
4 | margin: 0 auto;
5 | max-width: 960px;
6 | }
7 |
8 | .blog-post__meta {
9 | margin-bottom: 1.4rem;
10 | }
11 |
12 | .blog-post__meta a {
13 | text-decoration: underline;
14 | }
15 |
16 | .blog-post__timestamp {
17 | display: block;
18 | }
19 |
20 | .blog-post__tags svg {
21 | height: auto;
22 | margin-right: 0.35rem;
23 | width: 15px;
24 | }
25 |
26 | .blog-post__tag-link {
27 | font-size: 0.875rem;
28 | }
29 |
30 | /* Blog related posts */
31 |
32 | .blog-related-posts {
33 | background-color: #F8FAFC;
34 | }
35 |
36 | .blog-related-posts h2 {
37 | text-align: center;
38 | }
39 |
40 | .blog-related-posts__list {
41 | display: flex;
42 | flex-wrap: wrap;
43 | }
44 |
45 | .blog-related-posts__post {
46 | flex: 0 0 100%;
47 | padding: 1rem;
48 | }
49 |
50 | @media screen and (min-width: 768px) {
51 | .blog-related-posts__post {
52 | flex: 0 0 calc(100% / 2);
53 | }
54 | }
55 |
56 | @media screen and (min-width: 1000px) {
57 | .blog-related-posts__post {
58 | flex: 0 0 calc(100% / 3);
59 | }
60 | }
61 |
62 | .blog-related-posts__image {
63 | height: auto;
64 | max-width: 100%;
65 | }
66 |
67 | .blog-related-posts__title {
68 | margin: 0.7rem 0;
69 | }
70 |
71 | /* Blog comments */
72 |
73 | .blog-comments {
74 | margin: 0 auto;
75 | max-width: 680px;
76 | }
77 |
78 | .blog-comments .hs-submit {
79 | text-align: center;
80 | }
81 |
82 | .blog-comments .comment-reply-to {
83 | border: 0 none;
84 | }
85 |
86 | .blog-comments .comment-reply-to:hover,
87 | .blog-comments .comment-reply-to:focus {
88 | background-color: transparent;
89 | text-decoration: underline;
90 | }
91 |
--------------------------------------------------------------------------------
/src/css/elements/_typography.css:
--------------------------------------------------------------------------------
1 | /* The overflow-wrap is meant to prevent long/large words from breaking the mobile responsiveness of a page (e.g. horizontal scrolling). It is preferred to reduce font sizes on mobile to address this, with this CSS specifically helping with extreme scenarios where a reduction in font size is not possible. */
2 |
3 | body {
4 | line-height: 1.4;
5 | overflow-wrap: break-word;
6 | }
7 |
8 | /* Handles word breaking for a few specific languages which handle breaks in words differently. If your content is not translated into these languages, you can safely remove this. */
9 |
10 | html[lang^="ja"] body,
11 | html[lang^="zh"] body,
12 | html[lang^="ko"] body {
13 | line-break: strict;
14 | overflow-wrap: normal;
15 | word-break: break-all;
16 | }
17 |
18 | /* Paragraphs */
19 |
20 | p {
21 | font-size: 1rem;
22 | margin: 0 0 1.4rem;
23 | }
24 |
25 | /* Anchors */
26 |
27 | a {
28 | cursor: pointer;
29 | }
30 |
31 | /* Headings */
32 |
33 | h1,
34 | h2,
35 | h3,
36 | h4,
37 | h5,
38 | h6 {
39 | margin: 0 0 1.4rem;
40 | }
41 |
42 | /* Lists */
43 |
44 | ul,
45 | ol {
46 | margin: 0 0 1.4rem;
47 | }
48 |
49 | ul ul,
50 | ol ul,
51 | ul ol,
52 | ol ol {
53 | margin: 0;
54 | }
55 |
56 | ul.no-list {
57 | list-style: none;
58 | margin: 0;
59 | padding-left: 0;
60 | }
61 |
62 | /* Code blocks */
63 |
64 | pre {
65 | overflow: auto;
66 | }
67 |
68 | code {
69 | vertical-align: bottom;
70 | }
71 |
72 | /* Blockquotes */
73 |
74 | blockquote {
75 | border-left: 2px solid;
76 | margin: 0 0 1.4rem;
77 | padding-left: 0.7rem;
78 | }
79 |
80 | /* Horizontal rules */
81 |
82 | hr {
83 | border: none;
84 | border-bottom: 1px solid #CCC;
85 | }
86 |
87 | /* Image alt text */
88 |
89 | img {
90 | font-size: 0.583rem;
91 | word-break: normal;
92 | }
93 |
--------------------------------------------------------------------------------
/src/templates/blog-index.html:
--------------------------------------------------------------------------------
1 |
7 | {% set template_css = "../../css/templates/blog.css" %}
8 | {% extends "./layouts/base.html" %}
9 |
10 | {% block body %}
11 | {% dnd_area "dnd_area"
12 | label="Main section",
13 | class="body-container body-container--blog-index"
14 | %}
15 |
16 | {# Hero banner #}
17 |
18 | {% dnd_section
19 | background_color="#f8fafc",
20 | max_width=600,
21 | padding={
22 | "default": {
23 | "top": 80,
24 | "right": 0,
25 | "bottom": 80,
26 | "left": 0
27 | },
28 | "mobile": {
29 | "top": 80,
30 | "right": 20,
31 | "bottom": 80,
32 | "left": 20
33 | }
34 | }
35 | %}
36 | {% dnd_column %}
37 | {% dnd_row %}
38 | {% dnd_module
39 | path="@hubspot/rich_text",
40 | html='Blog Use this space to tell everyone about what you have to offer.
'
41 | %}
42 | {% end_dnd_module %}
43 | {% end_dnd_row %}
44 | {% dnd_row %}
45 | {% dnd_module
46 | path="@hubspot/blog_subscribe",
47 | title=""
48 | %}
49 | {% end_dnd_module %}
50 | {% end_dnd_row %}
51 | {% end_dnd_column %}
52 | {% end_dnd_section %}
53 |
54 | {# Blog listings and pagination #}
55 |
56 | {% dnd_section
57 | vertical_alignment="TOP"
58 | %}
59 | {% dnd_column %}
60 | {% dnd_row %}
61 | {% dnd_module path="@hubspot/blog_posts" %}
62 | {% end_dnd_module %}
63 | {% end_dnd_row %}
64 | {% dnd_row %}
65 | {% dnd_module path="@hubspot/pagination" %}
66 | {% end_dnd_module %}
67 | {% end_dnd_row %}
68 | {% end_dnd_column %}
69 | {% end_dnd_section %}
70 |
71 | {% end_dnd_area %}
72 | {% endblock body %}
73 |
--------------------------------------------------------------------------------
/src/sections/call-to-action.html:
--------------------------------------------------------------------------------
1 |
8 | {% dnd_section
9 | background_image={
10 | "backgroundPosition": "MIDDLE_CENTER",
11 | "backgroundSize": "cover",
12 | "imageUrl": context.background_image or get_asset_url("../images/large-placeholder-image.png")
13 | },
14 | max_width={{ context.max_width or 700 }},
15 | padding={
16 | "default": {
17 | "top": 140,
18 | "right": 20,
19 | "bottom": 160,
20 | "left": 20
21 | },
22 | "mobile": {
23 | "top": 80,
24 | "right": 20,
25 | "bottom": 80,
26 | "left": 20
27 | }
28 | },
29 | vertical_alignment="MIDDLE"
30 | %}
31 | {% dnd_column %}
32 | {% dnd_row
33 | padding={
34 | "default": {
35 | "top": 0,
36 | "right": 0,
37 | "bottom": 40,
38 | "left": 0
39 | },
40 | "mobile": {
41 | "top": 0,
42 | "right": 0,
43 | "bottom": 0,
44 | "left": 0
45 | }
46 | }
47 | %}
48 | {% dnd_module
49 | path="@hubspot/rich_text",
50 | html={{ context.content or 'Provide an excerpt here Use text and images to tell your company’s story. Explain what makes your product or service extraordinary.
' }}
51 | %}
52 | {% end_dnd_module %}
53 | {% end_dnd_row %}
54 | {% dnd_row %}
55 | {% dnd_module
56 | path="../modules/button",
57 | button_text={{ context.button_text or "Get started" }},
58 | styles={
59 | "alignment": {
60 | "alignment": {
61 | "horizontal_align": "CENTER"
62 | }
63 | }
64 | }
65 | %}
66 | {% end_dnd_module %}
67 | {% end_dnd_row %}
68 | {% end_dnd_column %}
69 | {% end_dnd_section %}
70 |
--------------------------------------------------------------------------------
/src/templates/home.html:
--------------------------------------------------------------------------------
1 |
7 | {% extends "./layouts/base.html" %}
8 |
9 | {% block body %}
10 |
11 | {# All templates are recommended to have an h1 present for both accessibility and SEO best practice. This should be at the top of the template before any other textual content. The h1 element below is within a dnd area to allow content editors the ability to adjust the content and alignment of the text. #}
12 |
13 | {% dnd_area "dnd_area"
14 | label="Main section",
15 | class="body-container body-container--home"
16 | %}
17 |
18 | {# Hero banner #}
19 |
20 | {% include_dnd_partial path="../sections/hero-banner.html" %}
21 |
22 | {# Two column image right #}
23 |
24 | {% include_dnd_partial path="../sections/multi-row-content.html" %}
25 |
26 | {# Two column image left #}
27 |
28 | {% dnd_section
29 | background_color="#f8fafc",
30 | vertical_alignment="MIDDLE"
31 | %}
32 | {% dnd_module
33 | path="@hubspot/linked_image",
34 | img={
35 | "alt": "Stock placeholder image with grayscale geometrical mountain landscape",
36 | "loading": "lazy",
37 | "max_height": 451,
38 | "max_width": 605,
39 | "size_type": "auto_custom_max",
40 | "src": get_asset_url("../images/grayscale-mountain.png")
41 | },
42 | offset=0,
43 | width=6
44 | %}
45 | {% end_dnd_module %}
46 | {% dnd_module
47 | path="@hubspot/rich_text",
48 | html="Provide more details here. Use text and images to tell your company’s story. Explain what makes your product or service extraordinary.
"
49 | offset=6,
50 | width=6
51 | %}
52 | {% end_dnd_module %}
53 | {% end_dnd_section %}
54 |
55 | {# Call to action #}
56 |
57 | {% include_dnd_partial path="../sections/call-to-action.html" %}
58 |
59 | {# Three column image with text #}
60 |
61 | {% include_dnd_partial path="../sections/multi-column-content.html" %}
62 |
63 | {% end_dnd_area %}
64 | {% endblock body %}
65 |
--------------------------------------------------------------------------------
/src/templates/layouts/base.html:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 | {% if page_meta.html_title or pageTitle %}{{ page_meta.html_title or pageTitle }} {% endif %}
9 | {% if brand_settings.favicon.src %} {% endif %}
10 |
11 | {{ require_css(get_asset_url("../../css/main.css")) }}
12 | {# This is intended to be used if a template requires template specific style sheets #}
13 | {% if template_css %}
14 | {{ require_css(get_asset_url(template_css)) }}
15 | {% endif %}
16 | {{ require_css(get_asset_url("../../css/theme-overrides.css")) }}
17 | {# To see a full list of what is included via standard_header_includes please reference this article: https://developers.hubspot.com/docs/cms/hubl/variables#required-page-template-variables #}
18 | {{ standard_header_includes }}
19 |
20 |
21 |
22 | {% block header %}
23 | {% global_partial path="../partials/header.html" %}
24 | {% endblock header %}
25 |
26 | {# The main-content ID is used for the navigation skipper in the header.html file. More information on the navigation skipper can be found here: https://github.com/HubSpot/cms-theme-boilerplate/wiki/Accessibility #}
27 |
28 |
29 | {% block body %}
30 | {% endblock body %}
31 |
32 |
33 | {% block footer %}
34 | {% global_partial path="../partials/footer.html" %}
35 | {% endblock footer %}
36 |
37 | {{ require_js(get_asset_url("../../js/main.js")) }}
38 | {# To see a full list of what is included via standard_footer_includes please reference this article: https://developers.hubspot.com/docs/cms/hubl/variables#required-page-template-variables #}
39 | {{ standard_footer_includes }}
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/css/components/_default-modules.css:
--------------------------------------------------------------------------------
1 | /* Menu and simple menu */
2 |
3 | .hs-menu-wrapper ul {
4 | display: flex;
5 | flex-wrap: wrap;
6 | list-style: none;
7 | margin: 0;
8 | padding-left: 0;
9 | }
10 |
11 | /* Horizontal menu */
12 |
13 | .hs-menu-wrapper.hs-menu-flow-horizontal .hs-menu-children-wrapper {
14 | flex-direction: column;
15 | }
16 |
17 | @media (max-width: 767px) {
18 | .hs-menu-wrapper.hs-menu-flow-horizontal ul {
19 | flex-direction: column;
20 | }
21 | }
22 |
23 | /* Vertical menu */
24 |
25 | .hs-menu-wrapper.hs-menu-flow-vertical ul {
26 | flex-direction: column;
27 | }
28 |
29 | /* Flyouts */
30 |
31 | .hs-menu-wrapper.hs-menu-flow-vertical.flyouts ul {
32 | display: inline-flex;
33 | }
34 |
35 | @media (max-width: 767px) {
36 | .hs-menu-wrapper.hs-menu-flow-vertical ul {
37 | display: flex;
38 | }
39 | }
40 |
41 | .hs-menu-wrapper.flyouts .hs-item-has-children {
42 | position: relative;
43 | }
44 |
45 | .hs-menu-wrapper.flyouts .hs-menu-children-wrapper {
46 | left: -9999px;
47 | opacity: 0;
48 | position: absolute;
49 | }
50 |
51 | .hs-menu-wrapper.flyouts .hs-menu-children-wrapper a {
52 | display: block;
53 | white-space: nowrap;
54 | }
55 |
56 | .hs-menu-wrapper.hs-menu-flow-horizontal.flyouts .hs-item-has-children:hover > .hs-menu-children-wrapper {
57 | left: 0;
58 | opacity: 1;
59 | top: 100%;
60 | }
61 |
62 | .hs-menu-wrapper.hs-menu-flow-vertical.flyouts .hs-item-has-children:hover > .hs-menu-children-wrapper {
63 | left: 100%;
64 | opacity: 1;
65 | top: 0;
66 | }
67 |
68 | @media (max-width: 767px) {
69 | .hs-menu-wrapper.flyouts .hs-menu-children-wrapper,
70 | .hs-menu-wrapper.hs-menu-flow-horizontal.flyouts .hs-item-has-children:hover > .hs-menu-children-wrapper,
71 | .hs-menu-wrapper.hs-menu-flow-vertical.flyouts .hs-item-has-children:hover > .hs-menu-children-wrapper {
72 | left: 0;
73 | opacity: 1;
74 | position: relative;
75 | top: auto;
76 | }
77 | }
78 |
79 | /* CTA, logo, and rich text images */
80 |
81 | .hs_cos_wrapper_type_cta img,
82 | .hs_cos_wrapper_type_logo img,
83 | .hs_cos_wrapper_type_rich_text img {
84 | height: auto;
85 | max-width: 100%;
86 | }
--------------------------------------------------------------------------------
/src/modules/button.module/module.html:
--------------------------------------------------------------------------------
1 | {# Module styles #}
2 |
3 | {% require_css %}
4 |
44 | {% end_require_css %}
45 |
46 | {# Sets attributes used for the link field #}
47 |
48 | {% set href = module.link.url.href %}
49 | {% if module.link.url.type == "EMAIL_ADDRESS" %}
50 | {% set href = "mailto:" + href %}
51 | {% endif %}
52 | {% set rel = [] %}
53 | {% if module.link.no_follow %}
54 | {% do rel.append("nofollow") %}
55 | {% endif %}
56 | {% if module.link.open_in_new_tab %}
57 | {% do rel.append("noopener") %}
58 | {% endif %}
59 |
60 | {# Button #}
61 |
62 |
70 |
--------------------------------------------------------------------------------
/src/modules/menu.module/fields.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "label": "Menu",
4 | "name": "menu",
5 | "type": "menu",
6 | "default": "default"
7 | },
8 | {
9 | "label": "Max levels",
10 | "name": "max_levels",
11 | "type": "number",
12 | "help_text": "Determines the number of menu tree children that can be expanded in the menu",
13 | "display": "text",
14 | "max": 3,
15 | "min": 1,
16 | "step": 1,
17 | "required": true,
18 | "default": 3
19 | },
20 | {
21 | "label": "Styles",
22 | "name": "styles",
23 | "type": "group",
24 | "tab": "STYLE",
25 | "children": [
26 | {
27 | "label": "Text",
28 | "name": "text",
29 | "type": "group",
30 | "children": [
31 | {
32 | "label": "Color",
33 | "name": "color",
34 | "type": "color",
35 | "visibility": {
36 | "hidden_subfields": {
37 | "opacity": true
38 | }
39 | }
40 | }
41 | ]
42 | },
43 | {
44 | "label": "Drop downs",
45 | "name": "drop_downs",
46 | "type": "group",
47 | "children": [
48 | {
49 | "label": "Text",
50 | "name": "text",
51 | "type": "group",
52 | "children": [
53 | {
54 | "label": "Color",
55 | "name": "color",
56 | "type": "color",
57 | "visibility": {
58 | "hidden_subfields": {
59 | "opacity": true
60 | }
61 | }
62 | }
63 | ]
64 | },
65 | {
66 | "label": "Background",
67 | "name": "background",
68 | "type": "group",
69 | "children": [
70 | {
71 | "label": "Color",
72 | "name": "color",
73 | "type": "color"
74 | }
75 | ]
76 | },
77 | {
78 | "label": "Border",
79 | "name": "border",
80 | "type": "group",
81 | "children": [
82 | {
83 | "label" : "Border",
84 | "name" : "border",
85 | "type" : "border"
86 | }
87 | ]
88 | }
89 | ]
90 | }
91 | ]
92 | }
93 | ]
94 |
--------------------------------------------------------------------------------
/src/sections/cards.html:
--------------------------------------------------------------------------------
1 |
8 | {% dnd_section %}
9 | {% dnd_column %}
10 | {% dnd_row %}
11 | {% dnd_module
12 | path="@hubspot/rich_text",
13 | html={{ context.content or '
Contact us ' }}
14 | %}
15 | {% end_dnd_module %}
16 | {% end_dnd_row %}
17 | {% dnd_row %}
18 | {% dnd_module
19 | path="../modules/card",
20 | card=[
21 | {
22 | "image": {
23 | "alt": context.card_one_image_alt or "Phone number",
24 | "loading": context.card_one_image_loading or "disabled",
25 | "max_height": context.card_one_image_height or 230,
26 | "max_width": context.card_one_image_width or 230,
27 | "size_type": "auto_custom_max",
28 | "src": context.card_one_image or get_asset_url("../images/phone.png")
29 | },
30 | "text": context.card_one_content or "(887) 929-0687
"
31 | },
32 | {
33 | "image": {
34 | "alt": context.card_two_image_alt or "Email",
35 | "loading": context.card_two_image_loading or "disabled",
36 | "max_height": context.card_two_image_height or 230,
37 | "max_width": context.card_two_image_width or 230,
38 | "size_type": "auto_custom_max",
39 | "src": context.card_two_image or get_asset_url("../images/email.png")
40 | },
41 | "text": context.card_two_content or "contact@business.com
"
42 | },
43 | {
44 | "image": {
45 | "alt": context.card_three_image_alt or "Address",
46 | "loading": context.card_three_image_loading or "disabled",
47 | "max_height": context.card_three_image_height or 230,
48 | "max_width": context.card_three_image_width or 230,
49 | "size_type": "auto_custom_max",
50 | "src": context.card_three_image or get_asset_url("../images/location.png")
51 | },
52 | "text": context.card_three_content or "2 Canal Park, Cambridge, MA 02141
"
53 | }
54 | ]
55 | %}
56 | {% end_dnd_module %}
57 | {% end_dnd_row %}
58 | {% end_dnd_column %}
59 | {% end_dnd_section %}
60 |
--------------------------------------------------------------------------------
/src/modules/card.module/module.html:
--------------------------------------------------------------------------------
1 | {# Module styles #}
2 |
3 | {% require_css %}
4 |
34 | {% end_require_css %}
35 |
36 | {# Cards #}
37 |
38 |
39 |
40 | {# Loops through each card in the cards repeater #}
41 |
42 | {% for card in module.card %}
43 |
44 | {% if card.image.src %}
45 | {% set sizeAttrs = 'width="{{ card.image.width|escape_attr }}" height="{{ card.image.height|escape_attr }}"' %}
46 | {% if card.image.size_type == "auto" %}
47 | {% set sizeAttrs = 'style="max-width: 100%; height: auto;"' %}
48 | {% elif card.image.size_type == "auto_custom_max" %}
49 | {% set sizeAttrs = 'width="{{ card.image.max_width|escape_attr }}" height="{{ card.image.max_height|escape_attr }}" style="max-width: 100%; max-height: auto;"' %}
50 | {% endif %}
51 | {% set loadingAttr = card.image.loading != "disabled" ? 'loading="{{ card.image.loading }}"' : "" %}
52 | {# loadingAttr, sizeAttrs escaped above #}
53 | {% endif %}
54 | {% if card.text %}
55 |
56 | {{ card.text|sanitize_html }}
57 |
58 | {% endif %}
59 |
60 | {% endfor %}
61 |
62 |
63 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### OSX ###
2 | # General
3 | .DS_Store
4 | .AppleDouble
5 | .LSOverride
6 |
7 | # Icon must end with two \r
8 | Icon
9 |
10 | # Thumbnails
11 | ._*
12 |
13 | # Files that might appear in the root of a volume
14 | .DocumentRevisions-V100
15 | .fseventsd
16 | .Spotlight-V100
17 | .TemporaryItems
18 | .Trashes
19 | .VolumeIcon.icns
20 | .com.apple.timemachine.donotpresent
21 |
22 | # Directories potentially created on remote AFP share
23 | .AppleDB
24 | .AppleDesktop
25 | Network Trash Folder
26 | Temporary Items
27 | .apdisk
28 |
29 | ### Node ###
30 | # .node-version
31 | # Logs
32 | logs
33 | *.log
34 | npm-debug.log*
35 | yarn-debug.log*
36 | yarn-error.log*
37 |
38 | # Runtime data
39 | pids
40 | *.pid
41 | *.seed
42 | *.pid.lock
43 |
44 | # Directory for instrumented libs generated by jscoverage/JSCover
45 | lib-cov
46 |
47 | # Coverage directory used by tools like istanbul
48 | coverage
49 |
50 | # nyc test coverage
51 | .nyc_output
52 |
53 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
54 | .grunt
55 |
56 | # Bower dependency directory (https://bower.io/)
57 | bower_components
58 |
59 | # node-waf configuration
60 | .lock-wscript
61 |
62 | # Compiled binary addons (https://nodejs.org/api/addons.html)
63 | build/Release
64 |
65 | # Dependency directories
66 | node_modules/
67 | jspm_packages/
68 |
69 | # TypeScript v1 declaration files
70 | typings/
71 |
72 | # Optional npm cache directory
73 | .npm
74 |
75 | # Optional eslint cache
76 | .eslintcache
77 |
78 | # Optional REPL history
79 | .node_repl_history
80 |
81 | # Output of 'npm pack'
82 | *.tgz
83 |
84 | # Yarn Integrity file
85 | .yarn-integrity
86 |
87 | # dotenv environment variables file
88 | .env
89 | .env.test
90 |
91 | # parcel-bundler cache (https://parceljs.org/)
92 | .cache
93 |
94 | # next.js build output
95 | .next
96 |
97 | # nuxt.js build output
98 | .nuxt
99 |
100 | # vuepress build output
101 | .vuepress/dist
102 |
103 | # Serverless directories
104 | .serverless/
105 |
106 | # FuseBox cache
107 | .fusebox/
108 |
109 | # DynamoDB Local files
110 | .dynamodb/
111 |
112 | ### VisualStudioCode ###
113 | .vscode/*
114 | # !.vscode/settings.json
115 | # ignore .vscode settings.json for now
116 | !.vscode/tasks.json
117 | !.vscode/launch.json
118 | !.vscode/extensions.json
119 |
120 | ### VisualStudioCode Patch ###
121 | # Ignore all local history of files
122 | .history
123 |
124 | # HubSpot configs
125 | hubspot.config.yaml
126 | hubspot.config.yml
127 |
128 | # Lock files
129 | package-lock.json
130 | yarn.lock
131 |
--------------------------------------------------------------------------------
/src/modules/menu.module/module.js:
--------------------------------------------------------------------------------
1 | // Website header variables
2 |
3 | var menuParentItems = document.querySelectorAll('.menu--desktop .menu__item--has-submenu');
4 | var childToggle = document.querySelectorAll('.menu--mobile .menu__child-toggle');
5 |
6 | // Desktop menu
7 |
8 | if (menuParentItems) {
9 | Array.prototype.forEach.call(menuParentItems, function(el){
10 |
11 | // Menu item variables
12 |
13 | var childToggle = el.querySelector('.menu__child-toggle');
14 |
15 | // Handles hover over
16 |
17 | el.addEventListener('mouseover', function(){
18 | this.classList.add('menu__item--open');
19 | this.querySelector('a').setAttribute('aria-expanded', 'true');
20 | this.querySelector('button').setAttribute('aria-expanded', 'true');
21 | });
22 |
23 | // Handles hover out
24 |
25 | el.addEventListener('mouseout', function(){
26 | document.querySelector('.menu__item--open > a').setAttribute('aria-expanded', 'false');
27 | document.querySelector('.menu__item--open > button').setAttribute('aria-expanded', 'false');
28 | document.querySelector('.menu__item--open').classList.remove('menu__item--open');
29 | });
30 |
31 | // Handles toggle of submenus
32 |
33 | childToggle.addEventListener('click', function(){
34 | if (this.parentNode.classList.contains('menu__item--open')) {
35 | this.parentNode.classList.remove('menu__item--open');
36 | this.parentNode.querySelector('a').setAttribute('aria-expanded', 'false');
37 | this.parentNode.querySelector('button').setAttribute('aria-expanded', 'false');
38 | }
39 | else {
40 | this.parentNode.classList.add('menu__item--open');
41 | this.parentNode.querySelector('a').setAttribute('aria-expanded', 'true');
42 | this.parentNode.querySelector('button').setAttribute('aria-expanded', 'true');
43 | }
44 | });
45 |
46 | });
47 |
48 | }
49 |
50 | // Mobile menu
51 |
52 | // Handles toggle of submenus
53 |
54 | if (childToggle) {
55 | Array.prototype.forEach.call(childToggle, function(el){
56 |
57 | el.addEventListener('click', function(){
58 | this.classList.toggle('menu__child-toggle--open');
59 | if (this.parentNode.classList.contains('menu__item--open')) {
60 | this.parentNode.classList.remove('menu__item--open');
61 | this.parentNode.querySelector('a').setAttribute('aria-expanded', 'false');
62 | this.parentNode.querySelector('button').setAttribute('aria-expanded', 'false');
63 | }
64 | else {
65 | this.parentNode.classList.add('menu__item--open');
66 | this.parentNode.querySelector('a').setAttribute('aria-expanded', 'true');
67 | this.parentNode.querySelector('button').setAttribute('aria-expanded', 'true');
68 | }
69 | });
70 |
71 | });
72 | }
--------------------------------------------------------------------------------
/src/modules/button.module/fields.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "label": "Button link",
4 | "name": "link",
5 | "type": "link",
6 | "supported_types": [
7 | "EXTERNAL",
8 | "CONTENT",
9 | "FILE",
10 | "EMAIL_ADDRESS",
11 | "CALL_TO_ACTION"
12 | ],
13 | "default": {
14 | "url": {
15 | "href": "",
16 | "type": "EXTERNAL"
17 | },
18 | "no_follow": false,
19 | "open_in_new_tab": false
20 | }
21 | },
22 | {
23 | "label": "Button text",
24 | "name": "button_text",
25 | "type": "text",
26 | "required": true,
27 | "default": "Add a button link here"
28 | },
29 | {
30 | "label": "Styles",
31 | "name": "styles",
32 | "type": "group",
33 | "tab": "STYLE",
34 | "children": [
35 | {
36 | "label": "Text",
37 | "name": "text",
38 | "type": "group",
39 | "children": [
40 | {
41 | "label": "Font",
42 | "name": "font",
43 | "type": "font"
44 | }
45 | ]
46 | },
47 | {
48 | "label": "Background",
49 | "name": "background",
50 | "type": "group",
51 | "children": [
52 | {
53 | "label": "Color",
54 | "name": "color",
55 | "type": "color"
56 | }
57 | ]
58 | },
59 | {
60 | "label": "Border",
61 | "name": "border",
62 | "type": "group",
63 | "children": [
64 | {
65 | "label": "Border",
66 | "name": "border",
67 | "type": "border"
68 | }
69 | ]
70 | },
71 | {
72 | "label": "Corner",
73 | "name": "corner",
74 | "type": "group",
75 | "children": [
76 | {
77 | "label": "Radius",
78 | "name": "radius",
79 | "type": "number",
80 | "display": "text",
81 | "max": 100,
82 | "step": 1,
83 | "suffix": "px"
84 | }
85 | ]
86 | },
87 | {
88 | "label": "Spacing",
89 | "name": "spacing",
90 | "type": "group",
91 | "children": [
92 | {
93 | "label": "Spacing",
94 | "name": "spacing",
95 | "type": "spacing"
96 | }
97 | ]
98 | },
99 | {
100 | "label": "Alignment",
101 | "name": "alignment",
102 | "type": "group",
103 | "children": [
104 | {
105 | "label": "Alignment",
106 | "name": "alignment",
107 | "type": "alignment",
108 | "alignment_direction": "HORIZONTAL"
109 | }
110 | ]
111 | }
112 | ]
113 | }
114 | ]
115 |
--------------------------------------------------------------------------------
/src/css/templates/system.css:
--------------------------------------------------------------------------------
1 | /* Error pages */
2 |
3 | .error-page {
4 | padding: 10rem 0;
5 | position: relative;
6 | text-align: center;
7 | }
8 |
9 | .error-page:before {
10 | color: #F3F6F9;
11 | content: attr(data-error);
12 | font-size: 40vw;
13 | font-weight: bold;
14 | left: 50%;
15 | position: absolute;
16 | top: 50%;
17 | transform: translate(-50%, -50%);
18 | width: 100%;
19 | z-index: -1;
20 | }
21 |
22 | @media screen and (min-width: 1100px) {
23 | .error-page:before {
24 | font-size: 20rem;
25 | }
26 | }
27 |
28 | /* System pages */
29 |
30 | .systems-page {
31 | margin: 0 auto;
32 | max-width: 700px;
33 | padding: 3rem 1.4rem;
34 | }
35 |
36 | .systems-page--search-results {
37 | max-width: 100%;
38 | }
39 |
40 | .systems-page .header {
41 | background-color: transparent;
42 | border-bottom: none;
43 | padding: 0;
44 | }
45 |
46 | .systems-page .success {
47 | background-color: #CDE3CC;
48 | border: 1.5px solid #4F7D24;
49 | border-radius: 6px;
50 | color: #4F7D24;
51 | display: inline-block;
52 | margin: 1.4rem 0;
53 | padding: 0.1rem 0.7rem;
54 | width: 100%;
55 | }
56 |
57 | .systems-page form input {
58 | max-width: 100%;
59 | }
60 |
61 | .systems-page form input[type='submit'] {
62 | margin: 0.7rem 0;
63 | display: block;
64 | }
65 |
66 | /* Search pages */
67 |
68 | .hs-search-results__title {
69 | font-size: 1.25rem;
70 | margin-bottom: 0.35rem;
71 | text-decoration: underline;
72 | }
73 |
74 | .hs-search-results__title:hover {
75 | text-decoration: none;
76 | }
77 |
78 | .hs-search-results__description {
79 | padding-top: 0.7rem;
80 | }
81 |
82 | /* Password prompt */
83 |
84 | .password-prompt input[type=password] {
85 | height: auto !important;
86 | margin-bottom: 1.4rem;
87 | }
88 |
89 | .systems-page #hs-login-widget-remember,
90 | .systems-page #hs-login-widget-remember ~ label {
91 | display: inline-block;
92 | margin-bottom: 0.175rem;
93 | }
94 |
95 | .systems-page #hs_login_reset {
96 | display: block;
97 | margin-bottom: 0.7rem;
98 | }
99 |
100 | /* Backup unsubscribe */
101 |
102 | .backup-unsubscribe #email-prefs-form div {
103 | padding-bottom: 0 !important;
104 | }
105 |
106 | .backup-unsubscribe input[type=email] {
107 | font-size: 0.875rem !important;
108 | margin-bottom: 1.4rem;
109 | padding: 0.7rem !important;
110 | }
111 |
112 | /* Subscription preferences */
113 |
114 | #email-prefs-form .item.disabled {
115 | opacity: 0.6;
116 | cursor: not-allowed;
117 | }
118 |
119 | #email-prefs-form .item.disabled input:disabled {
120 | cursor: not-allowed;
121 | }
122 |
123 | /* Membership pages */
124 |
125 | #hs-membership-form a[class*='show-password'] {
126 | font-size: 0.75rem;
127 | }
128 |
129 | /* Input error messages */
130 |
131 | .form-input-validation-message ul.hs-error-msgs {
132 | padding-left: 0;
133 | margin: 0;
134 | }
135 |
136 | .form-input-validation-message ul.hs-error-msgs li {
137 | margin: 0;
138 | }
--------------------------------------------------------------------------------
/src/sections/pricing.html:
--------------------------------------------------------------------------------
1 |
8 | {% dnd_section %}
9 | {% dnd_column %}
10 | {% dnd_row %}
11 | {% dnd_module
12 | path="@hubspot/rich_text",
13 | html={{ context.heading or '
Pricing ' }}
14 | %}
15 | {% end_dnd_module %}
16 | {% end_dnd_row %}
17 | {% dnd_row %}
18 | {% dnd_module
19 | path="../modules/pricing-card",
20 | button_text={{ context.card_one_button_text or "Buy starter" }},
21 | description={{ context.card_one_description or "For individuals or team just getting started with sales.
" }},
22 | features=[
23 | "Ad management",
24 | "Live chat",
25 | "Conversational bots",
26 | "Forms",
27 | "Pop-up forms",
28 | "Contact website activity",
29 | "List segmentation",
30 | "Email marketing",
31 | "Ad retargeting"
32 | ],
33 | offset=0,
34 | price={{ context.card_one_price or "$0" }},
35 | tier={{ context.card_one_tier or "Starter " }},
36 | timeframe={{ context.card_one_timeframe or "/mo" }},
37 | width=4
38 | %}
39 | {% end_dnd_module %}
40 | {% dnd_module
41 | path="../modules/pricing-card",
42 | button_text={{ context.card_two_button_text or "Buy professional" }},
43 | description={{ context.card_two_description or "For teams that need to create sales plans with confidence.
" }},
44 | features=[
45 | "Marketing automation",
46 | "Smart content",
47 | "Content creation tools",
48 | "SEO & content strategy",
49 | "Social media",
50 | "A/B testing",
51 | "Landing pages",
52 | "Calls-to-action",
53 | "Video hosting"
54 | ],
55 | offset=4,
56 | price={{ context.card_two_price or "$1200" }},
57 | tier={{ context.card_two_tier or "Professional " }},
58 | timeframe={{ context.card_two_timeframe or "/mo" }},
59 | width=4
60 | %}
61 | {% end_dnd_module %}
62 | {% dnd_module
63 | path="../modules/pricing-card",
64 | button_text={{ context.card_three_button_text or "Buy enterprise" }},
65 | description={{ context.card_three_description or "For teams that need additional security, control, and support.
" }},
66 | features=[
67 | "Content partitioning",
68 | "Hierarchical teams",
69 | "Single sign-on",
70 | "Social permissions",
71 | "Additional domains",
72 | "Email send frequency cap",
73 | "Calculated properties",
74 | "CMS membership",
75 | "Filtered analytics view"
76 | ],
77 | offset=8,
78 | price={{ context.card_three_price or "$3200" }},
79 | tier={{ context.card_three_tier or "Enterprise " }},
80 | timeframe={{ context.card_three_timeframe or "/mo" }},
81 | width=4
82 | %}
83 | {% end_dnd_module %}
84 | {% end_dnd_row %}
85 | {% end_dnd_column %}
86 | {% end_dnd_section %}
87 |
--------------------------------------------------------------------------------
/src/modules/pricing-card.module/module.css:
--------------------------------------------------------------------------------
1 | .card {
2 | text-align: center;
3 | }
4 | .card--pricing {
5 | box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.15);
6 | padding: 2.1rem;
7 | }
8 |
9 | @media screen and (max-width: 1200px) {
10 | .card--pricing {
11 | padding: 2.1rem 0.7rem;
12 | }
13 | }
14 |
15 | @media screen and (max-width: 787px) {
16 | .card--pricing {
17 | margin-bottom: 1.4rem;
18 | }
19 | }
20 |
21 | .card__subtitle,
22 | .card__body li {
23 | font-size: 0.9rem;
24 | }
25 |
26 | .card__body ul,
27 | .card__body li {
28 | padding: 0;
29 | }
30 |
31 | .card__body li {
32 | list-style: none;
33 | margin: 0;
34 | padding: 0.35rem 0;
35 | text-align: left;
36 | }
37 |
38 | .card__body svg {
39 | display: inline-block;
40 | margin-right: 0.7rem;
41 | max-width: 20px;
42 | }
43 |
44 | /* Overlay */
45 |
46 | .card__overlay-background {
47 | position: fixed;
48 |
49 | /* One less than the overlay z-index value */
50 | z-index: 999999;
51 | -webkit-backdrop-filter: blur(2px);
52 | backdrop-filter: blur(2px);
53 | background: rgba(0, 0, 0, 0.2);
54 | inset: 0;
55 | opacity: 0;
56 | transition: opacity 500ms ease 0s, visibility 500ms ease 0s;
57 | visibility: hidden;
58 | }
59 |
60 | .card__overlay-background.open {
61 | opacity: 1;
62 | visibility: visible;
63 | }
64 |
65 | /* Overlay */
66 |
67 | html.card__payments--overlay-open {
68 | position: relative;
69 | overflow: hidden;
70 | height: 100%;
71 | }
72 |
73 | .card__overlay {
74 | position: fixed;
75 |
76 | /* Well below the maximum value, but high enough to cover most cases */
77 | z-index: 1000000;
78 | top: 100%;
79 | right: 0;
80 | bottom: 0;
81 | left: 0;
82 | height: calc(100% - 50px);
83 | width: 100vw;
84 | background-color: #fff;
85 | transform: translateY(0);
86 | transition: transform 500ms ease 0s, visibility 500ms ease 0s;
87 | visibility: hidden;
88 | }
89 |
90 | .card__overlay.open {
91 | transform: translateY(-100%);
92 | transition: transform 500ms ease 0s, visibility 500ms ease 0s;
93 | visibility: visible;
94 | }
95 |
96 | button.card__overlay-close--top {
97 | position: absolute;
98 | top: -40px;
99 | right: 16px;
100 | display: flex;
101 | height: 30px;
102 | width: 30px;
103 | padding: 5px;
104 | border: none;
105 | border-radius: 50%;
106 | align-items: center;
107 | background: #fff;
108 | outline-color: #33475b;
109 | }
110 |
111 | button.card__overlay-close--top svg {
112 | fill: #7c98b6;
113 | }
114 |
115 | button.card__overlay-close--top:hover svg,
116 | button.card__overlay-close--top:focus svg {
117 | fill: #33475b;
118 | }
119 |
120 | @media screen and (min-width: 768px) {
121 | button.card__overlay-close--top {
122 | top: 16px;
123 | right: 16px;
124 | background: transparent;
125 | }
126 | }
127 |
128 | button.card__overlay-close--bottom {
129 | position: absolute;
130 | top: initial;
131 | right: 16px;
132 | bottom: 16px;
133 | padding: 5px;
134 | border: none;
135 | background: none;
136 | color: #33475b;
137 | font-size: 14px;
138 | font-weight: normal;
139 | opacity: 0;
140 | outline-color: #33475b;
141 | }
142 |
143 | button.card__overlay-close--bottom:focus {
144 | opacity: 1;
145 | }
146 |
147 | .card__overlay .payments-iframe-container {
148 | height: 100%;
149 | width: 100%;
150 | }
151 |
152 | .card__overlay .payments-iframe-container iframe {
153 | height: 100% !important; /* stylelint-disable-line declaration-no-important */
154 | }
155 |
156 |
157 |
--------------------------------------------------------------------------------
/src/templates/blog-post.html:
--------------------------------------------------------------------------------
1 |
7 | {% set template_css = "../../css/templates/blog.css" %}
8 | {% extends "./layouts/base.html" %}
9 |
10 | {% block body %}
11 |
12 |
13 | {# Blog post #}
14 |
15 |
16 |
17 | {{ content.name|sanitize_html }}
18 |
26 |
27 | {{ content.post_body }}{# escaped elsewhere #}
28 |
29 | {% if content.tag_list %}
30 |
31 | {% icon
32 | name="tag",
33 | purpose="decorative",
34 | style="SOLID"
35 | %}
36 | {% for tag in content.tag_list %}
37 |
{{ tag.name|escape_html }} {% if not loop.last %},{% endif %}
38 | {% endfor %}
39 |
40 | {% endif %}
41 |
42 | {% if group.allow_comments %}
43 |
49 | {% endif %}
50 |
51 |
52 | {# Recent posts listing #}
53 |
54 | {# This macro is used to format each recent post card and gets passed to the related_blog_posts HubL tag below #}
55 |
56 | {% macro related_posts(post, count, total) %}
57 | {% if count == 1 %}
58 |
59 |
60 |
Read On
61 |
62 | {% endif %}
63 |
64 | {% if post.featured_image %}
65 |
66 |
67 |
68 | {% endif %}
69 |
70 |
72 | {{ post.post_summary|truncatehtml(100)|sanitize_html("STRIP") }}
73 |
74 |
75 | {% if count == total %}
76 |
77 |
78 |
79 | {% endif %}
80 | {% endmacro %}
81 |
82 | {% related_blog_posts
83 | limit=3,
84 | no_wrapper=True,
85 | post_formatter="related_posts"
86 | %}
87 |
88 |
89 | {% endblock body %}
90 |
--------------------------------------------------------------------------------
/src/sections/multi-column-content.html:
--------------------------------------------------------------------------------
1 |
8 | {% dnd_section
9 | background_color={{ context.background_color or "#f8fafc" }},
10 | vertical_alignment="MIDDLE"
11 | %}
12 | {% dnd_column
13 | offset=0,
14 | width=4
15 | %}
16 | {% dnd_row %}
17 | {% dnd_module
18 | path="@hubspot/linked_image",
19 | img={
20 | "alt": context.column_one_image_alt or "Stock placeholder image with grayscale geometrical mountain landscape",
21 | "loading": context.column_one_image_loading or "lazy",
22 | "max_height": context.column_one_image_height or 451,
23 | "max_width": context.column_one_image_width or 605,
24 | "size_type": "auto_custom_max",
25 | "src": context.column_one_image or get_asset_url("../images/grayscale-mountain.png")
26 | }
27 | %}
28 | {% end_dnd_module %}
29 | {% end_dnd_row %}
30 | {% dnd_row %}
31 | {% dnd_module
32 | path="@hubspot/rich_text",
33 | html={{ context.column_one_content or "Feature one Use text and images to tell your company’s story. Explain what makes your product or service extraordinary.
" }}
34 | %}
35 | {% end_dnd_module %}
36 | {% end_dnd_row %}
37 | {% end_dnd_column %}
38 | {% dnd_column
39 | offset=4,
40 | width=4
41 | %}
42 | {% dnd_row %}
43 | {% dnd_module
44 | path="@hubspot/linked_image",
45 | img={
46 | "alt": context.column_two_image_alt or "Stock placeholder image with grayscale geometrical mountain landscape",
47 | "loading": context.column_two_image_loading or "lazy",
48 | "max_height": context.column_two_image_height or 451,
49 | "max_width": context.column_two_image_width or 605,
50 | "size_type": "auto_custom_max",
51 | "src": context.column_two_image or get_asset_url("../images/grayscale-mountain.png")
52 | }
53 | %}
54 | {% end_dnd_module %}
55 | {% end_dnd_row %}
56 | {% dnd_row %}
57 | {% dnd_module
58 | path="@hubspot/rich_text",
59 | html={{ context.column_two_content or "Feature two Use text and images to tell your company’s story. Explain what makes your product or service extraordinary.
" }}
60 | %}
61 | {% end_dnd_module %}
62 | {% end_dnd_row %}
63 | {% end_dnd_column %}
64 | {% dnd_column
65 | offset=8,
66 | width=4
67 | %}
68 | {% dnd_row %}
69 | {% dnd_module
70 | path="@hubspot/linked_image",
71 | img={
72 | "alt": context.column_three_image_alt or "Stock placeholder image with grayscale geometrical mountain landscape",
73 | "loading": context.column_three_image_loading or "lazy",
74 | "max_height": context.column_three_image_height or 451,
75 | "max_width": context.column_three_image_width or 605,
76 | "size_type": "auto_custom_max",
77 | "src": context.column_three_image or get_asset_url("../images/grayscale-mountain.png")
78 | }
79 | %}
80 | {% end_dnd_module %}
81 | {% end_dnd_row %}
82 | {% dnd_row %}
83 | {% dnd_module
84 | path="@hubspot/rich_text",
85 | html={{ context.column_three_content or "Feature three Use text and images to tell your company’s story. Explain what makes your product or service extraordinary.
" }}
86 | %}
87 | {% end_dnd_module %}
88 | {% end_dnd_row %}
89 | {% end_dnd_column %}
90 | {% end_dnd_section %}
91 |
--------------------------------------------------------------------------------
/src/css/elements/_forms.css:
--------------------------------------------------------------------------------
1 | /* Fields */
2 |
3 | .hs-form-field {
4 | margin-bottom: 1.4rem;
5 | }
6 |
7 | /* Labels */
8 |
9 | form label {
10 | display: block;
11 | font-size: 0.875rem;
12 | margin-bottom: 0.35rem;
13 | }
14 |
15 | /* Form Title */
16 | .form-title {
17 | margin-bottom: 0;
18 | }
19 |
20 | /* Help text */
21 |
22 | form legend {
23 | font-size: 0.875rem;
24 | }
25 |
26 | /* Inputs */
27 |
28 | form input[type=text],
29 | form input[type=search],
30 | form input[type=email],
31 | form input[type=password],
32 | form input[type=tel],
33 | form input[type=number],
34 | form input[type=file],
35 | form select,
36 | form textarea {
37 | display: inline-block;
38 | font-size: 0.875rem;
39 | padding: 0.7rem;
40 | width: 100%;
41 | }
42 |
43 | form textarea {
44 | resize: vertical;
45 | }
46 |
47 | form fieldset {
48 | max-width: 100% !important;
49 | }
50 |
51 | /* Inputs - checkbox/radio */
52 |
53 | form .inputs-list {
54 | margin: 0;
55 | padding: 0;
56 | list-style: none;
57 | }
58 |
59 | form .inputs-list > li {
60 | display: block;
61 | margin: 0.7rem 0;
62 | }
63 |
64 | form .inputs-list input,
65 | form .inputs-list span {
66 | vertical-align: middle;
67 | }
68 |
69 | form input[type=checkbox],
70 | form input[type=radio] {
71 | cursor: pointer;
72 | margin-right: 0.35rem;
73 | }
74 |
75 | /* Inputs - date picker */
76 |
77 | .hs-dateinput {
78 | position: relative;
79 | }
80 |
81 | .hs-dateinput:before {
82 | content:'\01F4C5';
83 | position: absolute;
84 | right: 10%;
85 | top: 50%;
86 | transform: translateY(-50%);
87 | }
88 |
89 | .fn-date-picker .pika-table thead th {
90 | color: #FFF;
91 | }
92 |
93 | .fn-date-picker td.is-selected .pika-button {
94 | border-radius: 0;
95 | box-shadow: none;
96 | }
97 |
98 | .fn-date-picker td .pika-button:hover,
99 | .fn-date-picker td .pika-button:focus {
100 | border-radius: 0 !important;
101 | color: #FFF;
102 | }
103 |
104 | /* Inputs - file picker */
105 |
106 | form input[type=file] {
107 | background-color: transparent;
108 | border: initial;
109 | padding: initial;
110 | }
111 |
112 | /* Headings and text */
113 |
114 | form .hs-richtext,
115 | form .hs-richtext p {
116 | font-size: 0.875rem;
117 | margin: 0 0 1.4rem;
118 | }
119 |
120 | form .hs-richtext img {
121 | max-width: 100% !important;
122 | }
123 |
124 | /* GDPR */
125 |
126 | .legal-consent-container .hs-form-booleancheckbox-display > span,
127 | .legal-consent-container .hs-form-booleancheckbox-display > span p {
128 | margin-left: 1rem !important;
129 | }
130 |
131 | /* Validation */
132 |
133 | .hs-form-required {
134 | color: #EF6B51;
135 | }
136 |
137 | .hs-input.invalid.error {
138 | border-color: #EF6B51;
139 | }
140 |
141 | .hs-error-msg {
142 | color: #EF6B51;
143 | margin-top: 0.35rem;
144 | }
145 |
146 | /* Submit button */
147 |
148 | form input[type=submit],
149 | form .hs-button {
150 | cursor: pointer;
151 | display: inline-block;
152 | text-align: center;
153 | transition: all 0.15s linear;
154 | white-space: normal;
155 | }
156 |
157 | /* Captcha */
158 |
159 | .grecaptcha-badge {
160 | margin: 0 auto;
161 | }
162 |
163 | {% if ( get_asset_version("@hubspot/search_input") == "1" ) %}
164 | /* Search button input field and suggestions */
165 | .body-container-wrapper .hs-search-field__button {
166 | padding: 15px;
167 | }
168 |
169 | .body-container-wrapper .hs-search-field__bar--button-inline .hs-search-field__button {
170 | margin-left: 6px;
171 | margin-bottom: 0;
172 | }
173 |
174 | .body-container-wrapper .hs-search-field__button svg {
175 | height: 15px;
176 | fill: #fff;
177 | }
178 |
179 | .body-container-wrapper .hs-search-field__bar > form > .hs-search-field__input {
180 | padding: 10px;
181 | }
182 |
183 | .body-container-wrapper .hs-search-field__suggestions li a {
184 | color: #494A52;
185 | padding: 0.35rem 0.7rem;
186 | text-decoration: none;
187 | transition: background-color 0.3s;
188 | }
189 | {% endif %}
190 |
--------------------------------------------------------------------------------
/src/js/main.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | // Variables
3 | var nav = document.querySelector('.header__navigation');
4 | var langSwitcher = document.querySelector('.header__language-switcher');
5 | var search = document.querySelector('.header__search');
6 | var allToggles = document.querySelectorAll('.header--toggle');
7 | var navToggle = document.querySelector('.header__navigation--toggle');
8 | var langToggle = document.querySelector('.header__language-switcher--toggle');
9 | var searchToggle = document.querySelector('.header__search--toggle');
10 | var closeToggle = document.querySelector('.header__close--toggle');
11 | var allElements = document.querySelectorAll(
12 | '.header--element, .header--toggle'
13 | );
14 | var emailGlobalUnsub = document.querySelector('input[name="globalunsub"]');
15 |
16 | // Functions
17 |
18 | // Function for executing code on document ready
19 | function domReady(callback) {
20 | if (['interactive', 'complete'].indexOf(document.readyState) >= 0) {
21 | callback();
22 | } else {
23 | document.addEventListener('DOMContentLoaded', callback);
24 | }
25 | }
26 |
27 | // Function for toggling mobile navigation
28 | function toggleNav() {
29 | allToggles.forEach(function (toggle) {
30 | toggle.classList.toggle('hide');
31 | });
32 |
33 | nav.classList.toggle('open');
34 | navToggle.classList.toggle('open');
35 |
36 | closeToggle.classList.toggle('show');
37 | }
38 |
39 | // Function for toggling mobile language selector
40 | function toggleLang() {
41 | allToggles.forEach(function (toggle) {
42 | toggle.classList.toggle('hide');
43 | });
44 |
45 | langSwitcher.classList.toggle('open');
46 | langToggle.classList.toggle('open');
47 |
48 | closeToggle.classList.toggle('show');
49 | }
50 |
51 | // Function for toggling mobile search field
52 | function toggleSearch() {
53 | allToggles.forEach(function (toggle) {
54 | toggle.classList.toggle('hide');
55 | });
56 |
57 | search.classList.toggle('open');
58 | searchToggle.classList.toggle('open');
59 |
60 | closeToggle.classList.toggle('show');
61 | }
62 |
63 | // Function for the header close option on mobile
64 | function closeAll() {
65 | allElements.forEach(function (element) {
66 | element.classList.remove('hide', 'open');
67 | });
68 |
69 | closeToggle.classList.remove('show');
70 | }
71 |
72 | // Function to disable the other checkbox inputs on the email subscription system page template
73 | function toggleDisabled() {
74 | var emailSubItem = document.querySelectorAll('#email-prefs-form .item');
75 |
76 | emailSubItem.forEach(function (item) {
77 | var emailSubItemInput = item.querySelector('input');
78 |
79 | if (emailGlobalUnsub.checked) {
80 | item.classList.add('disabled');
81 | emailSubItemInput.setAttribute('disabled', 'disabled');
82 | emailSubItemInput.checked = false;
83 | } else {
84 | item.classList.remove('disabled');
85 | emailSubItemInput.removeAttribute('disabled');
86 | }
87 | });
88 | }
89 |
90 | // Execute JavaScript on document ready
91 | domReady(function () {
92 | if (!document.body) {
93 | return;
94 | } else {
95 | // Function dependent on language switcher
96 | if (langSwitcher) {
97 | langToggle.addEventListener('click', toggleLang);
98 | }
99 |
100 | // Function dependent on navigation
101 | if (navToggle) {
102 | navToggle.addEventListener('click', toggleNav);
103 | }
104 |
105 | // Function dependent on search field
106 | if (searchToggle) {
107 | searchToggle.addEventListener('click', toggleSearch);
108 | }
109 |
110 | // Function dependent on close toggle
111 | if (closeToggle) {
112 | closeToggle.addEventListener('click', closeAll);
113 | }
114 |
115 | // Function dependent on email unsubscribe from all input
116 | if (emailGlobalUnsub) {
117 | emailGlobalUnsub.addEventListener('change', toggleDisabled);
118 | }
119 | }
120 | });
121 | })();
122 |
--------------------------------------------------------------------------------
/src/templates/hubdb.html:
--------------------------------------------------------------------------------
1 |
7 |
8 | {# Please note that only users with CMS Hub will have access to the HubDB tool. Therefore, this template should not be used in accounts without CMS Hub. We don't currently accept marketplace assets that leverage HubDB (https://developers.hubspot.com/docs/cms/marketplace-requirements/compliance-design-code-quality#1-3-unacceptable-asset-marketplace-submissions) so please remove this template if you're creating a marketplace asset. #}
9 |
10 | {# Before getting started with using HubDB we highly recommend you read through our HubDB documentation (https://developers.hubspot.com/docs/cms/features/hubdb) #}
11 |
12 | {% extends "./layouts/base.html" %}
13 |
14 | {# Testing config #}
15 |
16 | {# By setting the testing variable below to true, you can preview your template changes using a specific HubDB table directly from the design manager. Set the testing variable to false and isAvailableForNewContent in the template annotations to true when you're ready to use this template for a live page. #}
17 |
18 | {% set testing = true %} {# Set to false for production #}
19 | {% set testing_table_id = null %} {# Set to HubDB table id (integer) #}
20 | {% set testing_row_id = null %} {# Set to a HubDB table row id (integer) #}
21 | {% set testing_page_level = 0 %} {# Set to the dynamic page route level that you want to test. Set 0 for the root level page and 1 for an example of a dynamic page based on the testing_row_id #}
22 |
23 | {# Testing/production logic #}
24 |
25 | {% if testing %}
26 | {% set table_id = testing_table_id %}
27 | {% set row = hubdb_table_row( table_id, testing_row_id ) %}
28 | {% set page_level = testing_page_level %}
29 | {% else %}
30 | {% set table_id = dynamic_page_hubdb_table_id %}
31 | {% set row = dynamic_page_hubdb_row %}
32 | {% set page_level = dynamic_page_route_level %}
33 | {% endif %}
34 |
35 | {# Used on top level (table_id set in testing/production logic) #}
36 |
37 | {% set rows = hubdb_table_rows( table_id ) %}
38 |
39 | {% block body %}
40 |
41 |
42 |
43 | {% if table_id %}
44 |
45 | {% if page_level == 0 and rows|length > 0 %}
46 |
47 |
48 | {% module "page_title" path="@hubspot/text"
49 | label="Page title",
50 | value="Root Page Title"
51 | %}
52 |
53 |
54 |
55 |
56 | {% for row in rows %}
57 |
58 | {{ row.name }}
59 |
60 | {% endfor %}
61 |
62 |
63 | {% elif page_level == 1 and row %}
64 |
65 |
68 |
69 |
70 |
71 |
72 | Label
73 | Name
74 | Value
75 |
76 |
77 |
78 | {% for col in hubdb_table( table_id ).columns %}
79 |
80 | {{ col.label }}
81 | {{ col.name }}
82 | {{ row[ col.name ] }}
83 |
84 | {% endfor %}
85 |
86 |
87 |
88 | {% endif %}
89 |
90 | {% else %}
91 |
92 | {# Leverages HubSpot's editor class to only show an error message within the page editor if a user hasn't selected a HubDB table yet (https://designers.hubspot.com/how-to-make-custom-code-work-with-cms#using-hs-inline-edit-window-hsineditor) #}
93 |
94 | {% require_js %}
95 |
110 | {% end_require_js %}
111 |
112 | {% endif %}
113 |
114 |
115 |
116 | {% endblock %}
117 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to the HubSpot CMS Boilerplate
2 |
3 | Thank you for helping out with the HubSpot CMS Boilerplate! We are always looking for people to help contribute to and improve upon the project and there are plenty of ways that you can get involved. Please take a moment to review this document so that the contribution process is easy and effective for everyone involved.
4 |
5 | ## Using the issue tracker
6 |
7 | The [issue tracker](https://github.com/HubSpot/cms-theme-boilerplate/issues) is the preferred channel for reporting bugs, and making features requests but please be sure to follow the following guidelines:
8 | * For questions specific to your individual project, and how to build something, reach out in the [community developer forums](https://community.hubspot.com/t5/HubSpot-Developers/ct-p/developers) or [HubSpot Developer Slack](https://designers.hubspot.com/slack).
9 | * If you experience issues with your HubSpot account itself, such as features not working as expected, [reach out to HubSpot support](https://help.hubspot.com).
10 | * Please be respectful and constructive with any and all feedback, we all want to build a better experience together.
11 | * Please open issues for third party tools in their respective repositories (e.g. [prettier](https://github.com/prettier/prettier) and [eslint](https://github.com/eslint/eslint)).
12 |
13 | ## Reporting bugs
14 |
15 | A bug is a reproducible issue that is caused by the code in the HubSpot CMS Boilerplate. If you find a bug while using the HubSpot CMS Boilerplate for your projects, please let us know! Any bugs that are not specifically related to the HubSpot CMS Boilerplate and are more related to the HubSpot product should be filed to our support team. More information on contacting our support team can be found [here](https://knowledge.hubspot.com/account/get-help-with-hubspot).
16 |
17 | Guidelines for a bug report:
18 |
19 | * Search through [open GitHub issues](https://github.com/HubSpot/cms-theme-boilerplate/issues) to see if there is already an open issue.
20 | * Check to see if the issue has been [fixed in a recent pull request](https://github.com/HubSpot/cms-theme-boilerplate/pulls?q=is%3Apr+is%3Aclosed) and ensure that you’re using the latest version of the main branch when testing.
21 | * Isolate the problem and create a list of reproducible steps.
22 | * A good bug report should include all information needed for someone to resolve the issue. Please try to be as detailed as possible. Providing more detail will make it easier to identify the issue and resolve the issue faster.
23 |
24 | ## Feature requests
25 |
26 | A feature request is a request for a new feature that currently doesn't exist within the project. While we welcome feature requests, please take some time to determine how the feature request fits into the existing project. We'll need to understand why the feature is important and what it is solving. Any feature requests that are not specifically related to the HubSpot CMS Boilerplate and are more related to the HubSpot product should be submitted to our ideas forum [here](https://community.hubspot.com/t5/Ideas/ct-p/ideas) or in the #ideas channel in our public [developer Slack channel](https://developers.hubspot.com/slack).
27 |
28 | Guidelines for a feature request:
29 |
30 | * Search through [open GitHub issues](https://github.com/HubSpot/cms-theme-boilerplate/issues) to see if there is already an open issue related to the feature request.
31 | * Check to see if the feature request has been [implemented in a recent pull request](https://github.com/HubSpot/cms-theme-boilerplate/pulls?q=is%3Apr+is%3Aclosed) and ensure that you’re using the latest version of the main branch when testing.
32 |
33 | ## Pull requests
34 |
35 | Pull requests for bug fixes, enhancements, and new features are great ways to help contribute to the HubSpot CMS Boilerplate. You can and should expect some back-and-forth with stakeholders when you open a pull request. Please check in frequently to address any requests for changes so that your code can successfully be merged.
36 |
37 | Guidelines for pull requests:
38 |
39 | * Changes made in pull requests should have a focused scope and you should avoid containing unrelated commits to the change that is being made.
40 | * **Please reach out** before working on a significantly large pull request otherwise you may risk spending a lot of time on something that may not end up being merged into the HubSpot CMS Boilerplate. We’d recommend creating an issue using the label of `idea` prior to working on a large update to the project.
41 | * Please ensure that your changes follow our [style guide requirements](https://github.com/HubSpot/cms-theme-boilerplate/blob/main/STYLEGUIDE.md) to ensure that all code remains consistent and easy to read.
42 |
43 | We recommend [forking the project](https://help.github.com/en/enterprise/2.16/user/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork) and submitting your changes using the [pull request template](https://github.com/HubSpot/cms-theme-boilerplate/tree/main/.github/PULL_REQUEST_TEMPLATE).
--------------------------------------------------------------------------------
/src/modules/social-follow.module/module.html:
--------------------------------------------------------------------------------
1 | {# Module styles #}
2 |
3 | {% require_css %}
4 |
81 | {% end_require_css %}
82 |
83 | {# Social links #}
84 |
85 |
134 |
--------------------------------------------------------------------------------
/src/modules/menu.module/module.html:
--------------------------------------------------------------------------------
1 | {# Module styles #}
2 |
3 | {% require_css %}
4 |
80 | {% end_require_css %}
81 |
82 | {# Menu items #}
83 |
84 | {% macro menu_items() %}
85 |
86 | {% set menu = menu(module.menu, "site_root").children %}
87 |
88 | {% macro render_link_item(link, depth) %}
89 |
123 | {% endmacro %}
124 |
125 | {% for link in menu %}
126 | {{ render_link_item(link, 1) }}
127 | {% endfor %}
128 |
129 | {% endmacro %}
130 |
131 | {# Desktop menu #}
132 |
133 |
138 |
139 | {# Mobile menu #}
140 |
141 |
146 |
--------------------------------------------------------------------------------
/src/css/generic/_normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
2 |
3 | /* Document
4 | ========================================================================== */
5 |
6 | /**
7 | * 1. Correct the line height in all browsers.
8 | * 2. Prevent adjustments of font size after orientation changes in iOS.
9 | */
10 |
11 | html {
12 | line-height: 1.15; /* 1 */
13 | -webkit-text-size-adjust: 100%; /* 2 */
14 | }
15 |
16 | /* Sections
17 | ========================================================================== */
18 |
19 | /**
20 | * Remove the margin in all browsers.
21 | */
22 |
23 | body {
24 | margin: 0;
25 | }
26 |
27 | /**
28 | * Correct the font size and margin on `h1` elements within `section` and
29 | * `article` contexts in Chrome, Firefox, and Safari.
30 | */
31 |
32 | h1 {
33 | font-size: 2em;
34 | margin: 0.67em 0;
35 | }
36 |
37 | /* Grouping content
38 | ========================================================================== */
39 |
40 | /**
41 | * Add the correct box sizing in Firefox.
42 | */
43 |
44 | hr {
45 | box-sizing: content-box;
46 | height: 0;
47 | }
48 |
49 | /**
50 | * 1. Correct the inheritance and scaling of font size in all browsers.
51 | * 2. Correct the odd `em` font sizing in all browsers.
52 | */
53 |
54 | pre {
55 | font-family: monospace, monospace; /* 1 */
56 | font-size: 1em; /* 2 */
57 | }
58 |
59 | /* Text-level semantics
60 | ========================================================================== */
61 |
62 | /**
63 | * 1. Remove the bottom border in Chrome 57-
64 | * 2. Add the correct text decoration in Chrome, Edge, Opera, and Safari.
65 | */
66 |
67 | abbr[title] {
68 | border-bottom: none; /* 1 */
69 | text-decoration: underline; /* 2 */
70 | text-decoration: underline dotted; /* 2 */
71 | }
72 |
73 | /**
74 | * Add the correct font weight in Chrome, Edge, and Safari.
75 | */
76 |
77 | b,
78 | strong {
79 | font-weight: bolder;
80 | }
81 |
82 | /**
83 | * 1. Correct the inheritance and scaling of font size in all browsers.
84 | * 2. Correct the odd `em` font sizing in all browsers.
85 | */
86 |
87 | code,
88 | kbd,
89 | samp {
90 | font-family: monospace, monospace; /* 1 */
91 | font-size: 1em; /* 2 */
92 | }
93 |
94 | /**
95 | * Add the correct font size in all browsers.
96 | */
97 |
98 | small {
99 | font-size: 80%;
100 | }
101 |
102 | /**
103 | * Prevent `sub` and `sup` elements from affecting the line height in
104 | * all browsers.
105 | */
106 |
107 | sub,
108 | sup {
109 | font-size: 75%;
110 | line-height: 0;
111 | position: relative;
112 | vertical-align: baseline;
113 | }
114 |
115 | sub {
116 | bottom: -0.25em;
117 | }
118 |
119 | sup {
120 | top: -0.5em;
121 | }
122 |
123 | /* Forms
124 | ========================================================================== */
125 |
126 | /**
127 | * 1. Change the font styles in all browsers.
128 | * 2. Remove the margin in Firefox and Safari.
129 | */
130 |
131 | button,
132 | input,
133 | optgroup,
134 | select,
135 | textarea {
136 | font-family: inherit; /* 1 */
137 | font-size: 100%; /* 1 */
138 | line-height: 1.15; /* 1 */
139 | margin: 0; /* 2 */
140 | }
141 |
142 | /**
143 | * Remove the inheritance of text transform in Edge and Firefox.
144 | * 1. Remove the inheritance of text transform in Firefox.
145 | */
146 |
147 | button,
148 | select { /* 1 */
149 | text-transform: none;
150 | }
151 |
152 | /**
153 | * Correct the inability to style clickable types in iOS and Safari.
154 | */
155 |
156 | button,
157 | [type="button"],
158 | [type="reset"],
159 | [type="submit"] {
160 | -webkit-appearance: button;
161 | }
162 |
163 | /**
164 | * Remove the inner border and padding in Firefox.
165 | */
166 |
167 | button::-moz-focus-inner,
168 | [type="button"]::-moz-focus-inner,
169 | [type="reset"]::-moz-focus-inner,
170 | [type="submit"]::-moz-focus-inner {
171 | border-style: none;
172 | padding: 0;
173 | }
174 |
175 | /**
176 | * Restore the focus styles unset by the previous rule.
177 | */
178 |
179 | button:-moz-focusring,
180 | [type="button"]:-moz-focusring,
181 | [type="reset"]:-moz-focusring,
182 | [type="submit"]:-moz-focusring {
183 | outline: 1px dotted ButtonText;
184 | }
185 |
186 | /**
187 | * Correct the padding in Firefox.
188 | */
189 |
190 | fieldset {
191 | padding: 0.35em 0.75em 0.625em;
192 | }
193 |
194 | /**
195 | * Remove the padding so developers are not caught out when they zero out `fieldset` elements in all browsers.
196 | */
197 |
198 | legend {
199 | padding: 0;
200 | }
201 |
202 | /**
203 | * Add the correct vertical alignment in Chrome, Firefox, and Opera.
204 | */
205 |
206 | progress {
207 | vertical-align: baseline;
208 | }
209 |
210 | /**
211 | * Correct the cursor style of increment and decrement buttons in Chrome.
212 | */
213 |
214 | [type="number"]::-webkit-inner-spin-button,
215 | [type="number"]::-webkit-outer-spin-button {
216 | height: auto;
217 | }
218 |
219 | /**
220 | * 1. Correct the odd appearance in Chrome and Safari.
221 | * 2. Correct the outline style in Safari.
222 | */
223 |
224 | [type="search"] {
225 | -webkit-appearance: textfield; /* 1 */
226 | outline-offset: -2px; /* 2 */
227 | }
228 |
229 | /**
230 | * Remove the inner padding in Chrome and Safari on macOS.
231 | */
232 |
233 | [type="search"]::-webkit-search-decoration {
234 | -webkit-appearance: none;
235 | }
236 |
237 | /**
238 | * 1. Correct the inability to style clickable types in iOS and Safari.
239 | * 2. Change font properties to `inherit` in Safari.
240 | */
241 |
242 | ::-webkit-file-upload-button {
243 | -webkit-appearance: button; /* 1 */
244 | font: inherit; /* 2 */
245 | }
246 |
247 | /* Interactive
248 | ========================================================================== */
249 |
250 | /*
251 | * Add the correct display in Edge and Firefox.
252 | */
253 |
254 | details {
255 | display: block;
256 | }
257 |
258 | /*
259 | * Add the correct display in all browsers.
260 | */
261 |
262 | summary {
263 | display: list-item;
264 | }
--------------------------------------------------------------------------------
/src/modules/card.module/fields.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "label": "Card",
4 | "name": "card",
5 | "type": "group",
6 | "occurrence": {
7 | "default": 3,
8 | "min": 1,
9 | "sorting_label_field": "card.title"
10 | },
11 | "children": [
12 | {
13 | "label": "Image",
14 | "name": "image",
15 | "type": "image",
16 | "responsive": true,
17 | "resizable": true,
18 | "show_loading": true,
19 | "default": {
20 | "loading": "lazy"
21 | }
22 | },
23 | {
24 | "label": "Content",
25 | "name": "text",
26 | "type": "richtext",
27 | "enabled_features": [
28 | "advanced_emphasis",
29 | "alignment",
30 | "block",
31 | "emoji",
32 | "font_family",
33 | "font_size",
34 | "lists",
35 | "standard_emphasis"
36 | ],
37 | "default": "This is a title Contextual advertising can be profitable. It can either pay for your hosting and maintenance costs for you website or it can pay for a lot more.
"
38 | }
39 | ],
40 | "default": [
41 | {
42 | "image": {
43 | "loading": "lazy"
44 | },
45 | "text": "This is a title Contextual advertising can be profitable. It can either pay for your hosting and maintenance costs for you website or it can pay for a lot more.
"
46 | },
47 | {
48 | "image": {
49 | "loading": "lazy"
50 | },
51 | "text": "This is a title Contextual advertising can be profitable. It can either pay for your hosting and maintenance costs for you website or it can pay for a lot more.
"
52 | },
53 | {
54 | "image": {
55 | "loading": "lazy"
56 | },
57 | "text": "This is a title Contextual advertising can be profitable. It can either pay for your hosting and maintenance costs for you website or it can pay for a lot more.
"
58 | }
59 | ]
60 | },
61 | {
62 | "label": "Styles",
63 | "name": "styles",
64 | "type": "group",
65 | "tab": "STYLE",
66 | "children": [
67 | {
68 | "label": "Image",
69 | "name": "image",
70 | "type": "group",
71 | "children": [
72 | {
73 | "label": "Corner",
74 | "name": "corner",
75 | "type": "group",
76 | "children": [
77 | {
78 | "label": "Radius",
79 | "name": "radius",
80 | "type": "number",
81 | "display": "text",
82 | "max": 100,
83 | "step": 1,
84 | "suffix": "px"
85 | }
86 | ]
87 | }
88 | ]
89 | },
90 | {
91 | "label": "Card",
92 | "name": "card",
93 | "type": "group",
94 | "children": [
95 | {
96 | "label": "Background",
97 | "name": "background",
98 | "type": "group",
99 | "children": [
100 | {
101 | "label": "Background type",
102 | "name": "background_type",
103 | "id": "styles.card.background.background_type",
104 | "type": "choice",
105 | "choices": [
106 | ["none", "None"],
107 | ["color", "Color"],
108 | ["gradient", "Gradient"],
109 | ["image", "Image"]
110 | ],
111 | "display": "radio",
112 | "default": "none"
113 | },
114 | {
115 | "label": "Color",
116 | "name": "color",
117 | "type": "color",
118 | "visibility": {
119 | "controlling_field": "styles.card.background.background_type",
120 | "controlling_value_regex": "color",
121 | "operator": "EQUAL"
122 | }
123 | },
124 | {
125 | "label": "Gradient",
126 | "name": "gradient",
127 | "type": "gradient",
128 | "visibility": {
129 | "controlling_field": "styles.card.background.background_type",
130 | "controlling_value_regex": "gradient",
131 | "operator": "EQUAL"
132 | }
133 | },
134 | {
135 | "label": "Image",
136 | "name": "image",
137 | "type": "backgroundimage",
138 | "visibility": {
139 | "controlling_field": "styles.card.background.background_type",
140 | "controlling_value_regex": "image",
141 | "operator": "EQUAL"
142 | }
143 | }
144 | ]
145 | },
146 | {
147 | "label": "Border",
148 | "name": "border",
149 | "type": "group",
150 | "children": [
151 | {
152 | "label": "Border",
153 | "name": "border",
154 | "type": "border"
155 | }
156 | ]
157 | },
158 | {
159 | "label": "Corner",
160 | "name": "corner",
161 | "type": "group",
162 | "children": [
163 | {
164 | "label": "Radius",
165 | "name": "radius",
166 | "type": "number",
167 | "display": "text",
168 | "max": 100,
169 | "step": 1,
170 | "suffix": "px"
171 | }
172 | ]
173 | },
174 | {
175 | "label": "Spacing",
176 | "name": "spacing",
177 | "type": "group",
178 | "children": [
179 | {
180 | "label": "Spacing",
181 | "name": "spacing",
182 | "type": "spacing"
183 | }
184 | ]
185 | }
186 | ]
187 | }
188 | ]
189 | }
190 | ]
191 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | HubSpot CMS Boilerplate
2 |
3 |
4 | A straight-forward starting point for building a great website on the HubSpot CMS.
5 |
6 |
7 |
8 | Documentation |
9 | Demo website |
10 | Contributing
11 |
12 |
13 | [](https://github.com/HubSpot/cms-theme-boilerplate/releases)
14 | [](https://github.com/HubSpot/cms-theme-boilerplate/commits/main)
15 | [](https://github.com/HubSpot/cms-theme-boilerplate/graphs/contributors)
16 | [](https://github.com/HubSpot/cms-theme-boilerplate/watchers)
17 | [](https://github.com/HubSpot/cms-theme-boilerplate/stargazers)
18 | [](https://github.com/HubSpot/cms-theme-boilerplate/network/members)
19 | [](https://website.grader.com/tests/boilerplate.hubspotcms.com)
20 | [](https://developers.google.com/web/tools/lighthouse)
21 | [](https://developers.google.com/web/tools/lighthouse)
22 | [](https://developers.google.com/web/tools/lighthouse)
23 | [](https://github.com/HubSpot/cms-theme-boilerplate/blob/main/LICENSE)
24 |
25 | ## Purpose
26 |
27 | The [HubSpot CMS Boilerplate](https://designers.hubspot.com/docs/building-blocks/themes/hubspot-cms-boilerplate) is designed to offer developers a head start in the website building process. While the HubSpot CMS Boilerplate represents HubSpot's opinionated best practices, we intend to learn from similar projects and feedback. We hope it offers inspiration and utility for all website projects!
28 |
29 | ## Getting started
30 |
31 | ### To download the HubSpot CMS Boilerplate using the HubSpot CMS CLI:
32 |
33 | Before getting started, you will need to have [Node.js](https://nodejs.org) installed, the [HubSpot CMS CLI](https://developers.hubspot.com/docs/cms/guides/getting-started-with-local-development#install-dependencies) installed, and we strongly suggest that you set up a [HubSpot CMS Developer Sandbox](https://offers.hubspot.com/free-cms-developer-sandbox) for your QA/testing environment.
34 |
35 | 1. Navigate to the directory that you want to use for your project
36 | 2. Run `hs create website-theme ` to create a project from the HubSpot CMS Boilerplate
37 | 3. [Configure](https://developers.hubspot.com/docs/cms/guides/getting-started-with-local-development#configure-the-local-development-tools) the local development tools for the portal(s) you'd like to use for your project.
38 | 4. Run `hs watch --portal= src --initial-upload` to upload all the files in the project and [watch for changes](https://developers.hubspot.com/docs/cms/developer-reference/local-development-cms-cli#watch) to files in the `src` directory
39 |
40 | Please reference our _[Quick start guide to developing on the HubSpot CMS](https://developers.hubspot.com/docs/cms/guides/getting-started)_ and our _[Getting started with local development](https://designers.hubspot.com/tutorials/getting-started-with-local-development)_ articles for more information.
41 |
42 | ### To use version control in your project using GitHub and GitHub Actions:
43 |
44 | 1. [Fork](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) the HubSpot CMS Boilerplate repository and [clone](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository) your forked repository to your computer
45 | 2. [Set up GitHub secrets in your forked repository to encrypt sensitive information from showing publically](https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets) for `HUBSPOT_PORTAL_ID` and `HUBSPOT_PERSONAL_ACCESS_KEY`
46 | 3. Update the name of the directory that you'll be deploying to in your Design Manager in the `.github/workflows/deploy.yml` file (the current default `dest_dir` is `cms-theme-boilerplate`)
47 | 4. Deploy changes to your Design Manager by pushing to the `main` branch of your forked repository
48 |
49 | Please reference our [_HubSpot CMS deploy GitHub action page_](https://github.com/marketplace/actions/hubspot-cms-deploy) and _[Setting up continuous integration with a GitHub repository using GitHub Actions article](https://designers.hubspot.com/tutorials/github-integration)_ for more information.
50 |
51 | ## Style guide
52 |
53 | For details about the HubSpot CMS Boilerplate's recommended best practices and code formatting, please reference our [style guide](https://github.com/HubSpot/cms-theme-boilerplate/blob/master/STYLEGUIDE.md).
54 |
55 | ## Contributing
56 |
57 | If you’re interested in contributing to the HubSpot CMS Boilerplate, please read [CONTRIBUTING.md](https://github.com/HubSpot/cms-theme-boilerplate/blob/master/CONTRIBUTING.md) and [STYLEGUIDE.md](https://github.com/HubSpot/cms-theme-boilerplate/blob/master/STYLEGUIDE.md) to see how you can report an issue, make a feature request, or make a pull request.
58 |
59 | ## Versioning
60 |
61 | Previous releases and their documentation are available for [download](https://github.com/HubSpot/cms-theme-boilerplate/releases). To provide transparency into future releases, we create a project board that documents our planning in preparation for each [upcoming major and minor version](https://github.com/HubSpot/cms-theme-boilerplate/projects).
62 |
63 | ## Community
64 |
65 | You can stay up to date with HubSpot CMS Boilerplate updates and discussions in the #hs-cms-boilerplate channel in the [HubSpot Developer Slack](https://designers.hubspot.com/slack).
66 |
67 | ## License
68 |
69 | The code is available under the [Apache License, Version 2.0](https://github.com/HubSpot/cms-theme-boilerplate/blob/main/LICENSE)
70 |
--------------------------------------------------------------------------------
/src/modules/social-follow.module/fields.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "label": "Social links",
4 | "name": "social_links",
5 | "type": "group",
6 | "occurrence": {
7 | "default": 4,
8 | "min": 1
9 | },
10 | "children": [
11 | {
12 | "label": "Social account",
13 | "name": "social_account",
14 | "id": "social_account",
15 | "type": "choice",
16 | "choices": [
17 | ["facebook-f", "Facebook"],
18 | ["x-twitter", "Twitter"],
19 | ["instagram", "Instagram"],
20 | ["linkedin-in", "LinkedIn"],
21 | ["youtube", "YouTube"],
22 | ["pinterest-p", "Pinterest"],
23 | ["envelope", "Email"],
24 | ["link", "Website"],
25 | ["whatsapp", "Whatsapp"],
26 | ["custom_icon", "Custom icon"]
27 | ],
28 | "display": "select",
29 | "required": true,
30 | "default": "facebook-f"
31 | },
32 | {
33 | "label": "Custom icon",
34 | "name": "custom_icon",
35 | "type": "icon",
36 | "icon_set" : "fontawesome-6.4.2",
37 | "visibility": {
38 | "controlling_field": "social_account",
39 | "controlling_value_regex": "custom_icon",
40 | "operator": "EQUAL"
41 | },
42 | "required": true,
43 | "default": {
44 | "name": "arrow-alt-circle-up",
45 | "type" : "SOLID",
46 | "unicode": "f35b"
47 | }
48 | },
49 | {
50 | "label": "Social link",
51 | "name": "social_link",
52 | "type": "link",
53 | "required": true,
54 | "supported_types": ["EXTERNAL", "EMAIL_ADDRESS"],
55 | "default": {
56 | "no_follow": false,
57 | "open_in_new_tab": true,
58 | "url": {
59 | "content_id": null,
60 | "href": "https://www.facebook.com",
61 | "type": "EXTERNAL"
62 | }
63 | }
64 | },
65 | {
66 | "label": "Accessibility options",
67 | "name": "accessibility",
68 | "type": "group",
69 | "children": [
70 | {
71 | "label": "Title",
72 | "name": "title",
73 | "type": "text",
74 | "required": true,
75 | "default": "Follow us on Facebook"
76 | }
77 | ]
78 | }
79 | ],
80 | "default": [
81 | {
82 | "social_account": "facebook-f",
83 | "social_link": {
84 | "no_follow": false,
85 | "open_in_new_tab": true,
86 | "url": {
87 | "content_id": null,
88 | "href": "https://www.facebook.com",
89 | "type": "EXTERNAL"
90 | }
91 | },
92 | "accessibility": {
93 | "title": "Follow us on Facebook"
94 | }
95 | },
96 | {
97 | "social_account": "linkedin-in",
98 | "social_link": {
99 | "no_follow": false,
100 | "open_in_new_tab": true,
101 | "url": {
102 | "content_id": null,
103 | "href": "https://www.linkedin.com",
104 | "type": "EXTERNAL"
105 | }
106 | },
107 | "accessibility": {
108 | "title": "Follow us on LinkedIn"
109 | }
110 | },
111 | {
112 | "social_account": "x-twitter",
113 | "social_link": {
114 | "no_follow": false,
115 | "open_in_new_tab": true,
116 | "url": {
117 | "content_id": null,
118 | "href": "https://www.twitter.com",
119 | "type": "EXTERNAL"
120 | }
121 | },
122 | "accessibility": {
123 | "title": "Follow us on Twitter"
124 | }
125 | },
126 | {
127 | "social_account": "instagram",
128 | "social_link": {
129 | "no_follow": false,
130 | "open_in_new_tab": true,
131 | "url": {
132 | "content_id": null,
133 | "href": "https://www.instagram.com",
134 | "type": "EXTERNAL"
135 | }
136 | },
137 | "accessibility": {
138 | "title": "Follow us on Instagram"
139 | }
140 | }
141 | ]
142 | },
143 | {
144 | "label": "Styles",
145 | "name": "styles",
146 | "type": "group",
147 | "tab": "STYLE",
148 | "children": [
149 | {
150 | "label": "Fill",
151 | "name": "fill",
152 | "type": "group",
153 | "children": [
154 | {
155 | "label": "Color",
156 | "name": "color",
157 | "type": "color",
158 | "visibility": {
159 | "hidden_subfields": {
160 | "opacity": true
161 | }
162 | }
163 | }
164 | ]
165 | },
166 | {
167 | "label": "Size",
168 | "name": "size",
169 | "type": "group",
170 | "children": [
171 | {
172 | "label": "Size",
173 | "name": "size",
174 | "type": "number",
175 | "display": "text",
176 | "max": 50,
177 | "min": 1,
178 | "step": 1,
179 | "suffix": "px"
180 | }
181 | ]
182 | },
183 | {
184 | "label": "Background",
185 | "name": "background",
186 | "type": "group",
187 | "children": [
188 | {
189 | "label": "Color",
190 | "name": "color",
191 | "type": "color"
192 | }
193 | ]
194 | },
195 | {
196 | "label": "Corner",
197 | "name": "corner",
198 | "type": "group",
199 | "children": [
200 | {
201 | "label": "Radius",
202 | "name": "radius",
203 | "type": "number",
204 | "display": "text",
205 | "max": 100,
206 | "step": 1,
207 | "suffix": "px"
208 | }
209 | ]
210 | },
211 | {
212 | "label": "Spacing",
213 | "name": "spacing",
214 | "type": "group",
215 | "children": [
216 | {
217 | "label": "Space between icons",
218 | "name": "space_between_icons",
219 | "type": "number",
220 | "display": "slider",
221 | "max": 50,
222 | "min": 0,
223 | "step": 5,
224 | "suffix": "px"
225 | },
226 | {
227 | "label": "Spacing",
228 | "name": "spacing",
229 | "type": "spacing"
230 | }
231 | ]
232 | },
233 | {
234 | "label": "Alignment",
235 | "name": "alignment",
236 | "type": "group",
237 | "children": [
238 | {
239 | "label": "Alignment",
240 | "name": "alignment",
241 | "type": "alignment",
242 | "alignment_direction": "HORIZONTAL"
243 | }
244 | ]
245 | }
246 | ]
247 | }
248 | ]
249 |
--------------------------------------------------------------------------------
/src/modules/menu.module/module.css:
--------------------------------------------------------------------------------
1 | /* Menu */
2 |
3 | .menu--desktop {
4 | display: block;
5 | }
6 |
7 | .menu--mobile {
8 | display: none;
9 | }
10 |
11 | @media (max-width: 767px) {
12 | .menu--desktop {
13 | display: none;
14 | }
15 |
16 | .menu--mobile {
17 | display: block;
18 | }
19 | }
20 |
21 | /* Menu items */
22 |
23 | .menu__item {
24 | position: relative;
25 | }
26 |
27 | .menu__link {
28 | font-size: 0.917rem;
29 | line-height: 1.667rem;
30 | text-decoration: none;
31 | }
32 |
33 | .menu__link:hover,
34 | .menu__link:focus,
35 | .menu__link:active {
36 | text-decoration: none;
37 | }
38 |
39 | .menu__link--active-link,
40 | .menu__link--active-branch {
41 | font-weight: bold;
42 | }
43 |
44 | @media (min-width: 768px) and (max-width: 1150px) {
45 | .menu__link {
46 | font-size: 0.833rem;
47 | }
48 | }
49 |
50 | @media (max-width: 767px) {
51 | .menu__item {
52 | display: block;
53 | width: 100%;
54 | }
55 |
56 | .menu__link {
57 | display: block;
58 | font-size: 1.083rem;
59 | }
60 | }
61 |
62 | /* Menu items - top level */
63 |
64 | .menu__item--depth-1 {
65 | display: inline-block;
66 | padding: 0.7rem 0.875rem;
67 | text-transform: uppercase;
68 | }
69 |
70 | .menu__item--depth-1 > .menu__link--active-link:after {
71 | bottom: -3px;
72 | content: '';
73 | height: 2px;
74 | left: 0;
75 | position: absolute;
76 | width: 100%;
77 | }
78 |
79 | @media (max-width: 767px) {
80 | .menu__item--depth-1 {
81 | border-top: 2px solid #CED4DB;
82 | padding: 0;
83 | }
84 |
85 | .menu__item--depth-1 > .menu__link {
86 | padding: 0.35rem 1.225rem;
87 | }
88 |
89 | .menu__item--depth-1 > .menu__link--active-link:after {
90 | content: none;
91 | }
92 | }
93 |
94 | /* Menu items - submenus */
95 |
96 | .menu__submenu {
97 | box-shadow: 0 2px 9px 0 rgba(0, 0, 0, 0.2);
98 | border-radius: 3px;
99 | display: none;
100 | left: 0;
101 | position: absolute;
102 | text-align: left;
103 | text-transform: none;
104 | top: 100%;
105 | width: 270px;
106 | z-index: 99;
107 | }
108 |
109 | .menu__item--open > .menu__submenu {
110 | display: block;
111 | }
112 |
113 | .menu__submenu--level-2 {
114 | transform: translateX(-50%);
115 | }
116 |
117 | /* Keeps the first menu item's drop down menu aligned to the left of the top level menu item */
118 |
119 | .menu__item--depth-1:first-child .menu__submenu--level-2 {
120 | transform: unset;
121 | }
122 |
123 | .menu__submenu .menu__item {
124 | border-bottom: 1px solid #D1D6DC;
125 | padding: 0;
126 | width: 100%;
127 | }
128 |
129 | .menu__submenu .menu__link {
130 | display: block;
131 | padding: 0.7rem 1.05rem;
132 | transition: background-color 0.3s;
133 | width: 100%;
134 | }
135 |
136 | .menu__submenu--level-3 {
137 | left: 100%;
138 | top: 0;
139 | }
140 |
141 | /* Flyouts for the last two top level menu items go left to keep page responsive */
142 |
143 | .menu__item--depth-1:nth-last-child(-n+2) .menu__submenu--level-3 {
144 | left: auto;
145 | right: 100%;
146 | top: 0;
147 | }
148 |
149 | /* Accounts for child toggle */
150 |
151 | .menu__submenu .menu__item--has-submenu > .menu__link {
152 | padding-right: 3rem;
153 | }
154 |
155 | /* Creates the triangle at the top of the submenu drop down */
156 |
157 | @media (min-width: 768px) {
158 | .menu__submenu--level-2 > .menu__item:first-child:before {
159 | border-radius: 6px;
160 | box-shadow: 0 2px 9px 0 rgb(0 0 0 / 20%);
161 | content: '';
162 | display: block;
163 | height: 30px;
164 | left: 125px;
165 | margin-left: 1rem;
166 | overflow: hidden;
167 | position: absolute;
168 | top: -12px;
169 | transform: rotate(45deg);
170 | transition: background-color .3s;
171 | width: 30px;
172 | z-index: 2;
173 | }
174 |
175 | /* Keeps triangle to the left for the first menu item's drop down menu */
176 |
177 | .menu__item--depth-1:first-child > .menu__submenu--level-2 > .menu__item:first-child:before {
178 | left: 0;
179 | }
180 |
181 | .menu__submenu--level-2 > .menu__item:first-child > .menu__link {
182 | position: relative;
183 | z-index: 2;
184 | }
185 | }
186 |
187 | @media (max-width: 767px) {
188 | .menu__submenu {
189 | border: none;
190 | border-radius: 0;
191 | box-shadow: none;
192 | position: static;
193 | transform: unset;
194 | width: 100%;
195 | }
196 |
197 | .menu__submenu .menu__item {
198 | background-color: #FFF;
199 | border-bottom: none;
200 | border-top: 2px solid #EBEFF3;
201 | padding: 0;
202 | }
203 |
204 | .menu__submenu .menu__link {
205 | display: block;
206 | padding: 0.7rem 2rem;
207 | transition: none;
208 | width: 100%;
209 | }
210 |
211 | .menu__submenu .menu__item .menu__link:hover,
212 | .menu__submenu .menu__item .menu__link:focus {
213 | background-color: inherit;
214 | transition: none;
215 | }
216 |
217 | .menu__item--has-submenu > .menu__link {
218 | width: 70%;
219 | }
220 |
221 | .menu__submenu--level-3 .menu__item .menu__link {
222 | padding: 0.7rem 3rem;
223 | }
224 | }
225 |
226 | /* Menu icons */
227 |
228 | @media(min-width: 768px) {
229 | .menu__submenu .menu__child-toggle {
230 | margin-left: auto;
231 | padding: 0 1.05rem;
232 | }
233 |
234 | .menu__child-toggle {
235 | position: absolute;
236 | right: 5px;
237 | top: 30px;
238 | z-index: 2;
239 | }
240 |
241 | .menu__item--depth-1 > .menu__child-toggle {
242 | position: static;
243 | right: 0;
244 | top: 0;
245 | vertical-align: middle;
246 | }
247 |
248 | .menu__child-toggle-icon {
249 | border-left: 5px solid transparent;
250 | border-right: 5px solid transparent;
251 | border-top-style: solid;
252 | border-top-width: 7px;
253 | display: block;
254 | height: 0;
255 | margin-left: 1px;
256 | width: 0;
257 | }
258 | }
259 |
260 | @media (max-width: 767px) {
261 | .menu__child-toggle {
262 | background-position: center right 30px;
263 | background-repeat: no-repeat;
264 | background-size: 20px;
265 | border: none;
266 | cursor: pointer;
267 | height: 55px;
268 | padding: 15px 0;
269 | position: absolute;
270 | right: 0;
271 | top: 0;
272 | width: 30%;
273 | }
274 |
275 | .menu__child-toggle-icon {
276 | background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMTkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgc3Ryb2tlPSIjOTc5ODlGIiBzdHJva2Utd2lkdGg9IjIuNCIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cmVjdCB4PSIxLjIiIHk9IjkuNiIgd2lkdGg9IjE2LjgiIGhlaWdodD0iMSIgcng9Ii41Ii8+PHJlY3QgdHJhbnNmb3JtPSJyb3RhdGUoOTAgOS42IDkuNikiIHg9IjEuMiIgeT0iOS42IiB3aWR0aD0iMTYuOCIgaGVpZ2h0PSIxIiByeD0iLjUiLz48L2c+PC9zdmc+);
277 | background-repeat: no-repeat;
278 | display: block;
279 | height: 20px;
280 | margin-left: auto;
281 | margin-right: 1.05rem;
282 | transition: transform 0.4s;
283 | width: 20px;
284 | }
285 |
286 | .menu__item--open > .menu__child-toggle .menu__child-toggle-icon {
287 | transform: rotate(45deg);
288 | transition: transform 0.4s;
289 | }
290 | }
291 |
292 |
--------------------------------------------------------------------------------
/src/templates/partials/header.html:
--------------------------------------------------------------------------------
1 |
5 |
6 | {% macro add_lang_switcher() %}
7 | {% if get_asset_version('@hubspot/language_switcher') == 1 %}
8 | {% module "language-switcher"
9 | path="@hubspot/language_switcher",
10 | label="Language switcher",
11 | display_mode="localized"
12 | styles={
13 | "group_button" : {
14 | "group_alignment" : {
15 | "alignment" : {
16 | "horizontal_align" : "RIGHT"
17 | }
18 | },
19 | "group_background" : {
20 | "color" : {
21 | "color" : "#000000",
22 | "opacity" : 0
23 | }
24 | },
25 | "group_border" : {
26 | "border" : {
27 | "bottom" : {
28 | "style" : "none"
29 | },
30 | "left" : {
31 | "style" : "none"
32 | },
33 | "right" : {
34 | "style" : "none"
35 | },
36 | "top" : {
37 | "style" : "none"
38 | }
39 | }
40 | },
41 | "group_chevron" : {
42 | "color" : {
43 | "color" : "#516d8d",
44 | "opacity" : 100
45 | },
46 | "size" : 10,
47 | "spacing" : 10
48 | },
49 | "group_corner" : {
50 | "radius" : 0
51 | },
52 | "group_icon" : {
53 | "color" : {
54 | "color" : "#516d8d",
55 | "opacity" : 100
56 | },
57 | "size" : 15,
58 | "spacing" : 10
59 | },
60 | "group_spacing" : {
61 | "spacing" : {
62 | "padding" : {
63 | "bottom" : {
64 | "units" : "px",
65 | "value" : 7
66 | },
67 | "left" : {
68 | "units" : "px",
69 | "value" : 15
70 | },
71 | "right" : {
72 | "units" : "px",
73 | "value" : 15
74 | },
75 | "top" : {
76 | "units" : "px",
77 | "value" : 7
78 | }
79 | }
80 | }
81 | },
82 | "group_text" : {
83 | "font" : {
84 | "color" : "#516d8d",
85 | "size" : 18,
86 | "size_unit" : "px"
87 | }
88 | }
89 | },
90 | "group_dropdown" : {
91 | "group_border" : {
92 | "border" : {
93 | "bottom" : {
94 | "color" : "#000000",
95 | "opacity" : 100,
96 | "style" : "none",
97 | "width" : {
98 | "units" : "px",
99 | "value" : 1
100 | }
101 | },
102 | "left" : {
103 | "color" : "#000000",
104 | "opacity" : 100,
105 | "style" : "none",
106 | "width" : {
107 | "units" : "px",
108 | "value" : 1
109 | }
110 | },
111 | "right" : {
112 | "color" : "#000000",
113 | "opacity" : 100,
114 | "style" : "none",
115 | "width" : {
116 | "units" : "px",
117 | "value" : 1
118 | }
119 | },
120 | "top" : {
121 | "color" : "#000000",
122 | "opacity" : 100,
123 | "style" : "none",
124 | "width" : {
125 | "units" : "px",
126 | "value" : 1
127 | }
128 | }
129 | }
130 | },
131 | "group_box_shadow" : {
132 | "add_box_shadow" : true
133 | },
134 | "group_hover" : {
135 | "group_background" : {
136 | "color" : {
137 | "color" : "#f8fafc",
138 | "opacity" : 100
139 | }
140 | }
141 | },
142 | "group_text" : {
143 | "font" : {
144 | "color" : "#516d8d",
145 | "size" : 16,
146 | "size_unit" : "px"
147 | }
148 | }
149 | }
150 | },
151 | add_chevron_down=true,
152 | icon_options="icon"
153 | %}
154 | {% else %}
155 | {% module "language-switcher"
156 | path="@hubspot/language_switcher",
157 | label="Language switcher",
158 | display_mode="localized"
159 | %}
160 |
161 | {% endif %}
162 | {% endmacro %}
163 |
248 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | browser: true,
5 | node: true,
6 | },
7 | rules: {
8 | 'accessor-pairs': 'off',
9 | 'array-bracket-newline': 'off',
10 | 'array-bracket-spacing': 'off',
11 | 'array-callback-return': 'off',
12 | 'array-element-newline': 'off',
13 | 'arrow-body-style': 'off',
14 | 'arrow-parens': 'off',
15 | 'arrow-spacing': 'off',
16 | 'block-scoped-var': 'off',
17 | 'block-spacing': 'off',
18 | 'brace-style': 'off',
19 | 'callback-return': 'off',
20 | camelcase: 'off',
21 | 'capitalized-comments': 'off',
22 | 'class-methods-use-this': 'off',
23 | 'comma-dangle': 'off',
24 | 'comma-spacing': 'off',
25 | 'comma-style': 'off',
26 | complexity: 'off',
27 | 'computed-property-spacing': 'off',
28 | 'consistent-return': 'off',
29 | 'consistent-this': 'off',
30 | 'constructor-super': 'error',
31 | curly: 'off',
32 | 'default-case': 'off',
33 | 'dot-location': 'off',
34 | 'dot-notation': 'off',
35 | 'eol-last': 'off',
36 | eqeqeq: 'off',
37 | 'for-direction': 'off',
38 | 'func-call-spacing': 'off',
39 | 'func-name-matching': 'off',
40 | 'func-names': 'off',
41 | 'func-style': 'off',
42 | 'function-paren-newline': 'off',
43 | 'generator-star': 'off',
44 | 'generator-star-spacing': 'off',
45 | 'getter-return': 'off',
46 | 'global-require': 'off',
47 | 'guard-for-in': 'off',
48 | 'handle-callback-err': 'off',
49 | 'id-blacklist': 'off',
50 | 'id-length': 'off',
51 | 'id-match': 'off',
52 | 'implicit-arrow-linebreak': 'off',
53 | indent: 'off',
54 | 'indent-legacy': 'off',
55 | 'init-declarations': 'off',
56 | 'jsx-quotes': 'off',
57 | 'key-spacing': 'off',
58 | 'keyword-spacing': 'off',
59 | 'line-comment-position': 'off',
60 | 'linebreak-style': 'off',
61 | 'lines-around-comment': 'off',
62 | 'lines-around-directive': 'off',
63 | 'lines-between-class-members': 'off',
64 | 'max-depth': 'off',
65 | 'max-len': 'off',
66 | 'max-len': 0,
67 | 'max-lines': 'off',
68 | 'max-nested-callbacks': 'off',
69 | 'max-params': 'off',
70 | 'max-statements': 'off',
71 | 'max-statements-per-line': 'off',
72 | 'multiline-comment-style': 'off',
73 | 'multiline-ternary': 'off',
74 | 'multiline-ternary': 'off',
75 | 'new-cap': 'off',
76 | 'new-parens': 'off',
77 | 'new-parens': 'off',
78 | 'newline-after-var': 'off',
79 | 'newline-before-return': 'off',
80 | 'newline-per-chained-call': 'off',
81 | 'newline-per-chained-call': 'off',
82 | 'no-alert': 'off',
83 | 'no-array-constructor': 'off',
84 | 'no-arrow-condition': 'off',
85 | 'no-await-in-loop': 'off',
86 | 'no-bitwise': 'off',
87 | 'no-buffer-constructor': 'off',
88 | 'no-caller': 'off',
89 | 'no-case-declarations': 'error',
90 | 'no-catch-shadow': 'off',
91 | 'no-class-assign': 'error',
92 | 'no-comma-dangle': 'off',
93 | 'no-compare-neg-zero': 'error',
94 | 'no-cond-assign': 'error',
95 | 'no-confusing-arrow': 'off',
96 | 'no-confusing-arrow': 0,
97 | 'no-console': 'error',
98 | 'no-const-assign': 'error',
99 | 'no-constant-condition': 'error',
100 | 'no-continue': 'off',
101 | 'no-control-regex': 'error',
102 | 'no-debugger': 'error',
103 | 'no-delete-var': 'error',
104 | 'no-div-regex': 'off',
105 | 'no-dupe-args': 'error',
106 | 'no-dupe-class-members': 'error',
107 | 'no-dupe-keys': 'error',
108 | 'no-duplicate-case': 'error',
109 | 'no-duplicate-imports': 'off',
110 | 'no-else-return': 'off',
111 | 'no-empty': 'error',
112 | 'no-empty-character-class': 'error',
113 | 'no-empty-function': 'off',
114 | 'no-empty-pattern': 'error',
115 | 'no-eq-null': 'off',
116 | 'no-eval': 'off',
117 | 'no-ex-assign': 'error',
118 | 'no-extend-native': 'off',
119 | 'no-extra-bind': 'off',
120 | 'no-extra-boolean-cast': 'error',
121 | 'no-extra-label': 'off',
122 | 'no-extra-parens': 'off',
123 | 'no-extra-parens': 'off',
124 | 'no-extra-semi': 'error',
125 | 'no-extra-semi': 'off',
126 | 'no-fallthrough': 'error',
127 | 'no-floating-decimal': 'off',
128 | 'no-floating-decimal': 'off',
129 | 'no-func-assign': 'error',
130 | 'no-global-assign': 'error',
131 | 'no-implicit-coercion': 'off',
132 | 'no-implicit-globals': 'off',
133 | 'no-implied-eval': 'off',
134 | 'no-inline-comments': 'off',
135 | 'no-inner-declarations': 'error',
136 | 'no-invalid-regexp': 'error',
137 | 'no-invalid-this': 'off',
138 | 'no-irregular-whitespace': 'error',
139 | 'no-iterator': 'off',
140 | 'no-label-var': 'off',
141 | 'no-labels': 'off',
142 | 'no-lone-blocks': 'off',
143 | 'no-lonely-if': 'off',
144 | 'no-loop-func': 'off',
145 | 'no-magic-numbers': 'off',
146 | 'no-mixed-operators': 'off',
147 | 'no-mixed-operators': 0,
148 | 'no-mixed-requires': 'off',
149 | 'no-mixed-spaces-and-tabs': 'error',
150 | 'no-mixed-spaces-and-tabs': 'off',
151 | 'no-multi-assign': 'off',
152 | 'no-multi-spaces': 'off',
153 | 'no-multi-spaces': 'off',
154 | 'no-multi-str': 'off',
155 | 'no-multiple-empty-lines': 'off',
156 | 'no-multiple-empty-lines': 'off',
157 | 'no-native-reassign': 'off',
158 | 'no-negated-condition': 'off',
159 | 'no-negated-in-lhs': 'off',
160 | 'no-nested-ternary': 'off',
161 | 'no-new': 'off',
162 | 'no-new-func': 'off',
163 | 'no-new-object': 'off',
164 | 'no-new-require': 'off',
165 | 'no-new-symbol': 'error',
166 | 'no-new-wrappers': 'off',
167 | 'no-obj-calls': 'error',
168 | 'no-octal': 'error',
169 | 'no-octal-escape': 'off',
170 | 'no-param-reassign': 'off',
171 | 'no-path-concat': 'off',
172 | 'no-plusplus': 'off',
173 | 'no-process-env': 'off',
174 | 'no-process-exit': 'off',
175 | 'no-proto': 'off',
176 | 'no-prototype-builtins': 'off',
177 | 'no-redeclare': 'error',
178 | 'no-regex-spaces': 'error',
179 | 'no-reserved-keys': 'off',
180 | 'no-restricted-globals': 'off',
181 | 'no-restricted-imports': 'off',
182 | 'no-restricted-modules': 'off',
183 | 'no-restricted-properties': 'off',
184 | 'no-restricted-syntax': 'off',
185 | 'no-return-assign': 'off',
186 | 'no-return-await': 'off',
187 | 'no-script-url': 'off',
188 | 'no-self-assign': 'error',
189 | 'no-self-compare': 'off',
190 | 'no-sequences': 'off',
191 | 'no-shadow': 'off',
192 | 'no-shadow-restricted-names': 'off',
193 | 'no-space-before-semi': 'off',
194 | 'no-spaced-func': 'off',
195 | 'no-sparse-arrays': 'error',
196 | 'no-sync': 'off',
197 | 'no-tabs': 'off',
198 | 'no-template-curly-in-string': 'off',
199 | 'no-ternary': 'off',
200 | 'no-this-before-super': 'error',
201 | 'no-throw-literal': 'off',
202 | 'no-trailing-spaces': 'off',
203 | 'no-undef': 'error',
204 | 'no-undef-init': 'off',
205 | 'no-undefined': 'off',
206 | 'no-underscore-dangle': 'off',
207 | 'no-unexpected-multiline': 'error',
208 | 'no-unexpected-multiline': 0,
209 | 'no-unmodified-loop-condition': 'off',
210 | 'no-unneeded-ternary': 'off',
211 | 'no-unreachable': 'error',
212 | 'no-unsafe-finally': 'error',
213 | 'no-unsafe-negation': 'error',
214 | 'no-unused-expressions': 'off',
215 | 'no-unused-labels': 'error',
216 | 'no-unused-vars': 'error',
217 | 'no-use-before-define': 'off',
218 | 'no-useless-call': 'off',
219 | 'no-useless-computed-key': 'off',
220 | 'no-useless-concat': 'off',
221 | 'no-useless-constructor': 'off',
222 | 'no-useless-escape': 'error',
223 | 'no-useless-rename': 'off',
224 | 'no-useless-return': 'off',
225 | 'no-var': 'off',
226 | 'no-void': 'off',
227 | 'no-warning-comments': 'off',
228 | 'no-whitespace-before-property': 'off',
229 | 'no-with': 'off',
230 | 'no-wrap-func': 'off',
231 | 'nonblock-statement-body-position': 'off',
232 | 'object-curly-newline': 'off',
233 | 'object-curly-spacing': 'off',
234 | 'object-property-newline': 'off',
235 | 'object-shorthand': 'off',
236 | 'one-var': 'off',
237 | 'one-var-declaration-per-line': 'off',
238 | 'operator-assignment': 'off',
239 | 'operator-linebreak': 'off',
240 | 'padded-blocks': 'off',
241 | 'padding-line-between-statements': 'off',
242 | 'prefer-arrow-callback': 'off',
243 | 'prefer-const': 'off',
244 | 'prefer-destructuring': 'off',
245 | 'prefer-numeric-literals': 'off',
246 | 'prefer-promise-reject-errors': 'off',
247 | 'prefer-reflect': 'off',
248 | 'prefer-rest-params': 'off',
249 | 'prefer-spread': 'off',
250 | 'prefer-template': 'off',
251 | 'quote-props': 'off',
252 | quotes: 'off',
253 | radix: 'off',
254 | 'require-await': 'off',
255 | 'require-jsdoc': 'off',
256 | 'require-yield': 'error',
257 | 'rest-spread-spacing': 'off',
258 | semi: 'off',
259 | 'semi-spacing': 'off',
260 | 'semi-style': 'off',
261 | 'sort-imports': 'off',
262 | 'sort-keys': 'off',
263 | 'sort-vars': 'off',
264 | 'space-after-function-name': 'off',
265 | 'space-after-keywords': 'off',
266 | 'space-before-blocks': 'off',
267 | 'space-before-function-paren': 'off',
268 | 'space-before-function-parentheses': 'off',
269 | 'space-before-keywords': 'off',
270 | 'space-in-brackets': 'off',
271 | 'space-in-parens': 'off',
272 | 'space-infix-ops': 'off',
273 | 'space-return-throw-case': 'off',
274 | 'space-unary-ops': 'off',
275 | 'space-unary-word-ops': 'off',
276 | 'spaced-comment': 'off',
277 | strict: 'off',
278 | 'switch-colon-spacing': 'off',
279 | 'symbol-description': 'off',
280 | 'template-curly-spacing': 'off',
281 | 'template-tag-spacing': 'off',
282 | 'unicode-bom': 'off',
283 | 'use-isnan': 'error',
284 | 'valid-jsdoc': 'off',
285 | 'valid-typeof': 'error',
286 | 'vars-on-top': 'off',
287 | 'wrap-iife': 'off',
288 | 'wrap-regex': 'off',
289 | 'yield-star-spacing': 'off',
290 | yoda: 'off',
291 | },
292 | };
293 |
--------------------------------------------------------------------------------
/src/modules/pricing-card.module/fields.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "label": "Product tier",
4 | "name": "tier",
5 | "id": "tier",
6 | "type": "richtext",
7 | "enabled_features": [
8 | "alignment",
9 | "block",
10 | "font_family",
11 | "font_size",
12 | "standard_emphasis"
13 | ],
14 | "default": "Free "
15 | },
16 | {
17 | "label": "Product description",
18 | "name": "description",
19 | "type": "richtext",
20 | "enabled_features": [
21 | "alignment",
22 | "block",
23 | "font_family",
24 | "font_size",
25 | "standard_emphasis"
26 | ],
27 | "default": "For teams that need additional security, control, and support.
"
28 | },
29 | {
30 | "label": "Features list icon",
31 | "name": "feature_icon",
32 | "type": "icon",
33 | "icon_set" : "fontawesome-6.4.2",
34 | "default": {
35 | "name": "check",
36 | "type": "SOLID",
37 | "unicode": "f00c"
38 | }
39 | },
40 | {
41 | "label": "Features",
42 | "name": "features",
43 | "type": "text",
44 | "occurrence": {
45 | "default": 4,
46 | "max": 50,
47 | "min": 1
48 | },
49 | "show_emoji_picker": true,
50 | "default": [
51 | "10 users included",
52 | "2 GB of storage",
53 | "Email support",
54 | "Help center access"
55 | ]
56 | },
57 | {
58 | "label": "Price",
59 | "name": "price",
60 | "type": "text",
61 | "default": "$0"
62 | },
63 | {
64 | "label": "Price timeframe",
65 | "name": "timeframe",
66 | "type": "text",
67 | "default": "/ mo"
68 | },
69 | {
70 | "label": "Button text",
71 | "name": "button_text",
72 | "type": "text",
73 | "default": "Sign up for free"
74 | },
75 | {
76 | "label": "Button target",
77 | "name": "button_target",
78 | "id": "button_target",
79 | "type": "choice",
80 | "choices": [
81 | ["payment_link", "Use a payment link"],
82 | ["custom_link", "Other"]
83 | ],
84 | "display": "radio",
85 | "default" : "payment_link"
86 | },
87 | {
88 | "label": "Button link",
89 | "name": "button_link",
90 | "type": "link",
91 | "visibility": {
92 | "controlling_field": "button_target",
93 | "controlling_value_regex": "custom_link",
94 | "operator": "EQUAL"
95 | },
96 | "supported_types": ["EXTERNAL", "CONTENT"],
97 | "default": {
98 | "url": {
99 | "content_id": null,
100 | "type": "EXTERNAL",
101 | "href": ""
102 | }
103 | }
104 | },
105 | {
106 | "label": "Payment link",
107 | "name": "payment_link",
108 | "id": "payment_link",
109 | "type": "payment",
110 | "visibility": {
111 | "controlling_field": "button_target",
112 | "controlling_value_regex": "payment_link",
113 | "operator": "EQUAL"
114 | },
115 | "required": true
116 | },
117 | {
118 | "label": "Checkout behavior",
119 | "name": "checkout_behavior",
120 | "type": "choice",
121 | "visibility_rules": "ADVANCED",
122 | "advanced_visibility": {
123 | "boolean_operator": "AND",
124 | "criteria": [
125 | {
126 | "controlling_field": "button_target",
127 | "controlling_value_regex": "payment_link",
128 | "operator": "EQUAL"
129 | },
130 | {
131 | "controlling_field": "payment_link",
132 | "controlling_value_regex": "id\":\\d+",
133 | "operator": "MATCHES_REGEX"
134 | }
135 | ]
136 | },
137 | "choices": [
138 | ["new_tab", "Open in a new tab"],
139 | ["overlay", "Sliding overlay"]
140 | ],
141 | "display": "radio",
142 | "default": "overlay"
143 | },
144 | {
145 | "label": "Styles",
146 | "name": "styles",
147 | "type": "group",
148 | "tab": "STYLE",
149 | "children": [
150 | {
151 | "label": "Features",
152 | "name": "features",
153 | "type": "group",
154 | "children": [
155 | {
156 | "label": "Icon",
157 | "name": "icon",
158 | "type": "group",
159 | "children": [
160 | {
161 | "label": "Color",
162 | "name": "color",
163 | "type": "color",
164 | "visibility": {
165 | "hidden_subfields": {
166 | "opacity": true
167 | }
168 | }
169 | }
170 | ]
171 | },
172 | {
173 | "label": "Text",
174 | "name": "text",
175 | "type": "group",
176 | "children": [
177 | {
178 | "label": "Font",
179 | "name": "font",
180 | "type": "font"
181 | }
182 | ]
183 | },
184 | {
185 | "label": "Border",
186 | "name": "border",
187 | "type": "group",
188 | "children": [
189 | {
190 | "label": "Color",
191 | "name": "color",
192 | "type": "color"
193 | }
194 | ]
195 | },
196 | {
197 | "label": "Alignment",
198 | "name": "alignment",
199 | "type": "group",
200 | "children": [
201 | {
202 | "label": "Alignment",
203 | "name": "alignment",
204 | "type": "alignment",
205 | "alignment_direction": "HORIZONTAL"
206 | }
207 | ]
208 | }
209 | ]
210 | },
211 | {
212 | "label": "Price",
213 | "name": "price",
214 | "type": "group",
215 | "children": [
216 | {
217 | "label": "Text",
218 | "name": "text",
219 | "type": "group",
220 | "children": [
221 | {
222 | "label": "Font",
223 | "name": "font",
224 | "type": "font"
225 | }
226 | ]
227 | },
228 | {
229 | "label": "Alignment",
230 | "name": "alignment",
231 | "type": "group",
232 | "children": [
233 | {
234 | "label": "Alignment",
235 | "name": "alignment",
236 | "type": "alignment",
237 | "alignment_direction": "HORIZONTAL"
238 | }
239 | ]
240 | }
241 | ]
242 | },
243 | {
244 | "label": "Button",
245 | "name": "button",
246 | "type": "group",
247 | "children": [
248 | {
249 | "label": "Text",
250 | "name": "text",
251 | "type": "group",
252 | "children": [
253 | {
254 | "label": "Font",
255 | "name": "font",
256 | "type": "font"
257 | }
258 | ]
259 | },
260 | {
261 | "label": "Background",
262 | "name": "background",
263 | "type": "group",
264 | "children": [
265 | {
266 | "label": "Color",
267 | "name": "color",
268 | "type": "color"
269 | }
270 | ]
271 | },
272 | {
273 | "label": "Border",
274 | "name": "border",
275 | "type": "group",
276 | "children": [
277 | {
278 | "label" : "Border",
279 | "name" : "border",
280 | "type" : "border"
281 | }
282 | ]
283 | },
284 | {
285 | "label": "Corner",
286 | "name": "corner",
287 | "type": "group",
288 | "children": [
289 | {
290 | "label": "Radius",
291 | "name": "radius",
292 | "type": "number",
293 | "display": "text",
294 | "max": 100,
295 | "step": 1,
296 | "suffix": "px"
297 | }
298 | ]
299 | },
300 | {
301 | "label": "Spacing",
302 | "name": "spacing",
303 | "type": "group",
304 | "children": [
305 | {
306 | "label": "Spacing",
307 | "name": "spacing",
308 | "type": "spacing",
309 | "visibility": {
310 | "hidden_subfields": {
311 | "margin": true
312 | }
313 | }
314 | }
315 | ]
316 | },
317 | {
318 | "label": "Alignment",
319 | "name": "alignment",
320 | "type": "group",
321 | "children": [
322 | {
323 | "label": "Alignment",
324 | "name": "alignment",
325 | "type": "alignment",
326 | "alignment_direction": "HORIZONTAL"
327 | }
328 | ]
329 | }
330 | ]
331 | },
332 | {
333 | "label": "Card",
334 | "name": "card",
335 | "type": "group",
336 | "children": [
337 | {
338 | "label": "Background",
339 | "name": "background",
340 | "type": "group",
341 | "children": [
342 | {
343 | "label": "Background type",
344 | "name": "background_type",
345 | "id": "styles.card.background.background_type",
346 | "type": "choice",
347 | "choices": [
348 | ["none", "None"],
349 | ["color", "Background color"],
350 | ["gradient", "Background gradient"],
351 | ["image", "Background image"]
352 | ],
353 | "display": "radio",
354 | "default": "none"
355 | },
356 | {
357 | "label": "Color",
358 | "name": "color",
359 | "type": "color",
360 | "visibility": {
361 | "controlling_field": "styles.card.background.background_type",
362 | "controlling_value_regex": "color",
363 | "operator": "EQUAL"
364 | }
365 | },
366 | {
367 | "label": "Gradient",
368 | "name": "gradient",
369 | "type": "gradient",
370 | "visibility": {
371 | "controlling_field": "styles.card.background.background_type",
372 | "controlling_value_regex": "gradient",
373 | "operator": "EQUAL"
374 | }
375 | },
376 | {
377 | "label": "Image",
378 | "name": "image",
379 | "type": "backgroundimage",
380 | "visibility": {
381 | "controlling_field": "styles.card.background.background_type",
382 | "controlling_value_regex": "image",
383 | "operator": "EQUAL"
384 | }
385 | }
386 | ]
387 | },
388 | {
389 | "label": "Border",
390 | "name": "border",
391 | "type": "group",
392 | "children": [
393 | {
394 | "label": "Border",
395 | "name": "border",
396 | "type": "border"
397 | }
398 | ]
399 | },
400 | {
401 | "label": "Corner",
402 | "name": "corner",
403 | "type": "group",
404 | "children": [
405 | {
406 | "label": "Radius",
407 | "name": "radius",
408 | "type": "number",
409 | "display": "text",
410 | "max": 100,
411 | "step": 1,
412 | "suffix": "px"
413 | }
414 | ]
415 | },
416 | {
417 | "label": "Spacing",
418 | "name": "spacing",
419 | "type": "group",
420 | "children": [
421 | {
422 | "label": "Spacing",
423 | "name": "spacing",
424 | "type": "spacing"
425 | }
426 | ]
427 | }
428 | ]
429 | }
430 | ]
431 | }
432 | ]
433 |
--------------------------------------------------------------------------------
/src/modules/pricing-card.module/module.html:
--------------------------------------------------------------------------------
1 | {# Module variables #}
2 |
3 | {# Setting variable to true if the button_target field has payment_link selected (based on new field setup in comments for this PR #}
4 |
5 | {% set has_payment_link = module.button_target == "payment_link" %}
6 |
7 | {# Setting variable to true if the checkout_behavior is set to overlay #}
8 |
9 | {% set has_overlay = has_payment_link and module.checkout_behavior == "overlay" %}
10 |
11 | {# Sets attributes used for the link field #}
12 |
13 | {% if has_payment_link %}
14 | {% set href = module.payment_link.properties.checkoutUrl ~ "?referrer=CMS_MODULE_NEWTAB" %}
15 | {% set data_src = module.payment_link.properties.checkoutUrl ~ "?referrer=CMS_MODULE_OVERLAY&layout=full-page-overlay" %}
16 | {% do rel.append("nofollow") %}
17 | {% do rel.append("noopener") %}
18 | {% else %}
19 | {% set href = module.button_link.url.href %}
20 | {% if module.button_link.url.type is equalto "EMAIL_ADDRESS" %}
21 | {% set href = "mailto:" + href %}
22 | {% endif %}
23 | {% set rel = [] %}
24 | {% if module.button_link.no_follow %}
25 | {% do rel.append("nofollow") %}
26 | {% endif %}
27 | {% if module.button_link.open_in_new_tab %}
28 | {% do rel.append("noopener") %}
29 | {% endif %}
30 | {% endif %}
31 |
32 | {# Module styles #}
33 |
34 | {% require_css %}
35 |
122 | {% end_require_css %}
123 |
124 | {# Pricing card #}
125 |
126 |
127 | {% if module.tier and module.description %}
128 |
136 | {% endif %}
137 |
138 |
139 |
140 | {% for feature in module.features %}
141 |
142 | {% icon
143 | extra_classes="card__icon",
144 | name="{{ module.feature_icon.name }}",
145 | purpose="decorative",
146 | style="{{ module.feature_icon.type }}",
147 | unicode="{{ module.feature_icon.unicode }}"
148 | %}{{ feature|escape_html }}
149 |
150 | {% endfor %}
151 |
152 |
153 |
{{ module.price|escape_html }}{{ module.timeframe|escape_html }}
154 |
170 |
171 |
172 |
173 | {% if has_overlay %}
174 |
175 |
176 |
177 |
178 |
179 |
180 | {{ module.default_text.close_checkout|escape_html }}
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 | {# A focusable element is required to come after the iframe in order to trap focus in the overlay #}
191 |
192 |
{{ module.default_text.close_checkout|escape_html }}
193 |
194 | {% endif %}
195 |
196 | {# Module JS #}
197 |
198 | {% if has_overlay %}
199 | {% require_js %}
200 |
327 | {% end_require_js %}
328 | {% endif %}
329 |
--------------------------------------------------------------------------------