diff --git a/app/components/calls_to_action/adviser_component.html.erb b/app/components/calls_to_action/adviser_component.html.erb new file mode 100644 index 0000000000..7c55b6340e --- /dev/null +++ b/app/components/calls_to_action/adviser_component.html.erb @@ -0,0 +1,18 @@ +<%= tag.div(class: "adviser--border-top") if border %> +<%= tag.div class: classes do %> +
+ <%= image_pack_tag(image, + **helpers.image_alt_attribs_for_text(""), + class: "adviser__image") + %> +
+ +
+

+ <%= tag.span title if title.present? %> +

+ <%= tag.p text, class: 'adviser__text' if text.present? %> +

+ <%= link_to link_text, link_target, class: "button", role: "button", data: { "promo-type": "adviser" } if link_text.present? && link_target.present? %> +
+<% end %> diff --git a/app/components/calls_to_action/adviser_component.rb b/app/components/calls_to_action/adviser_component.rb new file mode 100644 index 0000000000..836c3c270f --- /dev/null +++ b/app/components/calls_to_action/adviser_component.rb @@ -0,0 +1,23 @@ +class CallsToAction::AdviserComponent < ViewComponent::Base + attr_reader :title, :text, :image, :link_text, :link_target, :classes, :border + + def initialize( + title: "Get free one-to-one support", + text: "An adviser with years of teaching experience can help you to become a teacher. Chat by phone, text, or email as little or often as you need.", + image: "static/images/adviser-black.png", + link_text: "Find out more about advisers", + link_target: "/teacher-training-advisers", + classes: [], + border: true + ) + super + + @title = title + @text = text + @image = image + @link_text = link_text + @link_target = link_target + @classes = ["adviser", *classes].compact.join(" ") + @border = border + end +end diff --git a/app/presenters/content/component_injector.rb b/app/presenters/content/component_injector.rb index 77860de489..4915119a2c 100644 --- a/app/presenters/content/component_injector.rb +++ b/app/presenters/content/component_injector.rb @@ -1,14 +1,26 @@ module Content class ComponentInjector - def initialize(type, params) - @type = type + CTA_PARENT_NAMESPACE = "cta_".freeze + + def initialize(type_string, params) + @type = full_type(type_string) @params = params end + def full_type(type_string) + return unless type_string + + if type_string.starts_with?(CTA_PARENT_NAMESPACE) + "CallsToAction::#{type_string.sub(CTA_PARENT_NAMESPACE, '').camelize}Component" + else + "Content::#{type_string.camelize}Component" + end + end + def component return unless @params - klass = "Content::#{@type.camelize}Component".constantize + klass = @type.constantize klass.new(**@params.deep_symbolize_keys) end end diff --git a/app/views/content/train-to-be-a-teacher/promos/_adviser-promo-degree.html.erb b/app/views/content/train-to-be-a-teacher/promos/_adviser-promo-degree.html.erb index 66de463082..46e4a4931b 100644 --- a/app/views/content/train-to-be-a-teacher/promos/_adviser-promo-degree.html.erb +++ b/app/views/content/train-to-be-a-teacher/promos/_adviser-promo-degree.html.erb @@ -1,8 +1,4 @@ -<%= render(CallsToAction::Promo::PromoComponent.new) do |promo| %> - <% promo.with_left_section(classes: %w[tta-background]) %> - <% promo.with_right_section(heading: "Get free one-to-one support") do %> -

Talk to an adviser with years of teaching experience about your different training and funding options. Chat through phone, text or email, as little or as often as you need.

- - <%= link_to("Find out more about advisers", "/teacher-training-advisers", class: "button") %> - <% end %> -<% end %> +<%= render CallsToAction::AdviserComponent.new( + text: "Talk to an adviser with years of teaching experience about your different training and funding options. Chat through phone, text or email, as little or as often as you need.", + border: "adviser--border-top" +) %> diff --git a/app/webpacker/images/adviser-black.png b/app/webpacker/images/adviser-black.png new file mode 100644 index 0000000000..5e9bcb182b Binary files /dev/null and b/app/webpacker/images/adviser-black.png differ diff --git a/app/webpacker/styles/components/adviser.scss b/app/webpacker/styles/components/adviser.scss new file mode 100644 index 0000000000..6a1c654ddc --- /dev/null +++ b/app/webpacker/styles/components/adviser.scss @@ -0,0 +1,81 @@ +.adviser { + max-width: $content-max-width; + display: flex; + flex-direction: column; + gap: $indent-amount * .5; + margin: 0 auto; + background-color: $grey; + + @include mq($from: tablet) { + flex-direction: row; + margin: 0 auto; + gap: 2 * $indent-amount; + } + + @include mq($until: tablet) { + &--border-top { + display: none; + } + } + + @include mq($from: tablet) { + &--border-top { + display: block; + border-top: 1px solid $grey-mid; + padding-top: 3em; + margin: 0 auto; + max-width: $content-max-width; + } + } + + &:last-of-type { + margin-bottom: 3em; + } + + &__image { + height: 10em; + width: auto; + } + + &__left { + flex: 0 1 45%; + padding-block: 2em; + min-height: 8em; + background-color: $yellow; + padding: 1em; + align-content: center; + text-align: center; + } + + &__right { + flex: 0 1 55%; + align-items: flex-start; + display: flex; + flex-direction: column; + padding-right: $indent-amount; + padding-bottom: $indent-amount; + + @include mq($until: tablet) { + padding-left: $indent-amount; + } + + @include mq($from: tablet) { + padding-top: $indent-amount; + } + + p, + h2 { + margin-top: 0; + } + + label { + font-weight: bold; + display: block; + } + + label, + input { + margin-bottom: .4em; + } + } +} diff --git a/app/webpacker/styles/git.scss b/app/webpacker/styles/git.scss index bad8a9d641..9b360d2d88 100644 --- a/app/webpacker/styles/git.scss +++ b/app/webpacker/styles/git.scss @@ -34,6 +34,7 @@ @import "./sections/talk-to-us"; @import "./sections/action-container"; +@import "./components/adviser"; @import "./components/arrow"; @import "./components/aspect-ratio"; @import "./components/badge"; diff --git a/docs/content.md b/docs/content.md index 48c45d4444..e1c743ed68 100644 --- a/docs/content.md +++ b/docs/content.md @@ -7,31 +7,32 @@ This documentation aims to be a reference for content editors that want to make 1. [Setting up Codespaces and Github](#getting-started) 2. [Finding a Page/Content to Edit](#finding-a-pagecontent-to-edit) 3. [Content Editing Tips/Info](#content-editing-tips-info) - * [Headings](#headings) - * [Frontmatter](#frontmatter) - * [Breadcrumbs](#breadcrumbs) - * [Links](#links) - * [SEO](#seo) - * [Prevent Indexing](#prevent-indexing) - * [Adding a Document or Image](#adding-a-document-or-image) - * [Calls to Action](#calls-to-action) - * [Main Content](#main-content) - * [Sidebar](#sidebar) - * [Accessibility](#accessibility) - * [iframe](#iframe) - * [Inset text](#inset-text) - * [Details expander for non-UK content](#details-expander-for-non-uk-content) - * [YouTube Video](#youtube-video) - * [Hero](#hero) - * [Values](#values) + * [Headings](#headings) + * [Frontmatter](#frontmatter) + * [Breadcrumbs](#breadcrumbs) + * [Links](#links) + * [SEO](#seo) + * [Prevent Indexing](#prevent-indexing) + * [Adding a Document or Image](#adding-a-document-or-image) + * [Calls to Action](#calls-to-action) + * [Adviser (CTA) component](#adviser-cta-component) + * [Main Content](#main-content) + * [Sidebar](#sidebar) + * [Accessibility](#accessibility) + * [iframe](#iframe) + * [Inset text](#inset-text) + * [Details expander for non-UK content](#details-expander-for-non-uk-content) + * [YouTube Video](#youtube-video) + * [Hero](#hero) + * [Values](#values) 4. [Creating a subject page](#creating-a-subject-page) 5. [Creating an inspirational page](#creating-an-inspirational-page) 6. [Creating a Blog Post](#creating-a-blog-post) - * [Images](#images) - * [Footers](#footers) + * [Images](#images) + * [Footers](#footers) 7. [Navigation](#navigation) - * [Main Navigation](#main-navigation) - * [Category Pages](#category-pages) + * [Main Navigation](#main-navigation) + * [Category Pages](#category-pages) 8. [Build errors](#build-errors) 9. [Internship providers](#internship-providers) 10. [Creating a new page](#creating-a-new-page) @@ -334,6 +335,51 @@ If you need to insert an expander into an erb file: ) %> ``` + +### Adviser (CTA) component + +You can use the Adviser (Call to Action) component to create a call to action to invite users to sign up for the Get an Adviser service. You can use the component directly in markdown files, or in ERB-HTMl partials. It takes the following parameters and all are optional - if not specified a default value will be used: + +* title +* text +* image +* link_text +* link_target +* classes +* border + +```yaml +--- +cta_adviser: + adviser1: + title: "Optional title" + text: "Optional text" + image: "/optional/path/to/image" + link_text: "Optional link text" + link_target: "/optional/path" + classes: ["class1", "class2", "class3"] + border: true +--- + +# My page + +$adviser1$ +``` +Alternatively, if you need to insert an adviser component in an erb file, you can call it like this: + +```yaml +<%= render CallsToAction::AdviserComponent.new( + title: "Optional title", + text: "Optional text", + image: "/optional/path/to/image", + link_text: "Optional link text", + link_target: "/optional/path", + classes: ["class1", "class2", "class3"], + border: true +)%> +``` + + ### YouTube video To add a YouTube video to your content you need to know the video ID. You can find this out by visiting the video on [youtube.com](https://www.youtube.com/) and looking in the address bar of your browser (it is in the format `watch?v=`). diff --git a/lib/template_handlers/markdown.rb b/lib/template_handlers/markdown.rb index 199d0ca285..e139033c20 100644 --- a/lib/template_handlers/markdown.rb +++ b/lib/template_handlers/markdown.rb @@ -10,7 +10,7 @@ class Markdown DEFAULTS = {}.freeze GLOBAL_FRONT_MATTER = Rails.root.join("config/frontmatter.yml").freeze - COMPONENT_TYPES = %w[quote quote_list inset_text youtube_video steps expander].freeze + COMPONENT_TYPES = %w[quote quote_list inset_text youtube_video steps expander cta_adviser].freeze class << self def call(template, source = nil) diff --git a/spec/components/calls_to_action/adviser_component_spec.rb b/spec/components/calls_to_action/adviser_component_spec.rb new file mode 100644 index 0000000000..57966b5a58 --- /dev/null +++ b/spec/components/calls_to_action/adviser_component_spec.rb @@ -0,0 +1,62 @@ +require "rails_helper" + +RSpec.describe CallsToAction::AdviserComponent, type: :component do + let(:title) { "Some Title" } + let(:text) { "Lorum ipsum dollar" } + let(:image) { "static/images/adviser-black.png" } + let(:link_text) { "Find out more about advisers" } + let(:link_target) { "/somewhere" } + + describe "rendering the component" do + let(:kwargs) { { title: title, text: text, image: image, link_text: link_text, link_target: link_target } } + let(:component) { described_class.new(**kwargs) } + + before { render_inline(component) { content } } + + specify "renders the adviser component" do + expect(page).to have_css(".adviser") + end + + specify "the image is present" do + image_element = page.find("img") + + expect(image_element[:src]).to match(Regexp.new(File.basename(image, ".*"))) + expect(image_element[:alt]).to eql("") + end + + specify "the title is present" do + expect(page).to have_css(".heading-l", text: title) + end + + specify "the text is present" do + expect(page).to have_css("p.adviser__text", text: text) + end + + specify "the link is present" do + expect(page).to have_link(link_text, href: link_target) + end + + context "when no title is present" do + let(:kwargs) { { text: text, image: image, link_text: link_text, link_target: link_target } } + + specify "it should use the default title" do + expect(page).to have_css(".heading-l", text: "Get free one-to-one support") + end + end + + context "when no link is present" do + let(:link_text) { nil } + let(:link_target) { nil } + + it { expect(page).not_to have_css("a") } + end + + context "when no text is present" do + let(:text) { nil } + + specify "no paragraph tag should be rendered" do + expect(page).not_to have_css("p.adviser__text") + end + end + end +end