Merge pull request #4762 from betagouv/form-stylesheet
Usager : amélioration de la clarté et de l'accessibilité des formulaires
This commit is contained in:
commit
d5fcaf7073
13 changed files with 152 additions and 66 deletions
|
@ -3,6 +3,7 @@ $small-page-width: 840px;
|
|||
|
||||
$default-spacer: 8px;
|
||||
$default-padding: 2 * $default-spacer;
|
||||
$default-fields-spacer: 5 * $default-spacer;
|
||||
|
||||
// layouts
|
||||
$two-columns-padding: 60px;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
}
|
||||
|
||||
%outline {
|
||||
&:active,
|
||||
&:active:not(:disabled),
|
||||
&:focus {
|
||||
outline: 3px solid $blue;
|
||||
}
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
width: 100%;
|
||||
height: 0;
|
||||
margin-top: $default-padding;
|
||||
margin-bottom: 2 * $default-padding;
|
||||
margin-bottom: $default-fields-spacer;
|
||||
border: none;
|
||||
border-bottom: 1px solid $border-grey;
|
||||
border-bottom: 2px solid $border-grey;
|
||||
}
|
||||
|
||||
@mixin notice-text-style {
|
||||
font-size: 14px;
|
||||
font-size: 16px;
|
||||
color: $grey;
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
|||
}
|
||||
|
||||
label {
|
||||
font-size: 18px;
|
||||
margin-bottom: $default-padding;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
|
@ -45,7 +46,6 @@
|
|||
|
||||
.notice {
|
||||
@include notice-text-style;
|
||||
font-weight: bold;
|
||||
margin-top: - $default-spacer;
|
||||
margin-bottom: $default-padding;
|
||||
|
||||
|
@ -70,32 +70,80 @@
|
|||
visibility: visible;
|
||||
}
|
||||
|
||||
// Align checkboxes on the top-left side of the label
|
||||
// Move checkbox to the top-left side of the label
|
||||
&.editable-champ-checkbox,
|
||||
&.editable-champ-radio.vertical,
|
||||
&.editable-champ-engagement {
|
||||
p,
|
||||
label {
|
||||
padding-left: 28px;
|
||||
}
|
||||
|
||||
input[type=checkbox],
|
||||
input[type=radio] {
|
||||
input[type=checkbox] {
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
top: 3px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
// When an (eventual) notice is displayed after the input, give it some bottom margin.
|
||||
.notice {
|
||||
margin-bottom: $default-fields-spacer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.radios {
|
||||
display: flex;
|
||||
|
||||
// Horizontal layout (default)
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
|
||||
label {
|
||||
display: inline;
|
||||
margin-left: $default-padding;
|
||||
margin-right: $default-padding;
|
||||
}
|
||||
|
||||
// Vertical layout
|
||||
&.vertical {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
|
||||
label {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
padding: $default-padding $default-padding $default-padding $default-spacer;
|
||||
border: 1px solid $border-grey;
|
||||
border-radius: 4px;
|
||||
font-weight: normal;
|
||||
background: $white;
|
||||
user-select: none;
|
||||
|
||||
&:last-of-type {
|
||||
margin-bottom: $default-fields-spacer;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $light-grey;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:active {
|
||||
border-color: darken($border-grey, 10);
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
input[type=radio] {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.notice {
|
||||
margin: 4px 0 0 27px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +157,7 @@
|
|||
select,
|
||||
.attachment {
|
||||
display: block;
|
||||
margin-bottom: 2 * $default-padding;
|
||||
margin-bottom: $default-fields-spacer;
|
||||
|
||||
&.small-margin {
|
||||
margin-bottom: $default-padding / 2;
|
||||
|
@ -117,7 +165,7 @@
|
|||
}
|
||||
|
||||
.add-row {
|
||||
margin-bottom: 2 * $default-padding;
|
||||
margin-bottom: $default-fields-spacer;
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
|
@ -182,16 +230,14 @@
|
|||
input[type=radio] {
|
||||
@extend %outline;
|
||||
|
||||
margin-left: 5px;
|
||||
margin-right: 4px;
|
||||
margin-bottom: 2 * $default-padding;
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
// Firefox tends to display checkbox controls smaller than other browsers.
|
||||
// Firefox tends to display some controls smaller than other browsers.
|
||||
// Ensure a consistency of size between browsers.
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
margin-left: 5px;
|
||||
margin-right: 4px;
|
||||
margin-bottom: $default-fields-spacer;
|
||||
}
|
||||
|
||||
input[type=date] {
|
||||
|
@ -234,7 +280,7 @@
|
|||
|
||||
.select2-container {
|
||||
display: block;
|
||||
margin-bottom: 2 * $default-padding;
|
||||
margin-bottom: $default-fields-spacer;
|
||||
|
||||
&.select2-container--focus {
|
||||
.select2-selection {
|
||||
|
@ -304,10 +350,17 @@
|
|||
}
|
||||
|
||||
.header-section {
|
||||
display: inline-block;
|
||||
color: $blue;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
margin-bottom: 2 * $default-padding;
|
||||
font-size: 30px;
|
||||
margin-bottom: 3 * $default-padding;
|
||||
border-bottom: 3px solid $blue;
|
||||
}
|
||||
|
||||
.header-subsection {
|
||||
font-size: 22px;
|
||||
color: $blue;
|
||||
margin-bottom: $default-padding;
|
||||
}
|
||||
|
||||
.explication-libelle {
|
||||
|
@ -317,7 +370,7 @@
|
|||
}
|
||||
|
||||
.explication {
|
||||
margin-bottom: $default-padding;
|
||||
margin-bottom: $default-fields-spacer;
|
||||
padding: $default-padding / 2;
|
||||
background-color: $light-grey;
|
||||
|
||||
|
@ -326,6 +379,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
.siret-info {
|
||||
margin-top: -$default-fields-spacer;
|
||||
margin-bottom: $default-fields-spacer;
|
||||
// Ensure the bottom-margin is not collapsed when the element is empty
|
||||
min-height: 1px;
|
||||
}
|
||||
|
||||
.send-wrapper {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
@ -388,15 +448,4 @@
|
|||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.pj-input {
|
||||
input[type=file] {
|
||||
margin: $default-padding 0 (2 * $default-padding);
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.piece-description {
|
||||
margin-bottom: $default-padding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,4 +2,11 @@ class Champs::HeaderSectionChamp < Champ
|
|||
def search_terms
|
||||
# The user cannot enter any information here so it doesn’t make much sense to search
|
||||
end
|
||||
|
||||
def section_index
|
||||
dossier
|
||||
.champs
|
||||
.filter { |c| c.type_champ == TypeDeChamp.type_champs.fetch(:header_section) }
|
||||
.index(self) + 1
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,5 +7,6 @@
|
|||
= render partial: "shared/dossiers/editable_champs/editable_champ", locals: { champ: champ, form: form }
|
||||
= form.hidden_field :id
|
||||
= form.hidden_field :_destroy, disabled: true
|
||||
%button.button.danger.remove-row
|
||||
Supprimer
|
||||
.flex.row-reverse
|
||||
%button.button.danger.remove-row
|
||||
Supprimer l’élément
|
||||
|
|
|
@ -78,18 +78,17 @@
|
|||
|
||||
- if !@procedure.locked?
|
||||
%h2.header-section À qui s’adresse ma démarche ?
|
||||
.editable-champ.editable-champ-radio.vertical
|
||||
.radios.vertical
|
||||
= f.label :for_individual, value: true do
|
||||
= f.radio_button :for_individual, true
|
||||
Ma démarche s’adresse à un particulier
|
||||
%p.notice En choisissant cette option, l’usager devra renseigner son nom et prénom avant d’accéder au formulaire
|
||||
= f.radio_button :for_individual, true
|
||||
%p.notice En choisissant cette option, l’usager devra renseigner son nom et prénom avant d’accéder au formulaire
|
||||
|
||||
.editable-champ.editable-champ-radio.vertical
|
||||
= f.label :for_individual, value: false do
|
||||
= f.radio_button :for_individual, false
|
||||
Ma démarche s’adresse à une personne morale
|
||||
%p.notice
|
||||
En choisissant cette option, l’usager devra renseigner son n° SIRET.<br>Grâce à l’API Entreprise, les informations sur la personne morale (raison sociale, adresse du siège, etc.) seront automatiquement renseignées.
|
||||
= f.radio_button :for_individual, false
|
||||
%p.notice
|
||||
En choisissant cette option, l’usager devra renseigner son n° SIRET.<br>Grâce à l’API Entreprise, les informations sur la personne morale (raison sociale, adresse du siège, etc.) seront automatiquement renseignées.
|
||||
|
||||
%p.explication
|
||||
Si votre démarche s’adresse indifféremment à une personne morale ou un particulier, choisissez l'option « Particuliers ». Vous pourrez ajouter un champ SIRET directement dans le formulaire.
|
||||
|
|
|
@ -52,16 +52,16 @@
|
|||
%label Mot de passe
|
||||
%input{ type: "password", value: "12345678" }
|
||||
|
||||
%h2.header-section Bouton radio verticaux
|
||||
.editable-champ.editable-champ-radio.vertical
|
||||
= f.label :archived, 'Option A', value: true
|
||||
%p.notice Une option tout à fait valable.
|
||||
= f.radio_button :archived, true
|
||||
|
||||
.editable-champ.editable-champ-radio.vertical
|
||||
= f.label :archived, 'Option B', value: false
|
||||
%p.notice Une autre option, pas mal non plus.
|
||||
= f.radio_button :archived, false
|
||||
%h3.header-subsection Bouton radio verticaux
|
||||
.radios.vertical
|
||||
= f.label :archived, value: true do
|
||||
= f.radio_button :archived, true
|
||||
Option A
|
||||
%p.notice Une option tout à fait valable.
|
||||
= f.label :archived, value: false do
|
||||
= f.radio_button :archived, false
|
||||
Option B
|
||||
%p.notice Une autre option, pas mal non plus.
|
||||
|
||||
.send-wrapper
|
||||
= f.submit 'Enregistrer un brouillon (formnovalidate)', formnovalidate: true, class: 'button send'
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
.editable-champ{ class: "editable-champ-#{champ.type_champ}" }
|
||||
- if champ.repetition?
|
||||
= render partial: 'shared/dossiers/editable_champs/header_section', locals: { champ: champ }
|
||||
|
||||
%h3.header-subsection= champ.libelle
|
||||
- if champ.description.present?
|
||||
%p.notice= string_to_html(champ.description, false)
|
||||
|
||||
- elsif has_label?(champ)
|
||||
= render partial: 'shared/dossiers/editable_champs/champ_label', locals: { form: form, champ: champ, seen_at: defined?(seen_at) ? seen_at : nil }
|
||||
|
||||
|
|
|
@ -1,2 +1,6 @@
|
|||
- section_index = champ.section_index
|
||||
|
||||
%h2.header-section
|
||||
- if section_index
|
||||
= "#{section_index}."
|
||||
= champ.libelle
|
||||
|
|
|
@ -8,16 +8,16 @@
|
|||
.flex.row-reverse
|
||||
- if champ.persisted?
|
||||
%button.button.danger.remove-row{ type: :button }
|
||||
Supprimer
|
||||
Supprimer l’élément
|
||||
- else
|
||||
%button.button.danger{ type: :button }
|
||||
Supprimer
|
||||
Supprimer l’élément
|
||||
|
||||
- if champ.persisted?
|
||||
= link_to champs_repetition_path(form.index), class: 'button add-row', data: { remote: true, method: 'POST', params: { champ_id: champ&.id }.to_query } do
|
||||
%span.icon.add
|
||||
Ajouter une ligne pour « #{champ.libelle} »
|
||||
Ajouter un élément pour « #{champ.libelle} »
|
||||
- else
|
||||
%a.button.add-row
|
||||
%span.icon.add
|
||||
Ajouter une ligne pour « #{champ.libelle} »
|
||||
Ajouter un élément pour « #{champ.libelle} »
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
= form.text_field :value,
|
||||
placeholder: champ.libelle,
|
||||
class: 'small-margin',
|
||||
data: { remote: true, debounce: true, url: champs_siret_path(form.index), params: { champ_id: champ&.id }.to_query, spinner: true },
|
||||
required: champ.mandatory?,
|
||||
pattern: "[0-9]{14}",
|
||||
title: "Le numéro de SIRET doit comporter exactement 14 chiffres"
|
||||
.spinner.right.hidden
|
||||
%div{ class: "siret-info-#{form.index}" }
|
||||
.siret-info{ class: "siret-info-#{form.index}" }
|
||||
- if champ.etablissement.present?
|
||||
= render partial: 'shared/dossiers/editable_champs/etablissement_titre', locals: { etablissement: champ.etablissement }
|
||||
|
|
|
@ -107,7 +107,7 @@ feature 'The user' do
|
|||
fill_in('text', with: 'super texte')
|
||||
expect(page).to have_field('text', with: 'super texte')
|
||||
|
||||
click_on 'Ajouter une ligne pour'
|
||||
click_on 'Ajouter un élément pour'
|
||||
|
||||
within '.row-1' do
|
||||
fill_in('text', with: 'un autre texte')
|
||||
|
@ -120,7 +120,7 @@ feature 'The user' do
|
|||
expect(page).to have_content('Supprimer', count: 2)
|
||||
|
||||
within '.row-1' do
|
||||
click_on 'Supprimer'
|
||||
click_on 'Supprimer l’élément'
|
||||
end
|
||||
|
||||
click_on 'Enregistrer le brouillon'
|
||||
|
|
26
spec/models/champs/header_section_champ_spec.rb
Normal file
26
spec/models/champs/header_section_champ_spec.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Champs::CheckboxChamp do
|
||||
let(:types_de_champ) do
|
||||
[
|
||||
create(:type_de_champ_header_section),
|
||||
create(:type_de_champ_civilite),
|
||||
create(:type_de_champ_text),
|
||||
create(:type_de_champ_header_section),
|
||||
create(:type_de_champ_email)
|
||||
]
|
||||
end
|
||||
|
||||
let(:procedure) { create(:procedure, types_de_champ: types_de_champ) }
|
||||
let(:dossier) { create(:dossier, procedure: procedure) }
|
||||
|
||||
describe '#section_index' do
|
||||
let(:first_header) { dossier.champs[0] }
|
||||
let(:second_header) { dossier.champs[3] }
|
||||
|
||||
it 'returns the index of the section (starting from 1)' do
|
||||
expect(first_header.section_index).to eq 1
|
||||
expect(second_header.section_index).to eq 2
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue