Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -248,5 +248,30 @@ def boolean_to_text(value)
value ? 'Yes' : 'No'
end

# Heading levels per render context and semantic role. The embedded widget is
# injected into host pages that already own the top-level <h1>, so its title
# is demoted to <h2> (and alerts to <h3>) to preserve valid heading order.
# Hosted forms own the page, so the title is the <h1>.
HEADING_LEVELS = {
hosted: { title: 'h1', alert: 'h2' },
embedded: { title: 'h2', alert: 'h3' },
}.freeze

# Context in which a form is being rendered for display, either :hosted or :embedded.
# Passed explicitly as a `render_context` local down each
# partial chain (:hosted from submissions/new, :embedded from components/widget/_fba).
# Defaults to :hosted to catch uses of partials in the form editor.
def form_render_context(render_context = nil)
render_context || :hosted
end

def title_heading_level(render_context = nil)
HEADING_LEVELS.fetch(form_render_context(render_context)).fetch(:title)
end

def alert_heading_level(render_context = nil)
HEADING_LEVELS.fetch(form_render_context(render_context)).fetch(:alert)
end

delegate :fiscal_year_and_quarter, to: :FiscalYear
end
174 changes: 118 additions & 56 deletions app/views/admin/forms/example.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,98 @@

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example page got spiffed up a bit but has no fundamental changes. This is the page where you can preview how your embedded form will look when it is embedded on a webpage.

