From c77164a7d3e35609518d3dcf0bc57ff6de64c694 Mon Sep 17 00:00:00 2001 From: Julie Muzina Date: Sat, 1 Nov 2025 23:49:19 -0400 Subject: [PATCH] quote wrapper - new grid, blocks --- .../_macros/shared/vf_section_top_rule.jinja | 13 +- templates/_macros/vf_quote-wrapper.jinja | 431 ++++++++++++------ .../quote-wrapper/block-no-signpost.html | 33 ++ .../patterns/quote-wrapper/block.html | 38 ++ .../patterns/quote-wrapper/combined.html | 3 + .../patterns/quote-wrapper/multiple.html | 23 + 6 files changed, 393 insertions(+), 148 deletions(-) create mode 100644 templates/docs/examples/patterns/quote-wrapper/block-no-signpost.html create mode 100644 templates/docs/examples/patterns/quote-wrapper/block.html create mode 100644 templates/docs/examples/patterns/quote-wrapper/multiple.html diff --git a/templates/_macros/shared/vf_section_top_rule.jinja b/templates/_macros/shared/vf_section_top_rule.jinja index 179936264..bcb859bc5 100644 --- a/templates/_macros/shared/vf_section_top_rule.jinja +++ b/templates/_macros/shared/vf_section_top_rule.jinja @@ -1,7 +1,12 @@ # Helper macro to render a top rule for a section. # Parameters: -# - top_rule_variant: string, one of "default", "muted", "highlighted", "none" -{%- macro vf_section_top_rule(top_rule_variant="default") -%} +# - top_rule_variant("default" | "muted" | "highlighted" |"none"): variant of horizontal rule to use +# - is_fixed_width(Boolean): Whether to constrain the rule by the fixed content width. Default to False. +# If you don't use this, you should wrap the rule in a .grid-row. +{%- macro vf_section_top_rule( + top_rule_variant="default", + is_fixed_width=False +) -%} {%- set top_rule_variant = top_rule_variant | trim | lower -%} {%- if top_rule_variant not in ["default", "muted", "highlighted", "none"] -%} {%- set top_rule_variant = "default" -%} @@ -23,6 +28,10 @@ {%- endif -%} {%- endif -%} + {%- if is_fixed_width -%} + {%- set top_rule_classes = top_rule_classes + " " + "is-fixed-width" -%} + {%- endif -%} + {%- if top_rule_variant != "none" -%}
{%- endif -%} diff --git a/templates/_macros/vf_quote-wrapper.jinja b/templates/_macros/vf_quote-wrapper.jinja index 024f28aeb..b2de8752d 100644 --- a/templates/_macros/vf_quote-wrapper.jinja +++ b/templates/_macros/vf_quote-wrapper.jinja @@ -1,3 +1,240 @@ +{% from "_macros/shared/vf_section_top_rule.jinja" import vf_section_top_rule %} + +{#- + Params + - body + - size ("small" | "medium" | "large") + - text (str) + -#} +{%- macro _quote_wrapper_body_block(body={}) -%} + {%- set quote_size = body.get("size", "") | trim | lower -%} + {%- set quote_text = body.get("text", "") | trim -%} + + {# Translate quote size param to quote heading level #} + {% if quote_size == 'large' %} + {% set quote_heading_level = 2 %} + {% elif quote_size == 'small' %} + {% set quote_heading_level = 6 %} + {% else %} + {% set quote_heading_level = 4 %} + {% endif %} + + {%- if quote_text | length > 0 -%} +

+ + “{{ quote_text }}” + +

+ {%- endif -%} +{%- endmacro %} + +{#- + Params + - citation + - name + - organisation + - title + -#} +{%- macro _quote_wrapper_citation_block(citation={}) -%} + {%- set citation_source_name = citation.get("name", "") | trim -%} + {%- set citation_source_title = citation.get("title", "") | trim -%} + {%- set citation_source_organisation = citation.get("organisation", "") | trim -%} + + {%- set has_citation_source_name = citation_source_name | length > 0 -%} + {%- set has_citation_source_title = citation_source_title | length > 0 -%} + {%- set has_citation_source_organisation = citation_source_organisation | length > 0 -%} + {%- set has_citation = has_citation_source_name or has_citation_source_title or has_citation_source_organisation -%} + + {%- if has_citation -%} + {#- Optional citation block -#} +

+ {% if has_citation_source_name -%} + {#- Optional citation source name -#} + {{ citation_source_name }} + {% if has_citation_source_title or has_citation_source_organisation -%} + {#- If the citation name is followed by title and/or organisation, add a line break -#} +
+ {% endif -%} + {% endif -%} + {% if has_citation_source_title or has_citation_source_organisation -%} + {#- Optional citation source title and/or organisation -#} + + {% if has_citation_source_title -%} + {#- Optional citation source title -#} + {{ citation_source_title }} + {%- if has_citation_source_organisation %} + {#- Add a line break between the title and org if both are present -#} +
+ {%- endif %} + {% endif %} + {%- if has_citation_source_organisation -%} + {#- Optional citation source organisation -#} + {{ citation_source_organisation }} + {%- endif %} +
+ {%- endif %} +

+ {% endif %} +{%- endmacro -%} + +{#- + Params + - heading + - title + - text + - link + - html + #} +{%- macro _quote_wrapper_heading_block(heading={}) %} + {%- set heading_title_text = heading.get("title", {}).get("text", "") | trim -%} + {%- set heading_link_html = heading.get("link", {}).get("html", "") | trim -%} + {%- set has_heading_title = heading_title_text | length > 0 -%} + {%- set has_heading_link = heading_link_html | length > 0 -%} + {%- set has_heading_row = has_heading_title or has_heading_link -%} + + {% if has_heading_row -%} + {#- Optional heading -#} +
+
+ {%- if has_heading_title %} + {#- Optional heading text -#} +
+

{{ heading_title_text }}

+
+ {%- endif -%} + + {%- if has_heading_link %} + {#- Optional heading link -#} +
+

+ {{ heading_link_html }} +

+
+ {% endif -%} +
+
+ {% endif -%} +{%- endmacro %} + +{#- + Params + - cta + - html (String) +-#} +{%- macro _quote_wrapper_cta_block(cta={}) -%} + {%- set cta_html = cta.get("html", "") | trim -%} + {% if cta_html | length > 0 %} + {#- Optional CTA block -#} +
+ {{- cta_html -}} +
+ {%- endif -%} +{%- endmacro -%} + +{#- + This macro exposes the main contents of the quote wrapper pattern. + this includes the citation, body (quote itself), CTA, and image. + Params + - contents + - citation + - name + - organisation + - title + - body + - size ("small" | "medium" | "large") + - text (String) + - cta + - html (String) + - image + - html (String) + #} +{%- macro _quote_wrapper_block_contents_column(contents={}) -%} + {%- set citation = contents.get("citation", {}) -%} + {%- set body = contents.get("body", {}) -%} + {%- set cta = contents.get("cta", {}) -%} + {%- set image = contents.get("image", {}) -%} + {%- set has_citation = (citation.get("name") or citation.get("title") or citation.get("organisation")) | trim | length > 0 -%} + {%- set has_cta = cta.get("html") | trim | length > 0 -%} + {%- set has_image = image.get("html") | trim | length > 0 -%} + {% if has_citation -%} + {#- When a citation is present, wrap the quote and citation in a nested grid to space them properly -#} +
+
+ {{ _quote_wrapper_body_block(body=body) }} +
+
+ {{ _quote_wrapper_citation_block(citation=citation) }} +
+
+ {% else -%} + {#- When no citation is present, display quote body without a nested grid -#} + {{ _quote_wrapper_body_block(body=body) }} + {% endif -%} + + {#- Optional CTA and/or image block -#} + {{ _quote_wrapper_cta_block(cta=cta) }} + + {#- Optional image block -#} + {{ image.get("html", "") }} +{%- endmacro -%} + +{#- + Params + - image (required) + - html (String) +-#} +{%- macro _quote_wrapper_block_signpost_column(signpost={}) -%} + {%- set signpost_html = signpost.get("image", {}).get("html", "") | trim -%} + {%- if signpost_html | length > 0 -%} +
+ {{ signpost_html | safe }} +
+ {%- endif -%} +{%- endmacro -%} + +{#- + Params + - signpost (optional) + - image + - html (String) + - contents (required) + - body + - size ("small" | "medium" | "large") + - text (str) + - citation + - name + - organisation + - title + - cta + - html (String) + - image + - html (String) + - has_divider (boolean) (optional): Whether to show a divider above the contents column when it is stacked with preceding content. Defaults to false. + - Note: passing a signpost will force this to True. +-#} +{%- macro vf_quote_block(signpost={}, contents={}) -%} + {%- set signpost_html = signpost.get("image", {}).get("html", "") | trim -%} + {%- set has_signpost = signpost_html | length > 0 -%} +
+ {%- if has_signpost -%} +
+ {%- if contents.get("has_divider", False) -%} +
+ {%- endif -%} + {#- Optional signpost image -#} + {{- _quote_wrapper_block_signpost_column(signpost=signpost) -}} +
+ {%- endif -%} + +
+ {%- if contents.get("has_divider", False) -%} +
+ {%- endif -%} + {{- _quote_wrapper_block_contents_column(contents=contents) -}} +
+
+{%- endmacro -%} + {# Params - title_text (string) (optional): The text to be displayed as the heading @@ -22,152 +259,54 @@ citation_source_organisation_text="", is_shallow=False ) -%} - {% set heading_link_content = caller('heading_link') %} - {% set has_heading_link = heading_link_content|trim|length > 0 %} - {% set has_title = title_text|length > 0 %} - {% set has_heading_row = has_title or has_heading_link %} - {% set signpost_image_content = caller('signpost_image') %} - {% set has_signpost_image = signpost_image_content|trim|length > 0 %} - {% set has_citation_source_name = citation_source_name_text|trim|length > 0 %} - {% set has_citation_source_title = citation_source_title_text|trim|length > 0 %} - {% set has_citation_source_organisation = citation_source_organisation_text|trim|length > 0 %} - {% set has_citation = has_citation_source_name or has_citation_source_title or has_citation_source_organisation %} - {% set cta_content = caller('cta') %} - {% set has_cta = cta_content|trim|length > 0 %} - {% set image_content = caller('image') %} - {% set has_image = image_content|trim|length > 0 %} - {% set quote_size = quote_size|trim|lower %} - - {# Translate quote size param to quote heading level #} - {% if quote_size == 'large' %} - {% set quote_heading_level = 2 %} - {% elif quote_size == 'small' %} - {% set quote_heading_level = 6 %} - {% else %} - {% set quote_heading_level = 4 %} - {% endif %} - - {%- macro _quote_body() -%} -
-

- - “{{ quote_text }}” - -

-
- {%- endmacro %} + {% set heading_link_content = caller('heading_link') %} + {% set has_heading_link = heading_link_content|trim|length > 0 %} + {% set has_title = title_text|length > 0 %} + {% set has_heading_row = has_title or has_heading_link %} + {% set signpost_image_content = caller('signpost_image') %} + {% set has_signpost_image = signpost_image_content|trim|length > 0 %} - {%- macro _citation_block() -%} - {%- if has_citation -%} - {#- Optional citation block -#} -

- {% if has_citation_source_name -%} - {#- Optional citation source name -#} - {{ citation_source_name_text }} - {% if has_citation_source_title or has_citation_source_organisation -%} - {#- If the citation name is followed by title and/or organisation, add a line break -#} -
- {% endif -%} - {% endif -%} - {% if has_citation_source_title or has_citation_source_organisation -%} - {#- Optional citation source title and/or organisation -#} - - {% if has_citation_source_title -%} - {#- Optional citation source title -#} - {{ citation_source_title_text }} - {%- if has_citation_source_organisation %} - {#- Add a line break between the title and org if both are present -#} -
- {%- endif %} - {% endif %} - {%- if has_citation_source_organisation -%} - {#- Optional citation source organisation -#} - {{ citation_source_organisation_text }} - {%- endif %} -
- {%- endif %} -

- {% endif %} - {%- endmacro -%} - - {%- macro _heading_block() %} - {% if has_heading_row -%} - {#- Optional heading -#} -
-
-
- {%- if has_title %} - {#- Optional heading text -#} -
-

{{ title_text }}

-
- {%- endif -%} - - {%- if has_heading_link %} - {#- Optional heading link -#} -
-

- {{ heading_link_content }} -

-
- {% endif -%} -
-
- {% endif -%} - {%- endmacro %} - -
- {{- _heading_block() -}} -
- {% if has_signpost_image -%} - {% if not has_heading_row %} - {#- - If a signpost is present, but no heading row, the signpost is the first piece of content in the pattern on small. - So, we place a standard rule above the signpost to separate it from the preceding section. - -#} -
- {% endif %} - {#- Optional signpost image -#} -
-
- {{ signpost_image_content }} -
-
- {% endif -%} - -
-
- {% if has_citation -%} - {#- When a citation is present, wrap the quote and citation in a nested grid to space them properly -#} -
-
- {{ _quote_body() }} -
-
-
- {{ _citation_block() }} -
-
- {% else -%} - {#- When no citation is present, display quote body without a nested grid -#} - {{ _quote_body() }} - {% endif -%} - - {%- if has_cta or has_image -%} - {#- Optional CTA and/or image block -#} - {%- if has_cta %} - {#- Optional CTA block -#} -
- {{ cta_content }} -
- {% endif -%} - - {% if has_image -%} - {#- Optional image block -#} - {{ image_content }} - {% endif -%} - {% endif -%} -
+
+ {#- pattern-level separator -#} + {%- if has_heading_row -%} + {{ vf_section_top_rule(top_rule_variant="default", is_fixed_width=True) }} + {%- endif -%} + {{- _quote_wrapper_heading_block( + heading={ + "title": { + "text": title_text + }, + "link": { + "html": heading_link_content + } + } + ) -}} + {#- TODO use `content.has_divider` only for non-first quote blocks once we support multiple quotes per pattern. -#} + {#- TODO add shallow spacing between each quote block in the pattern once we support multiple quotes per pattern. -#} + {{- vf_quote_block( + signpost={ + "image": { + "html": signpost_image_content + } + }, + contents={ + "body": { + "size": quote_size, + "text": quote_text + }, + "citation": { + "name": citation_source_name_text, + "title": citation_source_title_text, + "organisation": citation_source_organisation_text + }, + "image": { + "html": caller('image') + }, + "cta": { + "html": caller('cta') + }, + "has_divider": not has_heading_row + } + ) -}}
-
{% endmacro -%} \ No newline at end of file diff --git a/templates/docs/examples/patterns/quote-wrapper/block-no-signpost.html b/templates/docs/examples/patterns/quote-wrapper/block-no-signpost.html new file mode 100644 index 000000000..b0b5ba39b --- /dev/null +++ b/templates/docs/examples/patterns/quote-wrapper/block-no-signpost.html @@ -0,0 +1,33 @@ +{% extends "_layouts/examples.html" %} +{% from "_macros/vf_quote-wrapper.jinja" import vf_quote_block %} + +{% block title %}Quote block{% endblock %} +{% block standalone_css %}patterns_all{% endblock %} + +{% block content %} + +{{- vf_quote_block( + contents={ + "body": { + "size": "large", + "text": "This is a company where intelligence and learning are highly valued." + }, + "citation": { + "name": "Alyson Richens", + "organisation": "Canonical", + "title": "Customer Success Manager" + }, + "cta": { + "html": "Explore careers ›" + }, + "image": { + "html": " +
+ Ubuntu Summit crowd +
+ " + } + } +) -}} + +{% endblock %} \ No newline at end of file diff --git a/templates/docs/examples/patterns/quote-wrapper/block.html b/templates/docs/examples/patterns/quote-wrapper/block.html new file mode 100644 index 000000000..c9f1af7cc --- /dev/null +++ b/templates/docs/examples/patterns/quote-wrapper/block.html @@ -0,0 +1,38 @@ +{% extends "_layouts/examples.html" %} +{% from "_macros/vf_quote-wrapper.jinja" import vf_quote_block %} + +{% block title %}Quote block / No signpost{% endblock %} +{% block standalone_css %}patterns_all{% endblock %} + +{% block content %} + +{{- vf_quote_block( + contents={ + "body": { + "size": "large", + "text": "This is a company where intelligence and learning are highly valued." + }, + "citation": { + "name": "Alyson Richens", + "organisation": "Canonical", + "title": "Customer Success Manager" + }, + "cta": { + "html": "Explore careers ›" + }, + "image": { + "html": " +
+ Ubuntu Summit crowd +
+ " + } + }, + signpost={ + "image": { + "html": "Canonical logo" + } + } +) -}} + +{% endblock %} \ No newline at end of file diff --git a/templates/docs/examples/patterns/quote-wrapper/combined.html b/templates/docs/examples/patterns/quote-wrapper/combined.html index 85ca3a8f3..e2d5fe13f 100644 --- a/templates/docs/examples/patterns/quote-wrapper/combined.html +++ b/templates/docs/examples/patterns/quote-wrapper/combined.html @@ -22,5 +22,8 @@
{% include 'docs/examples/patterns/quote-wrapper/small-no-signpost.html' %}
{% include 'docs/examples/patterns/quote-wrapper/small-no-citation.html' %}
{% include 'docs/examples/patterns/quote-wrapper/small-no-header.html' %}
+
{% include 'docs/examples/patterns/quote-wrapper/multiple.html' %}
+
{% include 'docs/examples/patterns/quote-wrapper/block.html' %}
+
{% include 'docs/examples/patterns/quote-wrapper/block-no-signpost.html' %}
{% endwith %} {% endblock %} diff --git a/templates/docs/examples/patterns/quote-wrapper/multiple.html b/templates/docs/examples/patterns/quote-wrapper/multiple.html new file mode 100644 index 000000000..4be12f5e4 --- /dev/null +++ b/templates/docs/examples/patterns/quote-wrapper/multiple.html @@ -0,0 +1,23 @@ +{% extends "_layouts/examples.html" %} +{% from "_macros/vf_quote-wrapper.jinja" import vf_quote_wrapper %} + +{% block title %}Quote Wrapper / Multiple quotes{% endblock %} +{% block standalone_css %}patterns_all{% endblock %} + +{% block content %} + +{% call(slot) vf_quote_wrapper( + title_text="Hear from our community", + quote_size="small", + quote_text="Ubuntu is used so much everywhere that you can get drivers for everything, and there's a great community. It's ease-of-use makes everything faster, and not just for those of us who are already familiar with it. Even engineers without a software background can work on Ubuntu without issue", + citation_source_name_text="Sam Watson Jones", + citation_source_title_text="CEO, Small Robot Company", +) -%}{% endcall -%} + +{% call(slot) vf_quote_wrapper( + quote_size="small", + quote_text="We needed an operating system that was open, easy to modify, and reliable.", + citation_source_title_text="CEO, Northstar Robotics", +) -%}{% endcall -%} + +{% endblock %}