<!-- Demo content styles -->
<style>
:root {
--demo-bg: #f0f0f0;
--demo-surface: #ffffff;
--demo-border: #dfe1e2;
--demo-ink: #1b1b1b;
--demo-muted: #71767a;
--demo-accent: #005ea2;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
background-color: var(--demo-bg);
color: var(--demo-ink);
font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
line-height: 1.5;
}
.demo-shell {
max-width: 60rem;
margin: 0 auto;
padding: 2rem 1rem 4rem;
}
.demo-content {
background-color: #efefef;
border: 1px solid #E5E5E5;
min-height: 100px;
background-color: var(--demo-surface);
border: 1px solid var(--demo-border);
border-radius: 0.5rem;
}
.demo-header {
text-align: center;
padding: 2.5rem 1.5rem;
margin-bottom: 2rem;
}
.demo-header .demo-eyebrow {
display: block;
font-size: 0.875rem;
font-weight: 600;
letter-spacing: 0.05em;
text-transform: uppercase;
color: var(--demo-muted);
}
.demo-header h1 {
margin: 0.5rem 0 0;
font-size: 2rem;
line-height: 1.2;
}
.demo-grid {
margin-bottom: 4rem;
.demo-main {
padding: 2rem 1.5rem;
margin-bottom: 2rem;
}
.demo-placeholder {
min-height: 12rem;
margin-bottom: 2rem;
}

/* Inline delivery: the form renders directly inside the page body */
.demo-form-region {
padding: 2rem 1.5rem;
}
.demo-form-region .demo-form-label {
display: block;
font-size: 0.875rem;
font-weight: 600;
letter-spacing: 0.05em;
text-transform: uppercase;
color: var(--demo-muted);
margin-bottom: 1rem;
}
.demo-form-target {
background-color: var(--demo-bg);
border: 1px dashed var(--demo-border);
border-radius: 0.375rem;
padding: 1.5rem;
min-height: 6rem;
}

/* Custom button demo */
.demo-button-region {
padding: 3rem 1.5rem;
text-align: center;
}
.demo-grid div {
min-height: 300px;
.demo-custom-button {
display: inline-block;
cursor: pointer;
color: DeepPink;
font-family: sans-serif;
font-size: 2rem;
border: 7px solid DeepPink;
border-radius: 1rem;
padding: 1rem 1.5rem;
background-color: LightPink;
text-decoration: none;
}
</style>
<!-- End demo content styles -->
Expand All @@ -28,65 +110,45 @@
<body>
<!-- Demo content -->
<% if @form.delivery_method == "inline" %>
<br>
<div class="grid-container">
<div class="grid-col-12">
<main>
<div class="demo-shell">
<header class="demo-content demo-header">
<span class="demo-eyebrow">Example page</span>
<h1>Header</h1>
</header>
<main class="demo-content demo-form-region">
<span class="demo-form-label">Inline form</span>
<div class="demo-form-target">
<div id="<%= @form.element_selector %>">
Touchpoint will be rendered here.
</div>
</main>
</div>
</div>
</main>
</div>
<br>
<% elsif @form.delivery_method == "custom-button-modal" %>
<br>
<div class="grid-container">
<div class="grid-col-12">
<div style="padding-left: 5rem; padding-top: 5rem;">
<a id="<%= @form.element_selector %>" style="color: DeepPink; font-family: sans-serif; font-size: 2rem; border: 7px solid DeepPink; border-radius: 1rem; padding: 1rem; background-color: LightPink;">
This is a custom button
</a>
</div>
<div class="demo-shell">
<header class="demo-content demo-header">
<span class="demo-eyebrow">Example page</span>
<h1>Header</h1>
</header>
<div class="demo-content demo-button-region">
<a id="<%= @form.element_selector %>" class="demo-custom-button">
This is a custom button
</a>
</div>
</div>
<br>
<% else %>
<div class="grid-container demo-grid">
<header style="text-align: center;">
<div class="grid-row grid-gap-md">
<div class="grid-col-12 demo-content">
<br>
<span class="font-normal text-sans-sm">
Example page
</span>
<h1>
<br>header
</h1>
</div>
</div>
<div class="demo-shell">
<header class="demo-content demo-header">
<span class="demo-eyebrow">Example page</span>
<h1>Header</h1>
</header>
</div>
<div class="grid-container demo-grid">
<div class="grid-row grid-gap-md">
<div class="grid-col-12 demo-content">
<main>
<div style="text-align: center; padding: 1rem;">
main content
</div>
</main>
<main class="demo-content demo-main">
<div style="text-align: center;">
main content
</div>
</div>
</div>
<div class="grid-container demo-grid">
<div class="grid-row grid-gap-md">
<div class="grid-col-12 demo-content"></div>
</div>
</div>
<div class="grid-container demo-grid">
<div class="grid-row grid-gap-md">
<div class="grid-col-12 demo-content"></div>
</div>
</main>
<div class="demo-content demo-placeholder"></div>
<div class="demo-content demo-placeholder"></div>
</div>
<% end %>
<!--- End demo content -->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<%# locals: (form:, render_context: nil) %>
<br>
<div class="usa-alert usa-alert--info">
<div class="usa-alert__body">
<h3 class="usa-alert__heading">
<%= content_tag alert_heading_level(render_context), class: "usa-alert__heading" do %>
This form is not currently accepting feedback
</h3>
<% end %>
<p class="usa-alert__text">
The form,
<strong><%= form.title %></strong>,
Expand Down
4 changes: 3 additions & 1 deletion app/views/components/forms/_custom.html.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<%# locals: (form:, render_context: nil) %>

<% multi_section_question_number = 0 %>

<form
Expand Down Expand Up @@ -80,7 +82,7 @@
<% elsif question.question_type == "date_select" %>
<%= render 'components/forms/question_types/date_select', form: form, question: question, question_number: multi_section_question_number %>
<% elsif question.question_type == "custom_text_display" %>
<%= render 'components/forms/question_types/custom_text_display', form: form, question: question, question_number: multi_section_question_number %>
<%= render 'components/forms/question_types/custom_text_display', question: question, render_context: render_context %>
<% end %>
</div>
<% else %>
Expand Down
7 changes: 4 additions & 3 deletions app/views/components/forms/_custom_layout.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<%# locals: (form:, render_context: nil) %>
<div class="inner-wrapper">
<div class="grid-row">
<div class="grid-col-12">
<%= render "components/forms/logo_and_title", form: form %>
<%= render "components/forms/logo_and_title", form: form, render_context: render_context %>
<%- if form.instructions.present? %>
<div class="fba-instructions margin-bottom-2">
<%= sanitize(form.instructions) %>
Expand All @@ -14,8 +15,8 @@
</small>
</p>
<% end %>
<%= render 'components/forms/flash', form: form %>
<%= render partial: "components/forms/custom", locals: { form: form, questions: form.questions } %>
<%= render 'components/forms/flash', form: form, render_context: render_context %>
<%= render partial: "components/forms/custom", locals: { form: form, render_context: render_context } %>
</div>
</div>
</div>
Expand Down
9 changes: 5 additions & 4 deletions app/views/components/forms/_flash.html.erb
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
<%# locals: (form:, render_context: nil) %>
<div class="fba-alert usa-alert usa-alert--success" role="status" hidden>
<div class="usa-alert__body">
<h2 class="usa-alert__heading">
<%= content_tag alert_heading_level(render_context), class: "usa-alert__heading" do %>
<%= form.success_text_heading %>
</h2>
<% end %>
<div class="usa-alert__text">
<%= sanitize(form.success_text) %>
</div>
</div>
</div>
<div class="fba-alert-error usa-alert usa-alert--error" role="alert" hidden>
<div class="usa-alert__body">
<h2 class="usa-alert__heading">
<%= content_tag alert_heading_level(render_context), class: "usa-alert__heading" do %>
<%= t 'error' %>
</h2>
<% end %>
<p class="usa-alert__text">
alert message
</p>
Expand Down
35 changes: 18 additions & 17 deletions app/views/components/forms/_logo_and_title.html.erb
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
<header>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to making heading level configurable, I also moved the logo div outside of the heading tag, since div inside heading is not valid html.

<h1
class="word-break fba-modal-title"
id="<%= "fba-form-title-#{form.short_uuid}" %>">
<%- if form.logo.present? %>
<div class="margin-bottom-2 text-center">
<%- if form.header_logo_display_banner? %>
<%= image_tag(form.logo.tag.url,
alt: form.logo_alt_text_or_default,
class: "form-header-logo") %>
<% elsif form.header_logo_display_square? %>
<%= image_tag(form.logo.logo_square.url,
alt: form.logo_alt_text_or_default,
class: "form-header-logo-square") %>
<% end %>
</div>
<%# locals: (form:, render_context: nil) %>
<header class="fba-form-header">
<%- if form.logo.present? %>
<div class="text-center">
<%- if form.header_logo_display_banner? %>
<%= image_tag(form.logo.tag.url,
alt: form.logo_alt_text_or_default,
class: "form-header-logo") %>
<% elsif form.header_logo_display_square? %>
<%= image_tag(form.logo.logo_square.url,
alt: form.logo_alt_text_or_default,
class: "form-header-logo-square") %>
<% end %>
</div>
<% end %>
<%= content_tag title_heading_level(render_context),
class: "fba-modal-title",
id: "fba-form-title-#{form.short_uuid}" do %>
<%- if form.title.present? %>
<%= form.title %>
<% else %>
<span class="usa-sr-only">
Feedback form
</span>
<% end %>
</h1>
<% end %>
</header>
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<%# locals: (question:, render_context: nil) %>
<section
id="<%= question.ui_selector %>"
class="usa-site-alert usa-site-alert--info"
aria-label="Site alert">
<div class="usa-alert">
<div class="usa-alert__body">
<h3 class="usa-alert__heading">
<%= content_tag alert_heading_level(render_context), class: "usa-alert__heading" do %>
<%= question.text.html_safe %>
</h3>
<% end %>
<%- if question.help_text.present? %>
<p class="usa-alert__text">
<%= question.help_text.html_safe %>
Expand Down
6 changes: 4 additions & 2 deletions app/views/components/widget/_fba.js.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<%# locals: (form:, render_context: :embedded, suppress_ui: false) %>

// Form components are namespaced under 'fba' = 'Feedback Analytics'
// Updated: July 2024
'use strict';
Expand Down Expand Up @@ -882,14 +884,14 @@ var touchpointFormOptions<%= form.short_uuid %> = {
'suppressSubmitButton' : <%= form.suppress_submit_button %>,
'htmlFormBody' : function() {
<%- if (form.delivery_method == "inline" && !form.suppress_submit_button && form.element_selector?) || form.delivery_method == "modal" || form.delivery_method == "custom-button-modal" %>
return "<%= escape_javascript render(partial: 'components/widget/modal', locals: { form: form }) %>";
return "<%= escape_javascript render(partial: 'components/widget/modal', locals: { form: form, render_context: render_context }) %>";
<% else %>
return null;
<% end %>
},
'htmlFormBodyNoModal' : function() {
<%- if form.delivery_method == "inline" && form.suppress_submit_button && form.element_selector? %>
return "<%= escape_javascript render(partial: 'components/widget/no_modal', locals: { form: form }) %>";
return "<%= escape_javascript render(partial: 'components/widget/no_modal', locals: { form: form, render_context: render_context }) %>";
<% else %>
return null;
<% end %>
Expand Down
Loading